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) { 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=\"{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); }
/// <summary> /// Installs this kernel into Jupyter's list of available kernels. /// </summary> /// <param name="develop"> /// If <c>true</c>, this kernel will be installed in develop mode, /// such that the kernel is rebuilt whenever a new instance is /// started. /// </param> /// <param name="logLevel"> /// The default logging level to be used when starting new kernel /// instances. /// </param> /// <param name="prefix"> /// A path to be provided to <c>jupyter kernelspec install</c> /// as the prefix into which the kernel should be installed. /// Typically, this parameter is used when installing into an environment. /// If <c>null</c>, no prefix is passed to Jupyter. /// </param> /// <param name="user"> /// If <c>true</c>, the kernel will be installed for the current /// user only. /// </param> /// <param name="additionalFiles"> /// Specifies additional files which should be included in the kernelspec /// directory. Files are specified as a dictionary from file names /// to functions yielding streams that read the contents of each /// file. /// </param> /// <param name="pathToTool"> /// If present, the value of this parameter will be used in the /// kernelspec as an explicit path to the kernel being invoked, /// as opposed to using the dotnet command-line program to find /// the appropriate kernel. /// This is not needed in most circumstances, but can be helpful /// when working with CI environments that do not add .NET Global /// Tools to the PATH environment variable. /// </param> /// <remarks> /// This method dynamically generates a new <c>kernelspec.json</c> /// file representing the kernel properties provided when the /// application was constructed, along with options such as the /// development mode. /// </remarks> public int InstallKernelSpec(bool develop, LogLevel logLevel, string prefix = null, bool user = false, IDictionary <string, Func <Stream> > additionalFiles = null, IEnumerable <string> additionalKernelArguments = null, string pathToTool = 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 'dotnet " + $"{properties.KernelName} install' without the '--develop' option." ); // Serialize a new kernel spec that points to this directory. kernelSpec = new KernelSpec { DisplayName = properties.KernelName, 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 { kernelArgs.AddRange(new[] { "dotnet", properties.KernelName }); } kernelArgs.AddRange( new[] { "kernel", "--log-level", logLevel.ToString(), "{connection_file}" } ); kernelSpec = new KernelSpec { DisplayName = properties.DisplayName, 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 filesToDelete = new List <string>(); var jsonPath = Path.Combine(tempKernelSpecDir, "kernel.json"); Directory.CreateDirectory(tempKernelSpecDir); File.WriteAllText(jsonPath, JsonConvert.SerializeObject(kernelSpec)); filesToDelete.Add(jsonPath); 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(); using (var destStream = File.OpenWrite(dest)) { sourceStream.CopyTo(destStream); } filesToDelete.Add(dest); } } // Find out if we need any extra arguments. var extraArgs = new List <string>(); if (!String.IsNullOrWhiteSpace(prefix)) { extraArgs.Add($"--prefix=\"{prefix}\""); } if (user) { extraArgs.Add("--user"); } var process = Process.Start(new ProcessStartInfo { FileName = "jupyter", Arguments = $"kernelspec install {kernelSpecDir} --name=\"{properties.KernelName}\" {String.Join(" ", extraArgs)}" }); process.WaitForExit(); foreach (var fileName in filesToDelete) { try { File.Delete(fileName); } catch {} } Directory.Delete(tempKernelSpecDir); return(process.ExitCode); }