in src/KernelApplication.cs [387:540]
public int InstallKernelSpec(bool develop,
LogLevel logLevel,
string? prefix = null, IEnumerable<string>? extraInstallArgs = null,
IDictionary<string, Func<Stream>>? additionalFiles = null,
IEnumerable<string>? additionalKernelArguments = null,
string? pathToTool = null,
string? kernelName = null)
{
var kernelSpecDir = "";
KernelSpec kernelSpec;
if (develop)
{
if (pathToTool != null)
{
throw new InvalidDataException("Cannot use development mode together with custom tool paths.");
}
System.Console.WriteLine(
$"NOTE: Installing a kernel spec which references this directory.\n" +
$" Any changes made in this directory will affect the operation of the {properties.FriendlyName} kernel.\n" +
$" If this was not what you intended, run 'install' without the '--develop' option."
);
// Serialize a new kernel spec that points to this directory.
kernelSpec = new KernelSpec
{
DisplayName = properties.FriendlyName,
LanguageName = properties.LanguageName,
Arguments = new List<string> {
"dotnet", "run",
"--project", Directory.GetCurrentDirectory(),
"--", "kernel",
"--log-level", logLevel.ToString(),
"{connection_file}"
}
};
}
else
{
var kernelArgs = new List<string>();
if (pathToTool != null)
{
kernelArgs.Add(pathToTool);
}
else
{
if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "dotnet")
{
kernelArgs.AddRange(new[] { "dotnet", properties.KernelName });
}
else
{
kernelArgs.Add(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
}
}
kernelArgs.AddRange(
new[]
{
"kernel",
"--log-level", logLevel.ToString(),
"{connection_file}"
}
);
kernelSpec = new KernelSpec
{
DisplayName = properties.FriendlyName,
LanguageName = properties.LanguageName,
Arguments = kernelArgs
};
}
// Add any additional arguments to the kernel spec as needed.
if (additionalKernelArguments != null)
{
kernelSpec.Arguments.AddRange(additionalKernelArguments);
}
// Make a temporary directory to hold the kernel spec.
var tempKernelSpecDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var jsonPath = Path.Combine(tempKernelSpecDir, "kernel.json");
Directory.CreateDirectory(tempKernelSpecDir);
File.WriteAllText(jsonPath, JsonConvert.SerializeObject(kernelSpec));
kernelSpecDir = tempKernelSpecDir;
// Add any additional files we may need.
if (additionalFiles != null)
{
foreach (var (fileName, streamAction) in additionalFiles)
{
var dest = Path.Combine(tempKernelSpecDir, fileName);
var sourceStream = streamAction();
// Create nested directory
Directory.CreateDirectory(Path.GetDirectoryName(dest));
using (var destStream = File.OpenWrite(dest))
{
sourceStream.CopyTo(destStream);
}
}
}
// Find out if we need any extra arguments.
var extraArgs = extraInstallArgs?.ToList() ?? new List<string>();
if (!String.IsNullOrWhiteSpace(prefix)) { extraArgs.Add($"--prefix=\"{prefix}\""); }
Process? process = null;
try
{
process = Process.Start(new ProcessStartInfo
{
FileName = "jupyter",
Arguments = $"kernelspec install \"{kernelSpecDir}\" --name=\"{kernelName ?? properties.KernelName}\" {String.Join(" ", extraArgs)}"
});
}
catch (Win32Exception ex)
{
System.Console.ForegroundColor = ConsoleColor.Red;
if (ex.NativeErrorCode == 2)
{
System.Console.Error.WriteLine(
"[ERROR] " +
$"Could not install {properties.KernelName} into your Jupyter configuration, " +
"as `jupyter` was not found on your PATH. " +
"Please make sure that Jupyter is installed and is on your PATH. " +
"If you are using conda or venv, please " +
"make sure that you have the correct environment activated.\n"
);
}
else
{
System.Console.Error.WriteLine(
"[ERROR] " +
$"An exception occurred while trying to call `jupyter` to install {properties.KernelName} " +
"into your Jupyter configuration.\n"
);
}
System.Console.ResetColor();
System.Console.Error.WriteLine(
"Full exception details:\n" + ex.ToString()
);
}
catch (Exception ex)
{
System.Console.WriteLine(ex);
return -2;
}
process?.WaitForExit();
// Recursively delete all files and subdirectories in temp directory.
Directory.Delete(tempKernelSpecDir, true);
return process?.ExitCode ?? -1;
}