From 17e9aa7e8daeb0205b649538d17633ba468fee77 Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 18 Jul 2019 17:56:38 -0700 Subject: [PATCH 01/47] add --- MLS.Agent/StringExtensions.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MLS.Agent/StringExtensions.cs b/MLS.Agent/StringExtensions.cs index 1b3064551..76681e0ef 100644 --- a/MLS.Agent/StringExtensions.cs +++ b/MLS.Agent/StringExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Globalization; using System.Web; using Microsoft.AspNetCore.Html; @@ -22,5 +23,10 @@ public static IHtmlContent ToHtmlContent(this string value) { return new HtmlString(value); } + + public static string TrimLineEndings(this string value) + { + return value.Trim('\r', '\n'); + } } } \ No newline at end of file From ea3a636e30e0a191b2cd0f1fe2441aa6c5a9b6e2 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 10:16:37 -0700 Subject: [PATCH 02/47] add logic to create the directory From 5cc75a50cac1bc57b2ab0d32076c0b62714b5330 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 10:26:41 -0700 Subject: [PATCH 03/47] copy the files From 1df0c75eae2060a2c69ac8d329c8a40356627c43 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 10:30:15 -0700 Subject: [PATCH 04/47] add some logging From 6a348e875dc7a50781f512da4c514f9308880c37 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 11:18:24 -0700 Subject: [PATCH 05/47] merge --- MLS.Agent/CommandLine/CommandLineParser.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index 27e84a1c8..fbaa7090e 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -392,6 +392,14 @@ Command Jupyter() return jupyter(options, console, startServer, context); }); + var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); + installCommand.Handler = CommandHandler.Create((console) => + { + return DotnetKernelJupyterInstaller.InstallKernel((string command, string args) => MLS.Agent.Tools.CommandLine.Execute(command, args), console); + }); + + jupyterCommand.AddCommand(installCommand); + return jupyterCommand; } From 7429fb6162d48661f1aec9b93337d0a222bc797a Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 12:01:38 -0700 Subject: [PATCH 06/47] clean up and add more assertions From e49a6a874e39c19472d3b718daa15f13a3d3c494 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 12:05:47 -0700 Subject: [PATCH 07/47] merge --- MLS.Agent/StringExtensions.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MLS.Agent/StringExtensions.cs b/MLS.Agent/StringExtensions.cs index 76681e0ef..c9bb9ee17 100644 --- a/MLS.Agent/StringExtensions.cs +++ b/MLS.Agent/StringExtensions.cs @@ -23,10 +23,5 @@ public static IHtmlContent ToHtmlContent(this string value) { return new HtmlString(value); } - - public static string TrimLineEndings(this string value) - { - return value.Trim('\r', '\n'); - } } } \ No newline at end of file From 94aba0866df4eba6498e4b38300f507a6da891e4 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 18:07:29 -0700 Subject: [PATCH 08/47] add interface --- MLS.Agent.Tests/lJupyterPathInfoTests.cs | 82 ++++++++++++++++++++++ MLS.Agent/CommandLine/CommandLineParser.cs | 1 + MLS.Agent/JupyterDataPathResult.cs | 27 +++++++ MLS.Agent/JupyterPathInfo.cs | 51 ++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 MLS.Agent.Tests/lJupyterPathInfoTests.cs create mode 100644 MLS.Agent/JupyterDataPathResult.cs create mode 100644 MLS.Agent/JupyterPathInfo.cs diff --git a/MLS.Agent.Tests/lJupyterPathInfoTests.cs b/MLS.Agent.Tests/lJupyterPathInfoTests.cs new file mode 100644 index 000000000..5f45013f6 --- /dev/null +++ b/MLS.Agent.Tests/lJupyterPathInfoTests.cs @@ -0,0 +1,82 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Xunit; +using System; +using FluentAssertions; +using MLS.Agent.Tools; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using MLS.Agent.Jupyter; + +namespace MLS.Agent.Tests +{ + public class JupyterPathInfoTests + { + [Fact] + public void If_data_paths_are_present_GetDataPaths_returns_the_paths() + { + const string expectedPath = @"C:\myDataPath"; + + var pathsOutput = +$@"config: + C:\Users\.jupyter +data: + {expectedPath} +runtime: + C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); + var commandLineResult = new CommandLineResult(0, pathsOutput); + var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); + dataPathsResult.Paths.Should().HaveCount(1); + + dataPathsResult.Paths.First().FullName.Should().Be(expectedPath); + dataPathsResult.Error.Should().BeEmpty(); + } + + [Fact] + public void If_data_paths_are_not_present_GetDataPaths_returns_the_error() + { + var pathsOutput = +$@"config: + C:\Users\.jupyter +runtime: + C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); + var commandLineResult = new CommandLineResult(0, pathsOutput); + var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); + dataPathsResult.Error.Should().NotBeNull(); + } + + + [Fact] + public void If_the_command_line_result_has_error_GetDataPaths_returns_error() + { + var error = "some error"; + var commandLineResult = new CommandLineResult(1, null, new List(){ error }); + var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); + dataPathsResult.Paths.Should().BeEmpty(); + dataPathsResult.Error.Should().Contain(error); + } + + [Fact] + public void GetDataPaths_returns_the_data_paths_when_datapaths_appear_the_last_in_the_output() + { + const string expectedPath1 = @"C:\myDataPath1"; + const string expectedPath2 = @"C:\myDataPath2"; + + var pathsOutput = + $@"config: + C:\Users\.jupyter +runtime: + C:\Users\AppData\Roaming\jupyter\runtime +data: + {expectedPath1} + {expectedPath2}".Split("\n"); + var commandLineResult = new CommandLineResult(0, pathsOutput); + var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); + + dataPathsResult.Paths.Should().Contain(dir => dir.FullName == expectedPath1); + dataPathsResult.Paths.Should().Contain(dir => dir.FullName == expectedPath2); + } + } +} \ No newline at end of file diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index fbaa7090e..a1417c538 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -14,6 +14,7 @@ using Microsoft.DotNet.Interactive.Jupyter; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using MLS.Agent.Jupyter; using MLS.Agent.Markdown; using MLS.Repositories; using WorkspaceServer; diff --git a/MLS.Agent/JupyterDataPathResult.cs b/MLS.Agent/JupyterDataPathResult.cs new file mode 100644 index 000000000..09a23af57 --- /dev/null +++ b/MLS.Agent/JupyterDataPathResult.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MLS.Agent.Jupyter +{ + public class JupyterDataPathResult + { + public JupyterDataPathResult(IEnumerable paths) + { + Paths = paths; + Error = ""; + } + + public JupyterDataPathResult(string error) + { + Paths = Enumerable.Empty(); + Error = error; + } + + public IEnumerable Paths { get; } + public string Error { get; } + } +} \ No newline at end of file diff --git a/MLS.Agent/JupyterPathInfo.cs b/MLS.Agent/JupyterPathInfo.cs new file mode 100644 index 000000000..db168bd4e --- /dev/null +++ b/MLS.Agent/JupyterPathInfo.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using MLS.Agent.Tools; + +namespace MLS.Agent.Jupyter +{ + public class JupyterPathInfo + { + public static JupyterDataPathResult GetDataPaths(CommandLineResult jupyterPathResult) + { + if (jupyterPathResult.ExitCode == 0) + { + if (TryGetDataPaths(jupyterPathResult.Output.ToArray(), out var dataPaths)) + { + return new JupyterDataPathResult(dataPaths); + } + else + { + return new JupyterDataPathResult($"Could not find the jupyter kernel installation directory." + + $" Output of \"jupyter --paths\" is {string.Join('\n', jupyterPathResult.Output.ToArray())}"); + } + } + else + { + return new JupyterDataPathResult($"Tried to invoke \"jupyter --paths\" but failed with exception: {string.Join("\n", jupyterPathResult.Error)}"); + } + } + + private static bool TryGetDataPaths(string[] pathInfo, out IEnumerable dataPaths) + { + var dataHeaderIndex = Array.FindIndex(pathInfo, element => element.Trim().CompareTo("data:") == 0); + if (dataHeaderIndex != -1) + { + var nextHeaderIndex = Array.FindIndex(pathInfo, dataHeaderIndex + 1, element => element.Trim().EndsWith(":")); + if (nextHeaderIndex == -1) + nextHeaderIndex = pathInfo.Count(); + + dataPaths = pathInfo.Skip(dataHeaderIndex + 1).Take(nextHeaderIndex - dataHeaderIndex - 1).Select(dir => new DirectoryInfo(dir.Trim())); + return true; + } + + dataPaths = Enumerable.Empty(); + return false; + } + } +} \ No newline at end of file From 570ba8549cda7c1f78afdc94184c11c545518e4b Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 18:08:47 -0700 Subject: [PATCH 09/47] rename --- .../{lJupyterPathInfoTests.cs => JupyterPathInfoTests.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename MLS.Agent.Tests/{lJupyterPathInfoTests.cs => JupyterPathInfoTests.cs} (100%) diff --git a/MLS.Agent.Tests/lJupyterPathInfoTests.cs b/MLS.Agent.Tests/JupyterPathInfoTests.cs similarity index 100% rename from MLS.Agent.Tests/lJupyterPathInfoTests.cs rename to MLS.Agent.Tests/JupyterPathInfoTests.cs From e08b06b23cbec45f47ed0e289cf1f32ce5701eb3 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 19 Jul 2019 18:17:34 -0700 Subject: [PATCH 10/47] add test --- MLS.Agent.Tests/DotnetKernelInstallerTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 MLS.Agent.Tests/DotnetKernelInstallerTests.cs diff --git a/MLS.Agent.Tests/DotnetKernelInstallerTests.cs b/MLS.Agent.Tests/DotnetKernelInstallerTests.cs new file mode 100644 index 000000000..55c27e7c2 --- /dev/null +++ b/MLS.Agent.Tests/DotnetKernelInstallerTests.cs @@ -0,0 +1,22 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; +using MLS.Agent.Jupyter; +using MLS.Agent.Tools; +using System.CommandLine; +using System.Threading.Tasks; +using Xunit; +namespace MLS.Agent.Tests +{ + public class DotnetKernelInstallerTests + { + [Fact] + public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() + { + var console = new TestConsole(); + await DotnetKernelJupyterInstaller.InstallKernel((command, args) => Task.FromResult(new CommandLineResult(1)), console); + console.Error.ToString().Should().Contain(".NET Kernel Installation failed"); + } + } +} \ No newline at end of file From 4a8ee40b0c61c061f9a6f6f75e9dc4502713778f Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 26 Jul 2019 11:53:33 -0700 Subject: [PATCH 11/47] add command line --- MLS.Agent.Tests/DotnetKernelInstallerTests.cs | 35 +++++++++++++++++-- MLS.Agent/CommandLine/CommandLineParser.cs | 4 +-- .../JupyterCommandLine.cs | 24 +++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs diff --git a/MLS.Agent.Tests/DotnetKernelInstallerTests.cs b/MLS.Agent.Tests/DotnetKernelInstallerTests.cs index 55c27e7c2..5529ef23a 100644 --- a/MLS.Agent.Tests/DotnetKernelInstallerTests.cs +++ b/MLS.Agent.Tests/DotnetKernelInstallerTests.cs @@ -6,17 +6,48 @@ using MLS.Agent.Tools; using System.CommandLine; using System.Threading.Tasks; +using WorkspaceServer.Tests; using Xunit; namespace MLS.Agent.Tests { public class DotnetKernelInstallerTests { [Fact] - public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() + public void Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); - await DotnetKernelJupyterInstaller.InstallKernel((command, args) => Task.FromResult(new CommandLineResult(1)), console); + DotnetKernelJupyterInstaller.InstallKernel(new CommandLineResult(1), console); console.Error.ToString().Should().Contain(".NET Kernel Installation failed"); } + + [Fact] + public void Prints_to_console_when_kernel_installation_succeded() + { + var directory = Create.EmptyWorkspace().Directory; + directory.CreateSubdirectory("kernels"); + var console = new TestConsole(); + var dataPaths = +$@"config: + C:\Users\.jupyter +data: + {directory.FullName} +runtime: + C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); + DotnetKernelJupyterInstaller.InstallKernel(new CommandLineResult(0, dataPaths), console); + console.Out.ToString().Should().Contain(".NET kernel installation succeded"); + } + + [Fact] + public void Adds_the_kernels_json_file__and_logos_in_data_directory() + { + var directory = Create.EmptyWorkspace().Directory; + directory.CreateSubdirectory("kernels"); + var console = new TestConsole(); + var dataPaths = +$@"data: + {directory.FullName}".Split("\n"); + DotnetKernelJupyterInstaller.InstallKernel(new CommandLineResult(0, dataPaths), console); + directory.GetFiles().Should().BeEquivalentTo("kernels.json", "logo-32x32.png", "logo-64x64.png"); + } } } \ No newline at end of file diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index a1417c538..cbd8912c6 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -394,9 +394,9 @@ Command Jupyter() }); var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); - installCommand.Handler = CommandHandler.Create((console) => + installCommand.Handler = CommandHandler.Create(async (console) => { - return DotnetKernelJupyterInstaller.InstallKernel((string command, string args) => MLS.Agent.Tools.CommandLine.Execute(command, args), console); + return await new JupyterCommandLine(console).InvokeAsync(); }); jupyterCommand.AddCommand(installCommand); diff --git a/Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs b/Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs new file mode 100644 index 000000000..18154ea93 --- /dev/null +++ b/Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.CommandLine; +using System.Threading.Tasks; + +namespace Microsoft.DotNet.Try.Jupyter +{ + internal class JupyterCommandLine + { + private IConsole console; + + public JupyterCommandLine(IConsole console) + { + this.console = console; + } + + internal Task InvokeAsync() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file From 09010a073c2d72a4928c83152845825e6d479bce Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 26 Jul 2019 15:40:14 -0700 Subject: [PATCH 12/47] refactoring to the jupyter command line --- MLS.Agent.Tests/DotnetKernelInstallerTests.cs | 53 -------------- MLS.Agent.Tools/CommandLine.cs | 9 ++- MLS.Agent/CommandLine/CommandLineParser.cs | 1 - .../JupyterCommandLineTests.cs | 59 +++++++++++++++ .../JupyterPathInfoTests.cs | 5 +- ...ft.DotNet.Interactive.Jupyter.Tests.csproj | 1 + .../JupyterCommandLine.cs | 72 +++++++++++++++++++ .../JupyterDataPathResult.cs | 2 +- .../JupyterPathInfo.cs | 4 +- 9 files changed, 142 insertions(+), 64 deletions(-) delete mode 100644 MLS.Agent.Tests/DotnetKernelInstallerTests.cs create mode 100644 Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs rename {MLS.Agent.Tests => Microsoft.DotNet.Interactive.Jupyter.Tests}/JupyterPathInfoTests.cs (96%) create mode 100644 Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs rename {MLS.Agent => Microsoft.DotNet.Interactive.Jupyter}/JupyterDataPathResult.cs (93%) rename {MLS.Agent => Microsoft.DotNet.Interactive.Jupyter}/JupyterPathInfo.cs (94%) diff --git a/MLS.Agent.Tests/DotnetKernelInstallerTests.cs b/MLS.Agent.Tests/DotnetKernelInstallerTests.cs deleted file mode 100644 index 5529ef23a..000000000 --- a/MLS.Agent.Tests/DotnetKernelInstallerTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using FluentAssertions; -using MLS.Agent.Jupyter; -using MLS.Agent.Tools; -using System.CommandLine; -using System.Threading.Tasks; -using WorkspaceServer.Tests; -using Xunit; -namespace MLS.Agent.Tests -{ - public class DotnetKernelInstallerTests - { - [Fact] - public void Returns_error_when_jupyter_paths_could_not_be_obtained() - { - var console = new TestConsole(); - DotnetKernelJupyterInstaller.InstallKernel(new CommandLineResult(1), console); - console.Error.ToString().Should().Contain(".NET Kernel Installation failed"); - } - - [Fact] - public void Prints_to_console_when_kernel_installation_succeded() - { - var directory = Create.EmptyWorkspace().Directory; - directory.CreateSubdirectory("kernels"); - var console = new TestConsole(); - var dataPaths = -$@"config: - C:\Users\.jupyter -data: - {directory.FullName} -runtime: - C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); - DotnetKernelJupyterInstaller.InstallKernel(new CommandLineResult(0, dataPaths), console); - console.Out.ToString().Should().Contain(".NET kernel installation succeded"); - } - - [Fact] - public void Adds_the_kernels_json_file__and_logos_in_data_directory() - { - var directory = Create.EmptyWorkspace().Directory; - directory.CreateSubdirectory("kernels"); - var console = new TestConsole(); - var dataPaths = -$@"data: - {directory.FullName}".Split("\n"); - DotnetKernelJupyterInstaller.InstallKernel(new CommandLineResult(0, dataPaths), console); - directory.GetFiles().Should().BeEquivalentTo("kernels.json", "logo-32x32.png", "logo-64x64.png"); - } - } -} \ No newline at end of file diff --git a/MLS.Agent.Tools/CommandLine.cs b/MLS.Agent.Tools/CommandLine.cs index 7a925eba3..623d54d58 100644 --- a/MLS.Agent.Tools/CommandLine.cs +++ b/MLS.Agent.Tools/CommandLine.cs @@ -20,7 +20,8 @@ public static Task Execute( FileInfo exePath, string args, DirectoryInfo workingDir = null, - Budget budget = null) => + Budget budget = null, + (string key, string value)[] environmentVariables = null) => Execute(exePath.FullName, args, workingDir, @@ -30,7 +31,8 @@ public static async Task Execute( string command, string args, DirectoryInfo workingDir = null, - Budget budget = null) + Budget budget = null, + (string key, string value)[] environmentVariables =null) { args = args ?? ""; budget = budget ?? new Budget(); @@ -50,7 +52,8 @@ public static async Task Execute( error: data => { stdErr.AppendLine(data); - })) + }, + environmentVariables)) { var exitCode = await process.Complete(budget); diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index cbd8912c6..5bbc7d94d 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -14,7 +14,6 @@ using Microsoft.DotNet.Interactive.Jupyter; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using MLS.Agent.Jupyter; using MLS.Agent.Markdown; using MLS.Repositories; using WorkspaceServer; diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs new file mode 100644 index 000000000..f992e3e20 --- /dev/null +++ b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs @@ -0,0 +1,59 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; +using MLS.Agent.Tools; +using System; +using System.CommandLine; +using System.Threading.Tasks; +using WorkspaceServer.Tests; +using Xunit; + +namespace Microsoft.DotNet.Interactive.Jupyter.Tests +{ + public abstract class JupyterCommandLineTests + { + public abstract JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables); + [Fact] + public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() + { + var console = new TestConsole(); + await GetJupyterCommandLine(console).InvokeAsync(); + console.Error.ToString().Should().Contain(".NET kernel installation failed"); + } + + [Fact] + public async Task Prints_to_console_when_kernel_installation_succeded() + { + Environment.SetEnvironmentVariable("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3"); + var console = new TestConsole(); + await GetJupyterCommandLine(console, ("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3")).InvokeAsync(); + console.Out.ToString().Should().Contain(".NET kernel installation succeded"); + } + + [Fact] + public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() + { + var console = new TestConsole(); + await GetJupyterCommandLine(console).InvokeAsync(); + throw new NotImplementedException(); + //GetFiles().Should().BeEquivalentTo("kernels.json", "logo-32x32.png", "logo-64x64.png"); + } + } + + public class JupyterCommandLineIntegrationTests : JupyterCommandLineTests + { + public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) + { + return new JupyterCommandLine(console, environmentVariables); + } + } + + public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests + { + public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterPathInfoTests.cs b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterPathInfoTests.cs similarity index 96% rename from MLS.Agent.Tests/JupyterPathInfoTests.cs rename to Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterPathInfoTests.cs index 5f45013f6..44839e347 100644 --- a/MLS.Agent.Tests/JupyterPathInfoTests.cs +++ b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterPathInfoTests.cs @@ -2,15 +2,12 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Xunit; -using System; using FluentAssertions; using MLS.Agent.Tools; -using System.Threading.Tasks; using System.Collections.Generic; using System.Linq; -using MLS.Agent.Jupyter; -namespace MLS.Agent.Tests +namespace Microsoft.DotNet.Interactive.Jupyter.Tests { public class JupyterPathInfoTests { diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj b/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj index 28875454a..d6cc90e35 100644 --- a/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj +++ b/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj @@ -35,6 +35,7 @@ + diff --git a/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs b/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs new file mode 100644 index 000000000..4cfd6fe1c --- /dev/null +++ b/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs @@ -0,0 +1,72 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using MLS.Agent.Tools; +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.DotNet.Interactive.Jupyter +{ + public class JupyterCommandLine + { + private IConsole _console; + private readonly (string key, string value)[] _environmentVariables; + + public JupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) + { + _console = console; + _environmentVariables = environmentVariables; + } + + public async Task InvokeAsync() + { + var jupyterPathsResult = await CommandLine.Execute("python.exe", "-m jupyter --paths", environmentVariables: _environmentVariables); + var dataPathsResult = JupyterPathInfo.GetDataPaths(jupyterPathsResult); + if (string.IsNullOrEmpty(dataPathsResult.Error)) + { + Installkernel(dataPathsResult.Paths, _console); + _console.Out.WriteLine(".NET kernel installation succeded"); + return 0; + } + else + { + _console.Error.WriteLine($".NET kernel installation failed with error: {dataPathsResult.Error}"); + return -1; + } + } + + private void Installkernel(IEnumerable dataDirectories, IConsole console) + { + foreach (var directory in dataDirectories) + { + if (directory.Exists) + { + var kernelDirectory = directory.Subdirectory("kernels"); + if (kernelDirectory.Exists) + { + var dotnetkernelDir = kernelDirectory.Subdirectory(".NET"); + if (!dotnetkernelDir.Exists) + { + dotnetkernelDir.Create(); + } + + console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.FullName}"); + + //to do: find out what this path is + var jupyterInstallContent = new DirectoryInfo(@"C:\Users\akagarw\try.dot.net\github-try\try\Microsoft.DotNet.Interactive.Jupyter\ContentFiles"); + + // Copy the files into the kernels directory + File.Copy(jupyterInstallContent.GetFileSystemInfos("kernel.json").First().FullName, Path.Combine(dotnetkernelDir.FullName, "kernel.json"), overwrite: true); + File.Copy(jupyterInstallContent.GetFileSystemInfos("logo-32x32.png").First().FullName, Path.Combine(dotnetkernelDir.FullName, "logo-32x32.png"), overwrite: true); + File.Copy(jupyterInstallContent.GetFileSystemInfos("logo-64x64.png").First().FullName, Path.Combine(dotnetkernelDir.FullName, "logo-64x64.png"), overwrite: true); + console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.FullName}"); + } + } + } + } + } +} \ No newline at end of file diff --git a/MLS.Agent/JupyterDataPathResult.cs b/Microsoft.DotNet.Interactive.Jupyter/JupyterDataPathResult.cs similarity index 93% rename from MLS.Agent/JupyterDataPathResult.cs rename to Microsoft.DotNet.Interactive.Jupyter/JupyterDataPathResult.cs index 09a23af57..e0b8d976a 100644 --- a/MLS.Agent/JupyterDataPathResult.cs +++ b/Microsoft.DotNet.Interactive.Jupyter/JupyterDataPathResult.cs @@ -5,7 +5,7 @@ using System.IO; using System.Linq; -namespace MLS.Agent.Jupyter +namespace Microsoft.DotNet.Interactive.Jupyter { public class JupyterDataPathResult { diff --git a/MLS.Agent/JupyterPathInfo.cs b/Microsoft.DotNet.Interactive.Jupyter/JupyterPathInfo.cs similarity index 94% rename from MLS.Agent/JupyterPathInfo.cs rename to Microsoft.DotNet.Interactive.Jupyter/JupyterPathInfo.cs index db168bd4e..5603a7244 100644 --- a/MLS.Agent/JupyterPathInfo.cs +++ b/Microsoft.DotNet.Interactive.Jupyter/JupyterPathInfo.cs @@ -7,7 +7,7 @@ using System.Linq; using MLS.Agent.Tools; -namespace MLS.Agent.Jupyter +namespace Microsoft.DotNet.Interactive.Jupyter { public class JupyterPathInfo { @@ -22,7 +22,7 @@ public static JupyterDataPathResult GetDataPaths(CommandLineResult jupyterPathRe else { return new JupyterDataPathResult($"Could not find the jupyter kernel installation directory." + - $" Output of \"jupyter --paths\" is {string.Join('\n', jupyterPathResult.Output.ToArray())}"); + $" Output of \"jupyter --paths\" is {string.Join("\n", jupyterPathResult.Output.ToArray())}"); } } else From 645f6a5ab739b17a76177233071c0dcc49c9af47 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 26 Jul 2019 15:57:56 -0700 Subject: [PATCH 13/47] use the directory accessor and test --- .../JupyterCommandLineTests.cs | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs index f992e3e20..a7a29db81 100644 --- a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs +++ b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs @@ -2,10 +2,14 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using FluentAssertions; +using Microsoft.DotNet.Try.Markdown; using MLS.Agent.Tools; using System; using System.CommandLine; +using System.IO; +using System.Linq; using System.Threading.Tasks; +using WorkspaceServer; using WorkspaceServer.Tests; using Xunit; @@ -14,6 +18,8 @@ namespace Microsoft.DotNet.Interactive.Jupyter.Tests public abstract class JupyterCommandLineTests { public abstract JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables); + + public abstract IDirectoryAccessor GetExpectedKernelsDirectory(); [Fact] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { @@ -25,24 +31,33 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() [Fact] public async Task Prints_to_console_when_kernel_installation_succeded() { + //to do: using environment variable this way will cause test flakiness Environment.SetEnvironmentVariable("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3"); var console = new TestConsole(); await GetJupyterCommandLine(console, ("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3")).InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } - [Fact] + [Fact] public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() { + Environment.SetEnvironmentVariable("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3"); var console = new TestConsole(); - await GetJupyterCommandLine(console).InvokeAsync(); - throw new NotImplementedException(); - //GetFiles().Should().BeEquivalentTo("kernels.json", "logo-32x32.png", "logo-64x64.png"); + await GetJupyterCommandLine(console, ("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3")).InvokeAsync(); + + var dotnetDirectoryAccessor = GetExpectedKernelsDirectory().GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath(".NET")); + dotnetDirectoryAccessor.DirectoryExists(new RelativeDirectoryPath(".")).Should().BeTrue(); + dotnetDirectoryAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); } } public class JupyterCommandLineIntegrationTests : JupyterCommandLineTests { + public override IDirectoryAccessor GetExpectedKernelsDirectory() + { + return new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\AppData\Local\Continuum\anaconda3\share\jupyter\kernels")); + } + public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) { return new JupyterCommandLine(console, environmentVariables); @@ -51,6 +66,11 @@ public override JupyterCommandLine GetJupyterCommandLine(IConsole console, param public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests { + public override IDirectoryAccessor GetExpectedKernelsDirectory() + { + throw new NotImplementedException(); + } + public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) { throw new NotImplementedException(); From 813addbd98079f4966303235a2bb2a03c3a662ea Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 26 Jul 2019 16:54:53 -0700 Subject: [PATCH 14/47] add the file.copy thing --- .../JupyterCommandLineTests.cs | 3 +- .../JupyterCommandLine.cs | 45 ++++++++++--------- WorkspaceServer/DirectoryAccessor.cs | 6 +++ .../FileSystemDirectoryAccessor.cs | 9 ++++ WorkspaceServer/IDirectoryAccessor.cs | 2 + 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs index a7a29db81..e4a254b92 100644 --- a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs +++ b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs @@ -46,7 +46,7 @@ public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() await GetJupyterCommandLine(console, ("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3")).InvokeAsync(); var dotnetDirectoryAccessor = GetExpectedKernelsDirectory().GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath(".NET")); - dotnetDirectoryAccessor.DirectoryExists(new RelativeDirectoryPath(".")).Should().BeTrue(); + dotnetDirectoryAccessor.DirectoryExists(".").Should().BeTrue(); dotnetDirectoryAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); } } @@ -60,6 +60,7 @@ public override IDirectoryAccessor GetExpectedKernelsDirectory() public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) { + return new JupyterCommandLine(console, environmentVariables); } } diff --git a/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs b/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs index 4cfd6fe1c..f808b892a 100644 --- a/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs +++ b/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs @@ -8,17 +8,20 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using WorkspaceServer; namespace Microsoft.DotNet.Interactive.Jupyter { public class JupyterCommandLine { private IConsole _console; + private readonly IDirectoryAccessor _kernelContentDirAccessor; private readonly (string key, string value)[] _environmentVariables; public JupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) { _console = console; + _kernelContentDirAccessor = new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\try.dot.net\github-try\try\Microsoft.DotNet.Interactive.Jupyter\ContentFiles")); ; _environmentVariables = environmentVariables; } @@ -28,7 +31,9 @@ public async Task InvokeAsync() var dataPathsResult = JupyterPathInfo.GetDataPaths(jupyterPathsResult); if (string.IsNullOrEmpty(dataPathsResult.Error)) { - Installkernel(dataPathsResult.Paths, _console); + //to do: find out what this path is + + Installkernel(dataPathsResult.Paths.Select(path => new FileSystemDirectoryAccessor(path)), _console); _console.Out.WriteLine(".NET kernel installation succeded"); return 0; } @@ -39,34 +44,30 @@ public async Task InvokeAsync() } } - private void Installkernel(IEnumerable dataDirectories, IConsole console) + private void Installkernel(IEnumerable directoryAccessors, IConsole console) { - foreach (var directory in dataDirectories) + foreach (var directoryAccessor in directoryAccessors) { - if (directory.Exists) + var kernelsDirAccessor = directoryAccessor.GetDirectoryAccessorForRelativePath("kernels"); + if (kernelsDirAccessor.RootDirectoryExists()) { - var kernelDirectory = directory.Subdirectory("kernels"); - if (kernelDirectory.Exists) - { - var dotnetkernelDir = kernelDirectory.Subdirectory(".NET"); - if (!dotnetkernelDir.Exists) - { - dotnetkernelDir.Create(); - } - - console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.FullName}"); + var dotnetkernelDir = kernelsDirAccessor.GetDirectoryAccessorForRelativePath(".NET"); + dotnetkernelDir.EnsureRootDirectoryExists(); - //to do: find out what this path is - var jupyterInstallContent = new DirectoryInfo(@"C:\Users\akagarw\try.dot.net\github-try\try\Microsoft.DotNet.Interactive.Jupyter\ContentFiles"); + console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); - // Copy the files into the kernels directory - File.Copy(jupyterInstallContent.GetFileSystemInfos("kernel.json").First().FullName, Path.Combine(dotnetkernelDir.FullName, "kernel.json"), overwrite: true); - File.Copy(jupyterInstallContent.GetFileSystemInfos("logo-32x32.png").First().FullName, Path.Combine(dotnetkernelDir.FullName, "logo-32x32.png"), overwrite: true); - File.Copy(jupyterInstallContent.GetFileSystemInfos("logo-64x64.png").First().FullName, Path.Combine(dotnetkernelDir.FullName, "logo-64x64.png"), overwrite: true); - console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.FullName}"); - } + // Copy the files into the kernels directory + File.Copy(GetFileWithName(_kernelContentDirAccessor, "kernel.json").FullName, dotnetkernelDir.GetFullyQualifiedFilePath("kernel.json").FullName, overwrite: true); + File.Copy(GetFileWithName(_kernelContentDirAccessor, "logo-32x32.png").FullName, dotnetkernelDir.GetFullyQualifiedFilePath("logo-32x32.png").FullName, overwrite: true); + File.Copy(GetFileWithName(_kernelContentDirAccessor, "logo-64x64.png").FullName, dotnetkernelDir.GetFullyQualifiedFilePath("logo-64x64.png").FullName, overwrite: true); + console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); } } } + + private FileInfo GetFileWithName(IDirectoryAccessor directoryAccessor, string filename) + { + return new FileInfo(directoryAccessor.GetFullyQualifiedFilePath(filename).FullName); + } } } \ No newline at end of file diff --git a/WorkspaceServer/DirectoryAccessor.cs b/WorkspaceServer/DirectoryAccessor.cs index e93241900..b30a97599 100644 --- a/WorkspaceServer/DirectoryAccessor.cs +++ b/WorkspaceServer/DirectoryAccessor.cs @@ -58,5 +58,11 @@ public static FileInfo GetFullyQualifiedFilePath(this IDirectoryAccessor directo public static FileInfo GetFullyQualifiedFilePath(this IDirectoryAccessor directoryAccessor, RelativeFilePath relativePath) => (FileInfo) directoryAccessor.GetFullyQualifiedPath(relativePath); + + public static bool RootDirectoryExists(this IDirectoryAccessor directoryAccessor) => + directoryAccessor.DirectoryExists("."); + + public static void EnsureRootDirectoryExists(this IDirectoryAccessor directoryAccessor) => + directoryAccessor.EnsureDirectoryExists("."); } } \ No newline at end of file diff --git a/WorkspaceServer/FileSystemDirectoryAccessor.cs b/WorkspaceServer/FileSystemDirectoryAccessor.cs index db8ce597b..13a9ba3c5 100644 --- a/WorkspaceServer/FileSystemDirectoryAccessor.cs +++ b/WorkspaceServer/FileSystemDirectoryAccessor.cs @@ -103,5 +103,14 @@ public IEnumerable GetAllFiles() } public override string ToString() => _rootDirectory.FullName; + + public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename) + { + var file= directoryAccessor.GetAllFiles().FirstOrDefault(file => file.FileName == filename); + if(file!=null) + { + File.Copy(directoryAccessor.GetFullyQualifiedFilePath(file.FileName).FullName, GetFullyQualifiedPath( new RelativeFilePath(filename)).FullName); + } + } } } diff --git a/WorkspaceServer/IDirectoryAccessor.cs b/WorkspaceServer/IDirectoryAccessor.cs index f0bfe7ef4..7171be190 100644 --- a/WorkspaceServer/IDirectoryAccessor.cs +++ b/WorkspaceServer/IDirectoryAccessor.cs @@ -28,5 +28,7 @@ public interface IDirectoryAccessor FileSystemInfo GetFullyQualifiedPath(RelativePath path); IDirectoryAccessor GetDirectoryAccessorForRelativePath(RelativeDirectoryPath path); + + void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename); } } \ No newline at end of file From b084bccb6d5fb0f184f66407f445fa52d1299a23 Mon Sep 17 00:00:00 2001 From: Akshita Date: Mon, 29 Jul 2019 16:22:54 -0700 Subject: [PATCH 15/47] add methods to directory accessor --- MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs | 13 +++++++++++++ MLS.Agent/MLS.Agent.csproj | 3 +++ MLS.Agent/Markdown/MarkdownProject.cs | 4 ++++ .../JupyterCommandLineTests.cs | 10 +++++++--- .../JupyterCommandLine.cs | 10 +++++----- WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs | 10 ++++++++++ WorkspaceServer/FileSystemDirectoryAccessor.cs | 4 ++-- WorkspaceServer/IDirectoryAccessor.cs | 2 +- 8 files changed, 45 insertions(+), 11 deletions(-) diff --git a/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs b/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs index 128ff70e4..49d0ac624 100644 --- a/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs +++ b/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using FluentAssertions; using Microsoft.DotNet.PlatformAbstractions; @@ -258,6 +259,18 @@ public void It_can_make_a_directory_accessor_from_an_absolute_DirectoryInfo() subdirectory.FileExists("Tutorial.md").Should().BeTrue(); } + + + [Fact] + public void It_can_copy_files() + { + var targetDirectory = CreateDirectory(); + var sourceDirectory = GetDirectory(TestAssets.SampleConsole); + + targetDirectory.CopyFileFromDirectory(sourceDirectory, "Program.cs", true); + targetDirectory.FileExists("Program.cs").Should().BeTrue(); + targetDirectory.ReadAllText("Program.cs").Should().Contain("using System"); + } } public class FileSystemDirectoryAccessorTests : DirectoryAccessorTests diff --git a/MLS.Agent/MLS.Agent.csproj b/MLS.Agent/MLS.Agent.csproj index 97f71d6f7..e27fe697a 100644 --- a/MLS.Agent/MLS.Agent.csproj +++ b/MLS.Agent/MLS.Agent.csproj @@ -121,6 +121,9 @@ demo.zip + + + diff --git a/MLS.Agent/Markdown/MarkdownProject.cs b/MLS.Agent/Markdown/MarkdownProject.cs index 74c0b16e9..99ec5cf20 100644 --- a/MLS.Agent/Markdown/MarkdownProject.cs +++ b/MLS.Agent/Markdown/MarkdownProject.cs @@ -71,6 +71,10 @@ public Task TryLockAsync() public void WriteAllText(RelativeFilePath path, string text) { } + + public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite) + { + } } internal IDirectoryAccessor DirectoryAccessor { get; } diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs index e4a254b92..3f47e33b4 100644 --- a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs +++ b/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs @@ -46,7 +46,7 @@ public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() await GetJupyterCommandLine(console, ("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3")).InvokeAsync(); var dotnetDirectoryAccessor = GetExpectedKernelsDirectory().GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath(".NET")); - dotnetDirectoryAccessor.DirectoryExists(".").Should().BeTrue(); + dotnetDirectoryAccessor.RootDirectoryExists().Should().BeTrue(); dotnetDirectoryAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); } } @@ -60,7 +60,6 @@ public override IDirectoryAccessor GetExpectedKernelsDirectory() public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) { - return new JupyterCommandLine(console, environmentVariables); } } @@ -69,7 +68,12 @@ public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests { public override IDirectoryAccessor GetExpectedKernelsDirectory() { - throw new NotImplementedException(); + return new InMemoryDirectoryAccessor() + { + ("kernels.json", ""), + ("logo-32x32.png", ""), + ("logo-64x64.png", "") + }; } public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) diff --git a/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs b/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs index f808b892a..eea7c19bc 100644 --- a/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs +++ b/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs @@ -15,13 +15,13 @@ namespace Microsoft.DotNet.Interactive.Jupyter public class JupyterCommandLine { private IConsole _console; - private readonly IDirectoryAccessor _kernelContentDirAccessor; + private readonly IDirectoryAccessor _kernelContentDir; private readonly (string key, string value)[] _environmentVariables; public JupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) { _console = console; - _kernelContentDirAccessor = new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\try.dot.net\github-try\try\Microsoft.DotNet.Interactive.Jupyter\ContentFiles")); ; + _kernelContentDir = new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\try.dot.net\github-try\try\Microsoft.DotNet.Interactive.Jupyter\ContentFiles")); ; _environmentVariables = environmentVariables; } @@ -57,9 +57,9 @@ private void Installkernel(IEnumerable directoryAccessors, I console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); // Copy the files into the kernels directory - File.Copy(GetFileWithName(_kernelContentDirAccessor, "kernel.json").FullName, dotnetkernelDir.GetFullyQualifiedFilePath("kernel.json").FullName, overwrite: true); - File.Copy(GetFileWithName(_kernelContentDirAccessor, "logo-32x32.png").FullName, dotnetkernelDir.GetFullyQualifiedFilePath("logo-32x32.png").FullName, overwrite: true); - File.Copy(GetFileWithName(_kernelContentDirAccessor, "logo-64x64.png").FullName, dotnetkernelDir.GetFullyQualifiedFilePath("logo-64x64.png").FullName, overwrite: true); + dotnetkernelDir.CopyFileFromDirectory(_kernelContentDir, "kernel.json", overwrite: true); + dotnetkernelDir.CopyFileFromDirectory(_kernelContentDir, "logo-32x32.png", overwrite: true); + dotnetkernelDir.CopyFileFromDirectory(_kernelContentDir, "logo-64x64.png", overwrite: true); console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); } } diff --git a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs index 41836df8c..1a081827c 100644 --- a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs +++ b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs @@ -177,6 +177,16 @@ public IEnumerable GetAllFilesRecursively() public override string ToString() => this.GetFullyQualifiedRoot().FullName; + public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite) + { + var file = directoryAccessor.GetAllFiles().FirstOrDefault(file => file.FileName == filename); + if (file != null) + { + var content = directoryAccessor.ReadAllText(file); + WriteAllText(file, content); + } + } + private class FileSystemInfoComparer : IEqualityComparer { public static FileSystemInfoComparer Instance { get; } = new FileSystemInfoComparer(); diff --git a/WorkspaceServer/FileSystemDirectoryAccessor.cs b/WorkspaceServer/FileSystemDirectoryAccessor.cs index 13a9ba3c5..eb54b067a 100644 --- a/WorkspaceServer/FileSystemDirectoryAccessor.cs +++ b/WorkspaceServer/FileSystemDirectoryAccessor.cs @@ -104,12 +104,12 @@ public IEnumerable GetAllFiles() public override string ToString() => _rootDirectory.FullName; - public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename) + public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite) { var file= directoryAccessor.GetAllFiles().FirstOrDefault(file => file.FileName == filename); if(file!=null) { - File.Copy(directoryAccessor.GetFullyQualifiedFilePath(file.FileName).FullName, GetFullyQualifiedPath( new RelativeFilePath(filename)).FullName); + File.Copy(directoryAccessor.GetFullyQualifiedFilePath(file.FileName).FullName, GetFullyQualifiedPath( new RelativeFilePath(filename)).FullName, overwrite); } } } diff --git a/WorkspaceServer/IDirectoryAccessor.cs b/WorkspaceServer/IDirectoryAccessor.cs index 7171be190..4286dfb29 100644 --- a/WorkspaceServer/IDirectoryAccessor.cs +++ b/WorkspaceServer/IDirectoryAccessor.cs @@ -29,6 +29,6 @@ public interface IDirectoryAccessor IDirectoryAccessor GetDirectoryAccessorForRelativePath(RelativeDirectoryPath path); - void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename); + void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite); } } \ No newline at end of file From c3c9264c7e10c7afff2c75eb42a0bfc1e457c53d Mon Sep 17 00:00:00 2001 From: Akshita Date: Mon, 29 Jul 2019 17:07:22 -0700 Subject: [PATCH 16/47] move files to mls.agent and remove the environment variables stuff --- .../JupyterCommandLineTests.cs | 15 +++++++------ .../JupyterPathInfoTests.cs | 2 +- MLS.Agent.Tools/CommandLine.cs | 9 +++----- .../JupyterCommandLine.cs | 21 +++++++------------ .../JupyterDataPathResult.cs | 2 +- .../JupyterPathInfo.cs | 2 +- 6 files changed, 20 insertions(+), 31 deletions(-) rename {Microsoft.DotNet.Interactive.Jupyter.Tests => MLS.Agent.Tests}/JupyterCommandLineTests.cs (79%) rename {Microsoft.DotNet.Interactive.Jupyter.Tests => MLS.Agent.Tests}/JupyterPathInfoTests.cs (98%) rename {Microsoft.DotNet.Interactive.Jupyter => MLS.Agent}/JupyterCommandLine.cs (68%) rename {Microsoft.DotNet.Interactive.Jupyter => MLS.Agent}/JupyterDataPathResult.cs (93%) rename {Microsoft.DotNet.Interactive.Jupyter => MLS.Agent}/JupyterPathInfo.cs (97%) diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs similarity index 79% rename from Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs rename to MLS.Agent.Tests/JupyterCommandLineTests.cs index 3f47e33b4..9a6c07dbd 100644 --- a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -13,11 +13,11 @@ using WorkspaceServer.Tests; using Xunit; -namespace Microsoft.DotNet.Interactive.Jupyter.Tests +namespace MLS.Agent.Tests { public abstract class JupyterCommandLineTests { - public abstract JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables); + public abstract JupyterCommandLine GetJupyterCommandLine(IConsole console); public abstract IDirectoryAccessor GetExpectedKernelsDirectory(); [Fact] @@ -34,16 +34,15 @@ public async Task Prints_to_console_when_kernel_installation_succeded() //to do: using environment variable this way will cause test flakiness Environment.SetEnvironmentVariable("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3"); var console = new TestConsole(); - await GetJupyterCommandLine(console, ("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3")).InvokeAsync(); + await GetJupyterCommandLine(console).InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } [Fact] public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() { - Environment.SetEnvironmentVariable("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3"); var console = new TestConsole(); - await GetJupyterCommandLine(console, ("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3")).InvokeAsync(); + await GetJupyterCommandLine(console).InvokeAsync(); var dotnetDirectoryAccessor = GetExpectedKernelsDirectory().GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath(".NET")); dotnetDirectoryAccessor.RootDirectoryExists().Should().BeTrue(); @@ -58,9 +57,9 @@ public override IDirectoryAccessor GetExpectedKernelsDirectory() return new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\AppData\Local\Continuum\anaconda3\share\jupyter\kernels")); } - public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) + public override JupyterCommandLine GetJupyterCommandLine(IConsole console) { - return new JupyterCommandLine(console, environmentVariables); + return new JupyterCommandLine(console); } } @@ -76,7 +75,7 @@ public override IDirectoryAccessor GetExpectedKernelsDirectory() }; } - public override JupyterCommandLine GetJupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) + public override JupyterCommandLine GetJupyterCommandLine(IConsole console) { throw new NotImplementedException(); } diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterPathInfoTests.cs b/MLS.Agent.Tests/JupyterPathInfoTests.cs similarity index 98% rename from Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterPathInfoTests.cs rename to MLS.Agent.Tests/JupyterPathInfoTests.cs index 44839e347..01dccb133 100644 --- a/Microsoft.DotNet.Interactive.Jupyter.Tests/JupyterPathInfoTests.cs +++ b/MLS.Agent.Tests/JupyterPathInfoTests.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; -namespace Microsoft.DotNet.Interactive.Jupyter.Tests +namespace MLS.Agent.Tests { public class JupyterPathInfoTests { diff --git a/MLS.Agent.Tools/CommandLine.cs b/MLS.Agent.Tools/CommandLine.cs index 623d54d58..5ff7268bf 100644 --- a/MLS.Agent.Tools/CommandLine.cs +++ b/MLS.Agent.Tools/CommandLine.cs @@ -20,8 +20,7 @@ public static Task Execute( FileInfo exePath, string args, DirectoryInfo workingDir = null, - Budget budget = null, - (string key, string value)[] environmentVariables = null) => + Budget budget = null) => Execute(exePath.FullName, args, workingDir, @@ -31,8 +30,7 @@ public static async Task Execute( string command, string args, DirectoryInfo workingDir = null, - Budget budget = null, - (string key, string value)[] environmentVariables =null) + Budget budget = null) { args = args ?? ""; budget = budget ?? new Budget(); @@ -52,8 +50,7 @@ public static async Task Execute( error: data => { stdErr.AppendLine(data); - }, - environmentVariables)) + })) { var exitCode = await process.Complete(budget); diff --git a/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs similarity index 68% rename from Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs rename to MLS.Agent/JupyterCommandLine.cs index eea7c19bc..089b45058 100644 --- a/Microsoft.DotNet.Interactive.Jupyter/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -10,24 +10,22 @@ using System.Threading.Tasks; using WorkspaceServer; -namespace Microsoft.DotNet.Interactive.Jupyter +namespace MLS.Agent { public class JupyterCommandLine { private IConsole _console; private readonly IDirectoryAccessor _kernelContentDir; - private readonly (string key, string value)[] _environmentVariables; - public JupyterCommandLine(IConsole console, params (string key, string value)[] environmentVariables) + public JupyterCommandLine(IConsole console) { _console = console; _kernelContentDir = new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\try.dot.net\github-try\try\Microsoft.DotNet.Interactive.Jupyter\ContentFiles")); ; - _environmentVariables = environmentVariables; } public async Task InvokeAsync() { - var jupyterPathsResult = await CommandLine.Execute("python.exe", "-m jupyter --paths", environmentVariables: _environmentVariables); + var jupyterPathsResult = await Tools.CommandLine.Execute(@"C:\Users\akagarw\AppData\Local\Continuum\anaconda3\python.exe", "-m jupyter --paths"); var dataPathsResult = JupyterPathInfo.GetDataPaths(jupyterPathsResult); if (string.IsNullOrEmpty(dataPathsResult.Error)) { @@ -56,18 +54,13 @@ private void Installkernel(IEnumerable directoryAccessors, I console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); - // Copy the files into the kernels directory - dotnetkernelDir.CopyFileFromDirectory(_kernelContentDir, "kernel.json", overwrite: true); - dotnetkernelDir.CopyFileFromDirectory(_kernelContentDir, "logo-32x32.png", overwrite: true); - dotnetkernelDir.CopyFileFromDirectory(_kernelContentDir, "logo-64x64.png", overwrite: true); + dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("kernel.json"), typeof(Program).ReadManifestResource("MLS.Agent.kernel.json")); + dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("logo-32x32.png"), typeof(Program).ReadManifestResource("MLS.Agent.logo-32x32.png")); + dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("logo-64x64.png"), typeof(Program).ReadManifestResource("MLS.Agent.logo-64x64.png")); + console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); } } } - - private FileInfo GetFileWithName(IDirectoryAccessor directoryAccessor, string filename) - { - return new FileInfo(directoryAccessor.GetFullyQualifiedFilePath(filename).FullName); - } } } \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive.Jupyter/JupyterDataPathResult.cs b/MLS.Agent/JupyterDataPathResult.cs similarity index 93% rename from Microsoft.DotNet.Interactive.Jupyter/JupyterDataPathResult.cs rename to MLS.Agent/JupyterDataPathResult.cs index e0b8d976a..188c021b0 100644 --- a/Microsoft.DotNet.Interactive.Jupyter/JupyterDataPathResult.cs +++ b/MLS.Agent/JupyterDataPathResult.cs @@ -5,7 +5,7 @@ using System.IO; using System.Linq; -namespace Microsoft.DotNet.Interactive.Jupyter +namespace MLS.Agent { public class JupyterDataPathResult { diff --git a/Microsoft.DotNet.Interactive.Jupyter/JupyterPathInfo.cs b/MLS.Agent/JupyterPathInfo.cs similarity index 97% rename from Microsoft.DotNet.Interactive.Jupyter/JupyterPathInfo.cs rename to MLS.Agent/JupyterPathInfo.cs index 5603a7244..21c63d3db 100644 --- a/Microsoft.DotNet.Interactive.Jupyter/JupyterPathInfo.cs +++ b/MLS.Agent/JupyterPathInfo.cs @@ -7,7 +7,7 @@ using System.Linq; using MLS.Agent.Tools; -namespace Microsoft.DotNet.Interactive.Jupyter +namespace MLS.Agent { public class JupyterPathInfo { From 1551585093e9bedcb070a4831f8d0865ef0ff9e9 Mon Sep 17 00:00:00 2001 From: Akshita Date: Mon, 29 Jul 2019 17:18:07 -0700 Subject: [PATCH 17/47] use python exe locattion --- MLS.Agent.Tests/JupyterCommandLineTests.cs | 2 -- MLS.Agent/CommandLine/CommandLineParser.cs | 1 + MLS.Agent/JupyterCommandLine.cs | 14 +++++++------- MLS.Agent/JupyterPathInfo.cs | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index 9a6c07dbd..1217937bd 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -31,8 +31,6 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() [Fact] public async Task Prints_to_console_when_kernel_installation_succeded() { - //to do: using environment variable this way will cause test flakiness - Environment.SetEnvironmentVariable("path", @"C:\Users\akagarw\AppData\Local\Continuum\anaconda3"); var console = new TestConsole(); await GetJupyterCommandLine(console).InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index 5bbc7d94d..c38d24d25 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -395,6 +395,7 @@ Command Jupyter() var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); installCommand.Handler = CommandHandler.Create(async (console) => { + var pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, "")); return await new JupyterCommandLine(console).InvokeAsync(); }); diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index 089b45058..a6be3b9da 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -14,24 +14,24 @@ namespace MLS.Agent { public class JupyterCommandLine { + private FileInfo _pythonExeLocation; private IConsole _console; - private readonly IDirectoryAccessor _kernelContentDir; public JupyterCommandLine(IConsole console) { + _pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\python.exe")); _console = console; - _kernelContentDir = new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\try.dot.net\github-try\try\Microsoft.DotNet.Interactive.Jupyter\ContentFiles")); ; } public async Task InvokeAsync() { - var jupyterPathsResult = await Tools.CommandLine.Execute(@"C:\Users\akagarw\AppData\Local\Continuum\anaconda3\python.exe", "-m jupyter --paths"); + var jupyterPathsResult = await Tools.CommandLine.Execute(_pythonExeLocation, "-m jupyter --paths"); var dataPathsResult = JupyterPathInfo.GetDataPaths(jupyterPathsResult); if (string.IsNullOrEmpty(dataPathsResult.Error)) { //to do: find out what this path is - Installkernel(dataPathsResult.Paths.Select(path => new FileSystemDirectoryAccessor(path)), _console); + Installkernel(dataPathsResult.Paths.Select(path => new FileSystemDirectoryAccessor(path))); _console.Out.WriteLine(".NET kernel installation succeded"); return 0; } @@ -42,7 +42,7 @@ public async Task InvokeAsync() } } - private void Installkernel(IEnumerable directoryAccessors, IConsole console) + private void Installkernel(IEnumerable directoryAccessors) { foreach (var directoryAccessor in directoryAccessors) { @@ -52,13 +52,13 @@ private void Installkernel(IEnumerable directoryAccessors, I var dotnetkernelDir = kernelsDirAccessor.GetDirectoryAccessorForRelativePath(".NET"); dotnetkernelDir.EnsureRootDirectoryExists(); - console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); + _console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("kernel.json"), typeof(Program).ReadManifestResource("MLS.Agent.kernel.json")); dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("logo-32x32.png"), typeof(Program).ReadManifestResource("MLS.Agent.logo-32x32.png")); dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("logo-64x64.png"), typeof(Program).ReadManifestResource("MLS.Agent.logo-64x64.png")); - console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); + _console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); } } } diff --git a/MLS.Agent/JupyterPathInfo.cs b/MLS.Agent/JupyterPathInfo.cs index 21c63d3db..0815b9a58 100644 --- a/MLS.Agent/JupyterPathInfo.cs +++ b/MLS.Agent/JupyterPathInfo.cs @@ -27,7 +27,7 @@ public static JupyterDataPathResult GetDataPaths(CommandLineResult jupyterPathRe } else { - return new JupyterDataPathResult($"Tried to invoke \"jupyter --paths\" but failed with exception: {string.Join("\n", jupyterPathResult.Error)}"); + return new JupyterDataPathResult($"Tried to invoke \"jupyter --paths\" but failed with error: {string.Join("\n", jupyterPathResult.Error)}"); } } From 2241c0f93c7d22c0b166c23e79368f93a224f6d6 Mon Sep 17 00:00:00 2001 From: Akshita Date: Mon, 29 Jul 2019 17:52:48 -0700 Subject: [PATCH 18/47] pass the expected things from the test --- MLS.Agent.Tests/JupyterCommandLineTests.cs | 93 ++++++++++++++-------- MLS.Agent/CommandLine/CommandLineParser.cs | 3 +- MLS.Agent/JupyterCommandLine.cs | 22 ++++- 3 files changed, 83 insertions(+), 35 deletions(-) diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index 1217937bd..c22d8ae9f 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -12,27 +12,39 @@ using WorkspaceServer; using WorkspaceServer.Tests; using Xunit; +using static MLS.Agent.JupyterCommandLine; namespace MLS.Agent.Tests { - public abstract class JupyterCommandLineTests + public class JupyterCommandLineTests { - public abstract JupyterCommandLine GetJupyterCommandLine(IConsole console); - - public abstract IDirectoryAccessor GetExpectedKernelsDirectory(); [Fact] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); - await GetJupyterCommandLine(console).InvokeAsync(); + var commandLineResult = new CommandLineResult(1); + var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); + await jupyterCommandLine.InvokeAsync(); console.Error.ToString().Should().Contain(".NET kernel installation failed"); } [Fact] public async Task Prints_to_console_when_kernel_installation_succeded() { + const string expectedPath = @"C:\myDataPath"; + + var pathsOutput = +$@"config: + C:\Users\.jupyter +data: + {expectedPath} +runtime: + C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); + var console = new TestConsole(); - await GetJupyterCommandLine(console).InvokeAsync(); + var commandLineResult = new CommandLineResult(0, pathsOutput); + var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); + await jupyterCommandLine.InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } @@ -40,42 +52,61 @@ public async Task Prints_to_console_when_kernel_installation_succeded() public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() { var console = new TestConsole(); - await GetJupyterCommandLine(console).InvokeAsync(); + var commandLineResult = new CommandLineResult(1); + var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); + await jupyterCommandLine.InvokeAsync(); + + throw new NotImplementedException(); - var dotnetDirectoryAccessor = GetExpectedKernelsDirectory().GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath(".NET")); - dotnetDirectoryAccessor.RootDirectoryExists().Should().BeTrue(); - dotnetDirectoryAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); + //var dotnetDirectoryAccessor = GetExpectedKernelsDirectory().GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath(".NET")); + //dotnetDirectoryAccessor.RootDirectoryExists().Should().BeTrue(); + //dotnetDirectoryAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); } } - public class JupyterCommandLineIntegrationTests : JupyterCommandLineTests - { - public override IDirectoryAccessor GetExpectedKernelsDirectory() - { - return new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\AppData\Local\Continuum\anaconda3\share\jupyter\kernels")); - } + //public class JupyterCommandLineIntegrationTests : JupyterCommandLineTests + //{ + // public override IDirectoryAccessor GetExpectedKernelsDirectory() + // { + // return new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\AppData\Local\Continuum\anaconda3\share\jupyter\kernels")); + // } - public override JupyterCommandLine GetJupyterCommandLine(IConsole console) - { - return new JupyterCommandLine(console); - } - } + // public override JupyterCommandLine GetJupyterCommandLine(IConsole console) + // { + // return new JupyterCommandLine(console, new JupyterPathStuff()); + // } + //} + + //public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests + //{ + // public override IDirectoryAccessor GetExpectedKernelsDirectory() + // { + // return new InMemoryDirectoryAccessor() + // { + // ("kernels.json", ""), + // ("logo-32x32.png", ""), + // ("logo-64x64.png", "") + // }; + // } - public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests + // public override JupyterCommandLine GetJupyterCommandLine(IConsole console, CommandLineResult commandLineResult) + // { + // return new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); + // } + //} + + public class InMemoryJupyterPathStuff : IJupyterPathStuff { - public override IDirectoryAccessor GetExpectedKernelsDirectory() + private CommandLineResult _commandLineResult; + + public InMemoryJupyterPathStuff(CommandLineResult commandLineResult) { - return new InMemoryDirectoryAccessor() - { - ("kernels.json", ""), - ("logo-32x32.png", ""), - ("logo-64x64.png", "") - }; + _commandLineResult = commandLineResult; } - public override JupyterCommandLine GetJupyterCommandLine(IConsole console) + public async Task GetJupyterPaths(FileInfo fileInfo, string args) { - throw new NotImplementedException(); + return _commandLineResult; } } } \ No newline at end of file diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index c38d24d25..f371a5e3a 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -395,8 +395,7 @@ Command Jupyter() var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); installCommand.Handler = CommandHandler.Create(async (console) => { - var pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, "")); - return await new JupyterCommandLine(console).InvokeAsync(); + return await new JupyterCommandLine(console, new JupyterPathStuff()).InvokeAsync(); }); jupyterCommand.AddCommand(installCommand); diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index a6be3b9da..65ab2cbfd 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using MLS.Agent.CommandLine; using MLS.Agent.Tools; using System; using System.Collections.Generic; @@ -16,16 +17,20 @@ public class JupyterCommandLine { private FileInfo _pythonExeLocation; private IConsole _console; + private IJupyterPathStuff _jupyterPathStuff; - public JupyterCommandLine(IConsole console) + public delegate Task GetJupyterPaths(FileInfo pythonExeLocation, string args); + + public JupyterCommandLine(IConsole console, IJupyterPathStuff jupyterPathStuff) { _pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\python.exe")); _console = console; + _jupyterPathStuff = jupyterPathStuff; } public async Task InvokeAsync() { - var jupyterPathsResult = await Tools.CommandLine.Execute(_pythonExeLocation, "-m jupyter --paths"); + var jupyterPathsResult = await _jupyterPathStuff.GetJupyterPaths(_pythonExeLocation, "-m jupyter --paths"); var dataPathsResult = JupyterPathInfo.GetDataPaths(jupyterPathsResult); if (string.IsNullOrEmpty(dataPathsResult.Error)) { @@ -63,4 +68,17 @@ private void Installkernel(IEnumerable directoryAccessors) } } } + + public interface IJupyterPathStuff + { + Task GetJupyterPaths(FileInfo fileInfo, string args); + } + + public class JupyterPathStuff : IJupyterPathStuff + { + public Task GetJupyterPaths(FileInfo fileInfo, string args) + { + return Tools.CommandLine.Execute(fileInfo, args); + } + } } \ No newline at end of file From 9ff64dafad41d288b98c235f5e1cd8f598f590fb Mon Sep 17 00:00:00 2001 From: Akshita Date: Mon, 29 Jul 2019 19:12:20 -0700 Subject: [PATCH 19/47] change the structure to use a helper --- MLS.Agent.Tests/JupyterCommandLineTests.cs | 91 +++++++++------------- MLS.Agent.Tests/JupyterPathInfoTests.cs | 79 ------------------- MLS.Agent/CommandLine/CommandLineParser.cs | 2 +- MLS.Agent/JupyterCommandLine.cs | 67 ++++++++++++---- MLS.Agent/JupyterDataPathResult.cs | 6 +- MLS.Agent/JupyterPathInfo.cs | 51 ------------ 6 files changed, 95 insertions(+), 201 deletions(-) delete mode 100644 MLS.Agent.Tests/JupyterPathInfoTests.cs delete mode 100644 MLS.Agent/JupyterPathInfo.cs diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index c22d8ae9f..dab9e2853 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -5,6 +5,7 @@ using Microsoft.DotNet.Try.Markdown; using MLS.Agent.Tools; using System; +using System.Collections.Generic; using System.CommandLine; using System.IO; using System.Linq; @@ -23,7 +24,7 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); var commandLineResult = new CommandLineResult(1); - var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); + var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathsHelper(commandLineResult)); await jupyterCommandLine.InvokeAsync(); console.Error.ToString().Should().Contain(".NET kernel installation failed"); } @@ -31,19 +32,10 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() [Fact] public async Task Prints_to_console_when_kernel_installation_succeded() { - const string expectedPath = @"C:\myDataPath"; - - var pathsOutput = -$@"config: - C:\Users\.jupyter -data: - {expectedPath} -runtime: - C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); - + const string dataDirectory = @"C:\myDataPath"; var console = new TestConsole(); - var commandLineResult = new CommandLineResult(0, pathsOutput); - var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); + var jupyterPathsHelper = new InMemoryJupyterPathsHelper(dataDirectory); + var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } @@ -51,59 +43,52 @@ public async Task Prints_to_console_when_kernel_installation_succeded() [Fact] public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() { + const string dataDirectory = @"C:\myDataPath"; + var console = new TestConsole(); - var commandLineResult = new CommandLineResult(1); - var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); + var jupyterPathsHelper = new InMemoryJupyterPathsHelper(dataDirectory); + var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); - throw new NotImplementedException(); - - //var dotnetDirectoryAccessor = GetExpectedKernelsDirectory().GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath(".NET")); - //dotnetDirectoryAccessor.RootDirectoryExists().Should().BeTrue(); - //dotnetDirectoryAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); + var dotnetDirAccessor = jupyterPathsHelper.GetDirectoryAccessorForPath(dataDirectory).GetDirectoryAccessorForRelativePath("kernels/.NET"); + dotnetDirAccessor.RootDirectoryExists().Should().BeTrue(); + dotnetDirAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); } } - //public class JupyterCommandLineIntegrationTests : JupyterCommandLineTests - //{ - // public override IDirectoryAccessor GetExpectedKernelsDirectory() - // { - // return new FileSystemDirectoryAccessor(new DirectoryInfo(@"C:\Users\akagarw\AppData\Local\Continuum\anaconda3\share\jupyter\kernels")); - // } - - // public override JupyterCommandLine GetJupyterCommandLine(IConsole console) - // { - // return new JupyterCommandLine(console, new JupyterPathStuff()); - // } - //} - - //public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests - //{ - // public override IDirectoryAccessor GetExpectedKernelsDirectory() - // { - // return new InMemoryDirectoryAccessor() - // { - // ("kernels.json", ""), - // ("logo-32x32.png", ""), - // ("logo-64x64.png", "") - // }; - // } - - // public override JupyterCommandLine GetJupyterCommandLine(IConsole console, CommandLineResult commandLineResult) - // { - // return new JupyterCommandLine(console, new InMemoryJupyterPathStuff(commandLineResult)); - // } - //} - - public class InMemoryJupyterPathStuff : IJupyterPathStuff + public class InMemoryJupyterPathsHelper : IJupyterPathsHelper { private CommandLineResult _commandLineResult; + private Dictionary _dataDirectories; - public InMemoryJupyterPathStuff(CommandLineResult commandLineResult) + public InMemoryJupyterPathsHelper(CommandLineResult commandLineResult) { _commandLineResult = commandLineResult; } + public InMemoryJupyterPathsHelper(string dataDirectory) + { + var pathsOutput = +$@"config: + C:\Users\.jupyter +data: + {dataDirectory} +runtime: + C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); + + _commandLineResult = new CommandLineResult(0, pathsOutput); + _dataDirectories = new Dictionary + { + { dataDirectory, new InMemoryDirectoryAccessor(new DirectoryInfo(dataDirectory)) } + }; + } + + public IDirectoryAccessor GetDirectoryAccessorForPath(string path) + { + _dataDirectories.TryGetValue(path, out var value); + return value; + } + public async Task GetJupyterPaths(FileInfo fileInfo, string args) { return _commandLineResult; diff --git a/MLS.Agent.Tests/JupyterPathInfoTests.cs b/MLS.Agent.Tests/JupyterPathInfoTests.cs deleted file mode 100644 index 01dccb133..000000000 --- a/MLS.Agent.Tests/JupyterPathInfoTests.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Xunit; -using FluentAssertions; -using MLS.Agent.Tools; -using System.Collections.Generic; -using System.Linq; - -namespace MLS.Agent.Tests -{ - public class JupyterPathInfoTests - { - [Fact] - public void If_data_paths_are_present_GetDataPaths_returns_the_paths() - { - const string expectedPath = @"C:\myDataPath"; - - var pathsOutput = -$@"config: - C:\Users\.jupyter -data: - {expectedPath} -runtime: - C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); - var commandLineResult = new CommandLineResult(0, pathsOutput); - var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); - dataPathsResult.Paths.Should().HaveCount(1); - - dataPathsResult.Paths.First().FullName.Should().Be(expectedPath); - dataPathsResult.Error.Should().BeEmpty(); - } - - [Fact] - public void If_data_paths_are_not_present_GetDataPaths_returns_the_error() - { - var pathsOutput = -$@"config: - C:\Users\.jupyter -runtime: - C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); - var commandLineResult = new CommandLineResult(0, pathsOutput); - var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); - dataPathsResult.Error.Should().NotBeNull(); - } - - - [Fact] - public void If_the_command_line_result_has_error_GetDataPaths_returns_error() - { - var error = "some error"; - var commandLineResult = new CommandLineResult(1, null, new List(){ error }); - var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); - dataPathsResult.Paths.Should().BeEmpty(); - dataPathsResult.Error.Should().Contain(error); - } - - [Fact] - public void GetDataPaths_returns_the_data_paths_when_datapaths_appear_the_last_in_the_output() - { - const string expectedPath1 = @"C:\myDataPath1"; - const string expectedPath2 = @"C:\myDataPath2"; - - var pathsOutput = - $@"config: - C:\Users\.jupyter -runtime: - C:\Users\AppData\Roaming\jupyter\runtime -data: - {expectedPath1} - {expectedPath2}".Split("\n"); - var commandLineResult = new CommandLineResult(0, pathsOutput); - var dataPathsResult = JupyterPathInfo.GetDataPaths(commandLineResult); - - dataPathsResult.Paths.Should().Contain(dir => dir.FullName == expectedPath1); - dataPathsResult.Paths.Should().Contain(dir => dir.FullName == expectedPath2); - } - } -} \ No newline at end of file diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index f371a5e3a..8e664f542 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -395,7 +395,7 @@ Command Jupyter() var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); installCommand.Handler = CommandHandler.Create(async (console) => { - return await new JupyterCommandLine(console, new JupyterPathStuff()).InvokeAsync(); + return await new JupyterCommandLine(console, new JupyterPathsHelper()).InvokeAsync(); }); jupyterCommand.AddCommand(installCommand); diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index 65ab2cbfd..7996fd332 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -15,28 +15,23 @@ namespace MLS.Agent { public class JupyterCommandLine { - private FileInfo _pythonExeLocation; - private IConsole _console; - private IJupyterPathStuff _jupyterPathStuff; + private readonly FileInfo _pythonExeLocation; + private readonly IConsole _console; + private readonly IJupyterPathsHelper _jupyterPathsHelper; - public delegate Task GetJupyterPaths(FileInfo pythonExeLocation, string args); - - public JupyterCommandLine(IConsole console, IJupyterPathStuff jupyterPathStuff) + public JupyterCommandLine(IConsole console, IJupyterPathsHelper jupyterPathsHelper) { _pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\python.exe")); _console = console; - _jupyterPathStuff = jupyterPathStuff; + _jupyterPathsHelper = jupyterPathsHelper; } public async Task InvokeAsync() { - var jupyterPathsResult = await _jupyterPathStuff.GetJupyterPaths(_pythonExeLocation, "-m jupyter --paths"); - var dataPathsResult = JupyterPathInfo.GetDataPaths(jupyterPathsResult); + var dataPathsResult = await GetDataPathsAsync(); if (string.IsNullOrEmpty(dataPathsResult.Error)) { - //to do: find out what this path is - - Installkernel(dataPathsResult.Paths.Select(path => new FileSystemDirectoryAccessor(path))); + Installkernel(dataPathsResult.Paths); _console.Out.WriteLine(".NET kernel installation succeded"); return 0; } @@ -67,15 +62,59 @@ private void Installkernel(IEnumerable directoryAccessors) } } } + + public async Task GetDataPathsAsync() + { + var jupyterPathResult = await _jupyterPathsHelper.GetJupyterPaths(_pythonExeLocation, "-m jupyter --paths"); + if (jupyterPathResult.ExitCode == 0) + { + if (TryGetDataPaths(jupyterPathResult.Output.ToArray(), out var dataPaths)) + { + return new JupyterDataPathResult(dataPaths); + } + else + { + return new JupyterDataPathResult($"Could not find the jupyter kernel installation directory." + + $" Output of \"jupyter --paths\" is {string.Join("\n", jupyterPathResult.Output.ToArray())}"); + } + } + else + { + return new JupyterDataPathResult($"Tried to invoke \"jupyter --paths\" but failed with error: {string.Join("\n", jupyterPathResult.Error)}"); + } + } + + private bool TryGetDataPaths(string[] pathInfo, out IEnumerable dataPathsAccessor) + { + var dataHeaderIndex = Array.FindIndex(pathInfo, element => element.Trim().CompareTo("data:") == 0); + if (dataHeaderIndex != -1) + { + var nextHeaderIndex = Array.FindIndex(pathInfo, dataHeaderIndex + 1, element => element.Trim().EndsWith(":")); + if (nextHeaderIndex == -1) + nextHeaderIndex = pathInfo.Count(); + + dataPathsAccessor = pathInfo.Skip(dataHeaderIndex + 1).Take(nextHeaderIndex - dataHeaderIndex - 1).Select(dir => _jupyterPathsHelper.GetDirectoryAccessorForPath(dir.Trim())); + return true; + } + + dataPathsAccessor = null; + return false; + } } - public interface IJupyterPathStuff + public interface IJupyterPathsHelper { + IDirectoryAccessor GetDirectoryAccessorForPath(string v); Task GetJupyterPaths(FileInfo fileInfo, string args); } - public class JupyterPathStuff : IJupyterPathStuff + public class JupyterPathsHelper : IJupyterPathsHelper { + public IDirectoryAccessor GetDirectoryAccessorForPath(string path) + { + return new FileSystemDirectoryAccessor(new DirectoryInfo(path)); + } + public Task GetJupyterPaths(FileInfo fileInfo, string args) { return Tools.CommandLine.Execute(fileInfo, args); diff --git a/MLS.Agent/JupyterDataPathResult.cs b/MLS.Agent/JupyterDataPathResult.cs index 188c021b0..fb8b5012e 100644 --- a/MLS.Agent/JupyterDataPathResult.cs +++ b/MLS.Agent/JupyterDataPathResult.cs @@ -4,12 +4,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using WorkspaceServer; namespace MLS.Agent { public class JupyterDataPathResult { - public JupyterDataPathResult(IEnumerable paths) + public JupyterDataPathResult(IEnumerable paths) { Paths = paths; Error = ""; @@ -17,11 +18,10 @@ public JupyterDataPathResult(IEnumerable paths) public JupyterDataPathResult(string error) { - Paths = Enumerable.Empty(); Error = error; } - public IEnumerable Paths { get; } + public IEnumerable Paths { get; } public string Error { get; } } } \ No newline at end of file diff --git a/MLS.Agent/JupyterPathInfo.cs b/MLS.Agent/JupyterPathInfo.cs deleted file mode 100644 index 0815b9a58..000000000 --- a/MLS.Agent/JupyterPathInfo.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using MLS.Agent.Tools; - -namespace MLS.Agent -{ - public class JupyterPathInfo - { - public static JupyterDataPathResult GetDataPaths(CommandLineResult jupyterPathResult) - { - if (jupyterPathResult.ExitCode == 0) - { - if (TryGetDataPaths(jupyterPathResult.Output.ToArray(), out var dataPaths)) - { - return new JupyterDataPathResult(dataPaths); - } - else - { - return new JupyterDataPathResult($"Could not find the jupyter kernel installation directory." + - $" Output of \"jupyter --paths\" is {string.Join("\n", jupyterPathResult.Output.ToArray())}"); - } - } - else - { - return new JupyterDataPathResult($"Tried to invoke \"jupyter --paths\" but failed with error: {string.Join("\n", jupyterPathResult.Error)}"); - } - } - - private static bool TryGetDataPaths(string[] pathInfo, out IEnumerable dataPaths) - { - var dataHeaderIndex = Array.FindIndex(pathInfo, element => element.Trim().CompareTo("data:") == 0); - if (dataHeaderIndex != -1) - { - var nextHeaderIndex = Array.FindIndex(pathInfo, dataHeaderIndex + 1, element => element.Trim().EndsWith(":")); - if (nextHeaderIndex == -1) - nextHeaderIndex = pathInfo.Count(); - - dataPaths = pathInfo.Skip(dataHeaderIndex + 1).Take(nextHeaderIndex - dataHeaderIndex - 1).Select(dir => new DirectoryInfo(dir.Trim())); - return true; - } - - dataPaths = Enumerable.Empty(); - return false; - } - } -} \ No newline at end of file From e8cf00f4364196aabf646aeb5248e1dfb47520bb Mon Sep 17 00:00:00 2001 From: Akshita Date: Mon, 29 Jul 2019 19:16:21 -0700 Subject: [PATCH 20/47] remove not needed copy method --- MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs | 12 ------------ MLS.Agent/Markdown/MarkdownProject.cs | 5 ----- WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs | 10 ---------- WorkspaceServer/IDirectoryAccessor.cs | 2 -- 4 files changed, 29 deletions(-) diff --git a/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs b/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs index 49d0ac624..1e19cff54 100644 --- a/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs +++ b/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs @@ -259,18 +259,6 @@ public void It_can_make_a_directory_accessor_from_an_absolute_DirectoryInfo() subdirectory.FileExists("Tutorial.md").Should().BeTrue(); } - - - [Fact] - public void It_can_copy_files() - { - var targetDirectory = CreateDirectory(); - var sourceDirectory = GetDirectory(TestAssets.SampleConsole); - - targetDirectory.CopyFileFromDirectory(sourceDirectory, "Program.cs", true); - targetDirectory.FileExists("Program.cs").Should().BeTrue(); - targetDirectory.ReadAllText("Program.cs").Should().Contain("using System"); - } } public class FileSystemDirectoryAccessorTests : DirectoryAccessorTests diff --git a/MLS.Agent/Markdown/MarkdownProject.cs b/MLS.Agent/Markdown/MarkdownProject.cs index 99ec5cf20..deea1c935 100644 --- a/MLS.Agent/Markdown/MarkdownProject.cs +++ b/MLS.Agent/Markdown/MarkdownProject.cs @@ -71,12 +71,7 @@ public Task TryLockAsync() public void WriteAllText(RelativeFilePath path, string text) { } - - public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite) - { - } } - internal IDirectoryAccessor DirectoryAccessor { get; } private readonly PackageRegistry _packageRegistry; diff --git a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs index 1a081827c..41836df8c 100644 --- a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs +++ b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs @@ -177,16 +177,6 @@ public IEnumerable GetAllFilesRecursively() public override string ToString() => this.GetFullyQualifiedRoot().FullName; - public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite) - { - var file = directoryAccessor.GetAllFiles().FirstOrDefault(file => file.FileName == filename); - if (file != null) - { - var content = directoryAccessor.ReadAllText(file); - WriteAllText(file, content); - } - } - private class FileSystemInfoComparer : IEqualityComparer { public static FileSystemInfoComparer Instance { get; } = new FileSystemInfoComparer(); diff --git a/WorkspaceServer/IDirectoryAccessor.cs b/WorkspaceServer/IDirectoryAccessor.cs index 4286dfb29..f0bfe7ef4 100644 --- a/WorkspaceServer/IDirectoryAccessor.cs +++ b/WorkspaceServer/IDirectoryAccessor.cs @@ -28,7 +28,5 @@ public interface IDirectoryAccessor FileSystemInfo GetFullyQualifiedPath(RelativePath path); IDirectoryAccessor GetDirectoryAccessorForRelativePath(RelativeDirectoryPath path); - - void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite); } } \ No newline at end of file From cdaa3a7d616a7339fad928266a9ba43b3d9cd8d1 Mon Sep 17 00:00:00 2001 From: Akshita Date: Mon, 29 Jul 2019 20:01:11 -0700 Subject: [PATCH 21/47] add the tests for helpers --- MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs | 53 +++++++++++++++++ MLS.Agent.Tests/JupyterCommandLineTests.cs | 59 ++++++------------- .../InMemoryDirectoryAccessor.cs | 1 + 3 files changed, 72 insertions(+), 41 deletions(-) create mode 100644 MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs diff --git a/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs b/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs new file mode 100644 index 000000000..c3a027f96 --- /dev/null +++ b/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs @@ -0,0 +1,53 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using MLS.Agent.Tools; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using WorkspaceServer; +using WorkspaceServer.Tests; + +namespace MLS.Agent.Tests +{ + public class InMemoryJupyterPathsHelper : IJupyterPathsHelper + { + private CommandLineResult _commandLineResult; + private Dictionary _dataDirectories; + + public InMemoryJupyterPathsHelper(CommandLineResult commandLineResult) + { + _commandLineResult = commandLineResult; + } + + public InMemoryJupyterPathsHelper(string dataDirectory) + { + var pathsOutput = +$@"config: + C:\Users\.jupyter +data: + {dataDirectory} +runtime: + C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); + + _commandLineResult = new CommandLineResult(0, pathsOutput); + var directoryAccessor = new InMemoryDirectoryAccessor(new DirectoryInfo(dataDirectory)); + directoryAccessor.EnsureRootDirectoryExists(); + _dataDirectories = new Dictionary + { + { dataDirectory, directoryAccessor } + }; + } + + public IDirectoryAccessor GetDirectoryAccessorForPath(string path) + { + _dataDirectories.TryGetValue(path, out var value); + return value; + } + + public async Task GetJupyterPaths(FileInfo fileInfo, string args) + { + return _commandLineResult; + } + } +} \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index dab9e2853..acdb7922e 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -5,26 +5,26 @@ using Microsoft.DotNet.Try.Markdown; using MLS.Agent.Tools; using System; -using System.Collections.Generic; using System.CommandLine; using System.IO; using System.Linq; using System.Threading.Tasks; using WorkspaceServer; -using WorkspaceServer.Tests; using Xunit; using static MLS.Agent.JupyterCommandLine; namespace MLS.Agent.Tests { - public class JupyterCommandLineTests + public abstract class JupyterCommandLineTests { + public abstract IJupyterPathsHelper GetJupyterPathsHelper(); + [Fact] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); var commandLineResult = new CommandLineResult(1); - var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterPathsHelper(commandLineResult)); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper()); await jupyterCommandLine.InvokeAsync(); console.Error.ToString().Should().Contain(".NET kernel installation failed"); } @@ -32,10 +32,8 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() [Fact] public async Task Prints_to_console_when_kernel_installation_succeded() { - const string dataDirectory = @"C:\myDataPath"; var console = new TestConsole(); - var jupyterPathsHelper = new InMemoryJupyterPathsHelper(dataDirectory); - var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper()); await jupyterCommandLine.InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } @@ -43,55 +41,34 @@ public async Task Prints_to_console_when_kernel_installation_succeded() [Fact] public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() { - const string dataDirectory = @"C:\myDataPath"; + var dataDirectory = Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\share\jupyter"); var console = new TestConsole(); - var jupyterPathsHelper = new InMemoryJupyterPathsHelper(dataDirectory); + var jupyterPathsHelper = GetJupyterPathsHelper(); var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); var dotnetDirAccessor = jupyterPathsHelper.GetDirectoryAccessorForPath(dataDirectory).GetDirectoryAccessorForRelativePath("kernels/.NET"); dotnetDirAccessor.RootDirectoryExists().Should().BeTrue(); - dotnetDirAccessor.GetAllFiles().Select(file => file.FileName).Should().BeEquivalentTo("kernel.json", "logo-32x32.png", "logo-64x64.png"); + dotnetDirAccessor.FileExists("kernel.json").Should().BeTrue(); + dotnetDirAccessor.FileExists("logo-32x32.png").Should().BeTrue(); + dotnetDirAccessor.FileExists("logo-64x64.png").Should().BeTrue(); } } - public class InMemoryJupyterPathsHelper : IJupyterPathsHelper + public class JupyterCommandLineIntegrationTests : JupyterCommandLineTests { - private CommandLineResult _commandLineResult; - private Dictionary _dataDirectories; - - public InMemoryJupyterPathsHelper(CommandLineResult commandLineResult) - { - _commandLineResult = commandLineResult; - } - - public InMemoryJupyterPathsHelper(string dataDirectory) + public override IJupyterPathsHelper GetJupyterPathsHelper() { - var pathsOutput = -$@"config: - C:\Users\.jupyter -data: - {dataDirectory} -runtime: - C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); - - _commandLineResult = new CommandLineResult(0, pathsOutput); - _dataDirectories = new Dictionary - { - { dataDirectory, new InMemoryDirectoryAccessor(new DirectoryInfo(dataDirectory)) } - }; - } - - public IDirectoryAccessor GetDirectoryAccessorForPath(string path) - { - _dataDirectories.TryGetValue(path, out var value); - return value; + return new JupyterPathsHelper(); } + } - public async Task GetJupyterPaths(FileInfo fileInfo, string args) + public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests + { + public override IJupyterPathsHelper GetJupyterPathsHelper() { - return _commandLineResult; + return new InMemoryJupyterPathsHelper(new CommandLineResult(0)); } } } \ No newline at end of file diff --git a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs index 41836df8c..712fffd91 100644 --- a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs +++ b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs @@ -144,6 +144,7 @@ public IEnumerator GetEnumerator() public IDirectoryAccessor GetDirectoryAccessorForRelativePath(RelativeDirectoryPath relativePath) { var newPath = WorkingDirectory.Combine(relativePath); + return new InMemoryDirectoryAccessor(newPath) { _files = _files From c4050882e1e68b2f44bd99427c0acfe0894816c6 Mon Sep 17 00:00:00 2001 From: Akshita Date: Tue, 30 Jul 2019 14:48:43 -0700 Subject: [PATCH 22/47] add ncrunch not ablr to build --- MLS.Agent/MLS.Agent.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MLS.Agent/MLS.Agent.csproj b/MLS.Agent/MLS.Agent.csproj index e27fe697a..303ca1352 100644 --- a/MLS.Agent/MLS.Agent.csproj +++ b/MLS.Agent/MLS.Agent.csproj @@ -33,6 +33,9 @@ + + + all From 02a8c802f3dac1bd35b7887fa4cbf298b7fec8ea Mon Sep 17 00:00:00 2001 From: Akshita Date: Tue, 30 Jul 2019 17:36:56 -0700 Subject: [PATCH 23/47] try to use the install command --- MLS.Agent.Tests/JupyterCommandLineTests.cs | 18 +++-- MLS.Agent/JupyterCommandLine.cs | 87 ++++++---------------- MLS.Agent/MLS.Agent.csproj | 19 +++-- 3 files changed, 48 insertions(+), 76 deletions(-) diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index acdb7922e..ac565f441 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -17,14 +17,14 @@ namespace MLS.Agent.Tests { public abstract class JupyterCommandLineTests { - public abstract IJupyterPathsHelper GetJupyterPathsHelper(); + public abstract IJupyterPathsHelper GetJupyterPathsHelper(CommandLineResult commandLineResult); [Fact] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); var commandLineResult = new CommandLineResult(1); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper()); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper(commandLineResult)); await jupyterCommandLine.InvokeAsync(); console.Error.ToString().Should().Contain(".NET kernel installation failed"); } @@ -33,7 +33,8 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() public async Task Prints_to_console_when_kernel_installation_succeded() { var console = new TestConsole(); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper()); + var commandLineResult = new CommandLineResult(0); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper(commandLineResult)); await jupyterCommandLine.InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } @@ -44,7 +45,8 @@ public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() var dataDirectory = Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\share\jupyter"); var console = new TestConsole(); - var jupyterPathsHelper = GetJupyterPathsHelper(); + var commandLineResult = new CommandLineResult(0); + var jupyterPathsHelper = GetJupyterPathsHelper(commandLineResult); var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); @@ -56,9 +58,9 @@ public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() } } - public class JupyterCommandLineIntegrationTests : JupyterCommandLineTests + public class JupyterCommandLineIntegrationTests: JupyterCommandLineTests { - public override IJupyterPathsHelper GetJupyterPathsHelper() + public override IJupyterPathsHelper GetJupyterPathsHelper(CommandLineResult commandLineResult) { return new JupyterPathsHelper(); } @@ -66,9 +68,9 @@ public override IJupyterPathsHelper GetJupyterPathsHelper() public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests { - public override IJupyterPathsHelper GetJupyterPathsHelper() + public override IJupyterPathsHelper GetJupyterPathsHelper(CommandLineResult commandLineResult) { - return new InMemoryJupyterPathsHelper(new CommandLineResult(0)); + return new InMemoryJupyterPathsHelper(commandLineResult); } } } \ No newline at end of file diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index 7996fd332..862221e38 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -4,10 +4,13 @@ using MLS.Agent.CommandLine; using MLS.Agent.Tools; using System; +using System.Collections; using System.Collections.Generic; using System.CommandLine; using System.IO; +using System.IO.Compression; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using WorkspaceServer; @@ -28,77 +31,35 @@ public JupyterCommandLine(IConsole console, IJupyterPathsHelper jupyterPathsHelp public async Task InvokeAsync() { - var dataPathsResult = await GetDataPathsAsync(); - if (string.IsNullOrEmpty(dataPathsResult.Error)) + using (var disposableDirectory = DisposableDirectory.Create()) { - Installkernel(dataPathsResult.Paths); - _console.Out.WriteLine(".NET kernel installation succeded"); - return 0; - } - else - { - _console.Error.WriteLine($".NET kernel installation failed with error: {dataPathsResult.Error}"); - return -1; - } - } + var assembly = typeof(Program).Assembly; - private void Installkernel(IEnumerable directoryAccessors) - { - foreach (var directoryAccessor in directoryAccessors) - { - var kernelsDirAccessor = directoryAccessor.GetDirectoryAccessorForRelativePath("kernels"); - if (kernelsDirAccessor.RootDirectoryExists()) + using (var resourceStream = assembly.GetManifestResourceStream("dotnetKernel.zip")) { - var dotnetkernelDir = kernelsDirAccessor.GetDirectoryAccessorForRelativePath(".NET"); - dotnetkernelDir.EnsureRootDirectoryExists(); + var zipPath = Path.Combine(disposableDirectory.Directory.FullName, "dotnetKernel.zip"); - _console.Out.WriteLine($"Installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); + using (var fileStream = new FileStream(zipPath, FileMode.Create, FileAccess.Write)) + { + resourceStream.CopyTo(fileStream); + } - dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("kernel.json"), typeof(Program).ReadManifestResource("MLS.Agent.kernel.json")); - dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("logo-32x32.png"), typeof(Program).ReadManifestResource("MLS.Agent.logo-32x32.png")); - dotnetkernelDir.WriteAllText(new Microsoft.DotNet.Try.Markdown.RelativeFilePath("logo-64x64.png"), typeof(Program).ReadManifestResource("MLS.Agent.logo-64x64.png")); - - _console.Out.WriteLine($"Finished installing the .NET kernel in directory: {dotnetkernelDir.GetFullyQualifiedRoot()}"); - } - } - } - - public async Task GetDataPathsAsync() - { - var jupyterPathResult = await _jupyterPathsHelper.GetJupyterPaths(_pythonExeLocation, "-m jupyter --paths"); - if (jupyterPathResult.ExitCode == 0) - { - if (TryGetDataPaths(jupyterPathResult.Output.ToArray(), out var dataPaths)) - { - return new JupyterDataPathResult(dataPaths); - } - else - { - return new JupyterDataPathResult($"Could not find the jupyter kernel installation directory." + - $" Output of \"jupyter --paths\" is {string.Join("\n", jupyterPathResult.Output.ToArray())}"); - } - } - else - { - return new JupyterDataPathResult($"Tried to invoke \"jupyter --paths\" but failed with error: {string.Join("\n", jupyterPathResult.Error)}"); - } - } + ZipFile.ExtractToDirectory(zipPath, disposableDirectory.Directory.FullName); - private bool TryGetDataPaths(string[] pathInfo, out IEnumerable dataPathsAccessor) - { - var dataHeaderIndex = Array.FindIndex(pathInfo, element => element.Trim().CompareTo("data:") == 0); - if (dataHeaderIndex != -1) - { - var nextHeaderIndex = Array.FindIndex(pathInfo, dataHeaderIndex + 1, element => element.Trim().EndsWith(":")); - if (nextHeaderIndex == -1) - nextHeaderIndex = pathInfo.Count(); + var result = await _jupyterPathsHelper.GetJupyterPaths(_pythonExeLocation, $"-m jupyter kernelspec install {disposableDirectory.Directory.Subdirectory("dotnetKernel").FullName}"); - dataPathsAccessor = pathInfo.Skip(dataHeaderIndex + 1).Take(nextHeaderIndex - dataHeaderIndex - 1).Select(dir => _jupyterPathsHelper.GetDirectoryAccessorForPath(dir.Trim())); - return true; + if(result.ExitCode ==0) + { + _console.Out.WriteLine(".NET kernel installation succeded"); + return 0; + } + else + { + _console.Error.WriteLine($".NET kernel installation failed with error: {string.Join('\n', result.Error)}"); + return -1; + } + } } - - dataPathsAccessor = null; - return false; } } diff --git a/MLS.Agent/MLS.Agent.csproj b/MLS.Agent/MLS.Agent.csproj index 303ca1352..cebce1cb1 100644 --- a/MLS.Agent/MLS.Agent.csproj +++ b/MLS.Agent/MLS.Agent.csproj @@ -32,10 +32,7 @@ - - - - + all @@ -196,7 +193,7 @@ - + PreserveNewest @@ -215,4 +212,16 @@ + + + + + + + + + + + + From d08840b79a6ea3a7bc3810399c57258c8bd04056 Mon Sep 17 00:00:00 2001 From: Akshita Date: Tue, 30 Jul 2019 18:20:09 -0700 Subject: [PATCH 24/47] add code to use the zip and the kernelspec install --- MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs | 8 +----- MLS.Agent.Tests/JupyterCommandLineTests.cs | 9 +++---- MLS.Agent/IJupyterPathsHelper.cs | 14 +++++++++++ MLS.Agent/JupyterCommandLine.cs | 23 ++--------------- MLS.Agent/JupyterPathsHelper.cs | 25 +++++++++++++++++++ MLS.Agent/MLS.Agent.csproj | 8 +++--- 6 files changed, 49 insertions(+), 38 deletions(-) create mode 100644 MLS.Agent/IJupyterPathsHelper.cs create mode 100644 MLS.Agent/JupyterPathsHelper.cs diff --git a/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs b/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs index c3a027f96..eebd28557 100644 --- a/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs +++ b/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs @@ -39,13 +39,7 @@ public InMemoryJupyterPathsHelper(string dataDirectory) }; } - public IDirectoryAccessor GetDirectoryAccessorForPath(string path) - { - _dataDirectories.TryGetValue(path, out var value); - return value; - } - - public async Task GetJupyterPaths(FileInfo fileInfo, string args) + public async Task ExecuteCommand(string args) { return _commandLineResult; } diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index ac565f441..23eb45d09 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -40,7 +40,7 @@ public async Task Prints_to_console_when_kernel_installation_succeded() } [Fact] - public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() + public async Task After_installation_kernelspec_list_gives_dotnet() { var dataDirectory = Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\share\jupyter"); @@ -50,11 +50,8 @@ public async Task Adds_the_kernels_json_file_and_logos_in_data_directory() var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); - var dotnetDirAccessor = jupyterPathsHelper.GetDirectoryAccessorForPath(dataDirectory).GetDirectoryAccessorForRelativePath("kernels/.NET"); - dotnetDirAccessor.RootDirectoryExists().Should().BeTrue(); - dotnetDirAccessor.FileExists("kernel.json").Should().BeTrue(); - dotnetDirAccessor.FileExists("logo-32x32.png").Should().BeTrue(); - dotnetDirAccessor.FileExists("logo-64x64.png").Should().BeTrue(); + var installedKernels = await jupyterPathsHelper.ExecuteCommand("-m jupyter kernelspec list"); + installedKernels.Output.Should().Contain(line => line.Contains(".net")); } } diff --git a/MLS.Agent/IJupyterPathsHelper.cs b/MLS.Agent/IJupyterPathsHelper.cs new file mode 100644 index 000000000..534ee1116 --- /dev/null +++ b/MLS.Agent/IJupyterPathsHelper.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using MLS.Agent.Tools; +using System.IO; +using System.Threading.Tasks; + +namespace MLS.Agent +{ + public interface IJupyterPathsHelper + { + Task ExecuteCommand(string command); + } +} \ No newline at end of file diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index 862221e38..ab2025b52 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -24,7 +24,7 @@ public class JupyterCommandLine public JupyterCommandLine(IConsole console, IJupyterPathsHelper jupyterPathsHelper) { - _pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\python.exe")); + _console = console; _jupyterPathsHelper = jupyterPathsHelper; } @@ -46,7 +46,7 @@ public async Task InvokeAsync() ZipFile.ExtractToDirectory(zipPath, disposableDirectory.Directory.FullName); - var result = await _jupyterPathsHelper.GetJupyterPaths(_pythonExeLocation, $"-m jupyter kernelspec install {disposableDirectory.Directory.Subdirectory("dotnetKernel").FullName}"); + var result = await _jupyterPathsHelper.ExecuteCommand($"-m jupyter kernelspec install {disposableDirectory.Directory.Subdirectory("dotnetKernel").FullName}"); if(result.ExitCode ==0) { @@ -62,23 +62,4 @@ public async Task InvokeAsync() } } } - - public interface IJupyterPathsHelper - { - IDirectoryAccessor GetDirectoryAccessorForPath(string v); - Task GetJupyterPaths(FileInfo fileInfo, string args); - } - - public class JupyterPathsHelper : IJupyterPathsHelper - { - public IDirectoryAccessor GetDirectoryAccessorForPath(string path) - { - return new FileSystemDirectoryAccessor(new DirectoryInfo(path)); - } - - public Task GetJupyterPaths(FileInfo fileInfo, string args) - { - return Tools.CommandLine.Execute(fileInfo, args); - } - } } \ No newline at end of file diff --git a/MLS.Agent/JupyterPathsHelper.cs b/MLS.Agent/JupyterPathsHelper.cs new file mode 100644 index 000000000..7d687e16c --- /dev/null +++ b/MLS.Agent/JupyterPathsHelper.cs @@ -0,0 +1,25 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using MLS.Agent.Tools; +using System.IO; +using System.Threading.Tasks; +using WorkspaceServer; + +namespace MLS.Agent +{ + public class JupyterPathsHelper : IJupyterPathsHelper + { + private FileInfo _pythonExeLocation; + + public JupyterPathsHelper() + { + _pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\python.exe")); + } + + public Task ExecuteCommand(string args) + { + return Tools.CommandLine.Execute(_pythonExeLocation, args); + } + } +} \ No newline at end of file diff --git a/MLS.Agent/MLS.Agent.csproj b/MLS.Agent/MLS.Agent.csproj index cebce1cb1..05cd9109d 100644 --- a/MLS.Agent/MLS.Agent.csproj +++ b/MLS.Agent/MLS.Agent.csproj @@ -121,9 +121,9 @@ demo.zip - - - + + dotnetKernel.zip + @@ -221,7 +221,7 @@ - + From d29acc59d0e4663fe16872c61492997e45585b22 Mon Sep 17 00:00:00 2001 From: Akshita Date: Wed, 31 Jul 2019 13:30:59 -0700 Subject: [PATCH 25/47] delete ununsed classes and rename --- MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs | 21 +++++++++ MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs | 47 ------------------- MLS.Agent.Tests/JupyterCommandLineTests.cs | 18 +++---- MLS.Agent/CommandLine/CommandLineParser.cs | 2 +- ...erPathsHelper.cs => IJupyterKernelSpec.cs} | 2 +- MLS.Agent/JupyterCommandLine.cs | 15 +++--- MLS.Agent/JupyterDataPathResult.cs | 27 ----------- ...terPathsHelper.cs => JupyterKernelSpec.cs} | 10 ++-- MLS.Agent/MLS.Agent.v3.ncrunchproject | 1 + 9 files changed, 45 insertions(+), 98 deletions(-) create mode 100644 MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs delete mode 100644 MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs rename MLS.Agent/{IJupyterPathsHelper.cs => IJupyterKernelSpec.cs} (89%) delete mode 100644 MLS.Agent/JupyterDataPathResult.cs rename MLS.Agent/{JupyterPathsHelper.cs => JupyterKernelSpec.cs} (54%) diff --git a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs new file mode 100644 index 000000000..eb31f9631 --- /dev/null +++ b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using MLS.Agent.Tools; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using WorkspaceServer; +using WorkspaceServer.Tests; + +namespace MLS.Agent.Tests +{ + public class InMemoryJupyterPathsHelper : IJupyterKernelSpec + { + public async Task ExecuteCommand(string args) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs b/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs deleted file mode 100644 index eebd28557..000000000 --- a/MLS.Agent.Tests/InMemoryJupyterPathsHelper.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using MLS.Agent.Tools; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using WorkspaceServer; -using WorkspaceServer.Tests; - -namespace MLS.Agent.Tests -{ - public class InMemoryJupyterPathsHelper : IJupyterPathsHelper - { - private CommandLineResult _commandLineResult; - private Dictionary _dataDirectories; - - public InMemoryJupyterPathsHelper(CommandLineResult commandLineResult) - { - _commandLineResult = commandLineResult; - } - - public InMemoryJupyterPathsHelper(string dataDirectory) - { - var pathsOutput = -$@"config: - C:\Users\.jupyter -data: - {dataDirectory} -runtime: - C:\Users\AppData\Roaming\jupyter\runtime".Split("\n"); - - _commandLineResult = new CommandLineResult(0, pathsOutput); - var directoryAccessor = new InMemoryDirectoryAccessor(new DirectoryInfo(dataDirectory)); - directoryAccessor.EnsureRootDirectoryExists(); - _dataDirectories = new Dictionary - { - { dataDirectory, directoryAccessor } - }; - } - - public async Task ExecuteCommand(string args) - { - return _commandLineResult; - } - } -} \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index 23eb45d09..260140b53 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -17,14 +17,14 @@ namespace MLS.Agent.Tests { public abstract class JupyterCommandLineTests { - public abstract IJupyterPathsHelper GetJupyterPathsHelper(CommandLineResult commandLineResult); + public abstract IJupyterKernelSpec GetJupyterKernelSpec(CommandLineResult commandLineResult); [Fact] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); var commandLineResult = new CommandLineResult(1); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper(commandLineResult)); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(commandLineResult)); await jupyterCommandLine.InvokeAsync(); console.Error.ToString().Should().Contain(".NET kernel installation failed"); } @@ -34,7 +34,7 @@ public async Task Prints_to_console_when_kernel_installation_succeded() { var console = new TestConsole(); var commandLineResult = new CommandLineResult(0); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterPathsHelper(commandLineResult)); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(commandLineResult)); await jupyterCommandLine.InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } @@ -46,28 +46,28 @@ public async Task After_installation_kernelspec_list_gives_dotnet() var console = new TestConsole(); var commandLineResult = new CommandLineResult(0); - var jupyterPathsHelper = GetJupyterPathsHelper(commandLineResult); + var jupyterPathsHelper = GetJupyterKernelSpec(commandLineResult); var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); - var installedKernels = await jupyterPathsHelper.ExecuteCommand("-m jupyter kernelspec list"); + var installedKernels = await jupyterPathsHelper.ExecuteCommand("list"); installedKernels.Output.Should().Contain(line => line.Contains(".net")); } } public class JupyterCommandLineIntegrationTests: JupyterCommandLineTests { - public override IJupyterPathsHelper GetJupyterPathsHelper(CommandLineResult commandLineResult) + public override IJupyterKernelSpec GetJupyterKernelSpec(CommandLineResult commandLineResult) { - return new JupyterPathsHelper(); + return new JupyterKernelSpec(); } } public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests { - public override IJupyterPathsHelper GetJupyterPathsHelper(CommandLineResult commandLineResult) + public override IJupyterKernelSpec GetJupyterKernelSpec(CommandLineResult commandLineResult) { - return new InMemoryJupyterPathsHelper(commandLineResult); + throw new NotImplementedException(); } } } \ No newline at end of file diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index 8e664f542..142242fb7 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -395,7 +395,7 @@ Command Jupyter() var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); installCommand.Handler = CommandHandler.Create(async (console) => { - return await new JupyterCommandLine(console, new JupyterPathsHelper()).InvokeAsync(); + return await new JupyterCommandLine(console, new JupyterKernelSpec()).InvokeAsync(); }); jupyterCommand.AddCommand(installCommand); diff --git a/MLS.Agent/IJupyterPathsHelper.cs b/MLS.Agent/IJupyterKernelSpec.cs similarity index 89% rename from MLS.Agent/IJupyterPathsHelper.cs rename to MLS.Agent/IJupyterKernelSpec.cs index 534ee1116..0303f4da2 100644 --- a/MLS.Agent/IJupyterPathsHelper.cs +++ b/MLS.Agent/IJupyterKernelSpec.cs @@ -7,7 +7,7 @@ namespace MLS.Agent { - public interface IJupyterPathsHelper + public interface IJupyterKernelSpec { Task ExecuteCommand(string command); } diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index ab2025b52..9d076d9a4 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -18,13 +18,11 @@ namespace MLS.Agent { public class JupyterCommandLine { - private readonly FileInfo _pythonExeLocation; private readonly IConsole _console; - private readonly IJupyterPathsHelper _jupyterPathsHelper; + private readonly IJupyterKernelSpec _jupyterPathsHelper; - public JupyterCommandLine(IConsole console, IJupyterPathsHelper jupyterPathsHelper) + public JupyterCommandLine(IConsole console, IJupyterKernelSpec jupyterPathsHelper) { - _console = console; _jupyterPathsHelper = jupyterPathsHelper; } @@ -44,12 +42,13 @@ public async Task InvokeAsync() resourceStream.CopyTo(fileStream); } - ZipFile.ExtractToDirectory(zipPath, disposableDirectory.Directory.FullName); + var dotnetDirectory = disposableDirectory.Directory.CreateSubdirectory(".NET"); + ZipFile.ExtractToDirectory(zipPath, dotnetDirectory.FullName); - var result = await _jupyterPathsHelper.ExecuteCommand($"-m jupyter kernelspec install {disposableDirectory.Directory.Subdirectory("dotnetKernel").FullName}"); - - if(result.ExitCode ==0) + var result = await _jupyterPathsHelper.ExecuteCommand($"install {dotnetDirectory.FullName} --user"); + if (result.ExitCode == 0) { + _console.Out.WriteLine(string.Join('\n', result.Output)); _console.Out.WriteLine(".NET kernel installation succeded"); return 0; } diff --git a/MLS.Agent/JupyterDataPathResult.cs b/MLS.Agent/JupyterDataPathResult.cs deleted file mode 100644 index fb8b5012e..000000000 --- a/MLS.Agent/JupyterDataPathResult.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.IO; -using System.Linq; -using WorkspaceServer; - -namespace MLS.Agent -{ - public class JupyterDataPathResult - { - public JupyterDataPathResult(IEnumerable paths) - { - Paths = paths; - Error = ""; - } - - public JupyterDataPathResult(string error) - { - Error = error; - } - - public IEnumerable Paths { get; } - public string Error { get; } - } -} \ No newline at end of file diff --git a/MLS.Agent/JupyterPathsHelper.cs b/MLS.Agent/JupyterKernelSpec.cs similarity index 54% rename from MLS.Agent/JupyterPathsHelper.cs rename to MLS.Agent/JupyterKernelSpec.cs index 7d687e16c..2e2e5d892 100644 --- a/MLS.Agent/JupyterPathsHelper.cs +++ b/MLS.Agent/JupyterKernelSpec.cs @@ -8,18 +8,18 @@ namespace MLS.Agent { - public class JupyterPathsHelper : IJupyterPathsHelper + public class JupyterKernelSpec : IJupyterKernelSpec { - private FileInfo _pythonExeLocation; + private readonly FileInfo _jupyterKernelSpec; - public JupyterPathsHelper() + public JupyterKernelSpec() { - _pythonExeLocation = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\python.exe")); + _jupyterKernelSpec = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\Scripts\jupyter-kernelspec.exe")); } public Task ExecuteCommand(string args) { - return Tools.CommandLine.Execute(_pythonExeLocation, args); + return Tools.CommandLine.Execute(_jupyterKernelSpec, args); } } } \ No newline at end of file diff --git a/MLS.Agent/MLS.Agent.v3.ncrunchproject b/MLS.Agent/MLS.Agent.v3.ncrunchproject index bec9489c9..a9a398b55 100644 --- a/MLS.Agent/MLS.Agent.v3.ncrunchproject +++ b/MLS.Agent/MLS.Agent.v3.ncrunchproject @@ -3,6 +3,7 @@ ..\docs\**.* wwwroot\**.* + ..\Microsoft.DotNet.Interactive.Jupyter\ContentFiles\**.* \ No newline at end of file From 0b930d56778510d97d3805f9591259445549036b Mon Sep 17 00:00:00 2001 From: Akshita Date: Wed, 31 Jul 2019 13:55:42 -0700 Subject: [PATCH 26/47] clean up and all inmemory tests are passing --- MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs | 40 +++++++++++++++++--- MLS.Agent.Tests/JupyterCommandLineTests.cs | 28 +++++--------- MLS.Agent/IJupyterKernelSpec.cs | 2 +- MLS.Agent/JupyterCommandLine.cs | 2 +- MLS.Agent/JupyterKernelSpec.cs | 4 +- 5 files changed, 49 insertions(+), 27 deletions(-) diff --git a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs index eb31f9631..a4aec4b56 100644 --- a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs +++ b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs @@ -3,18 +3,48 @@ using MLS.Agent.Tools; using System; -using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using WorkspaceServer; -using WorkspaceServer.Tests; namespace MLS.Agent.Tests { - public class InMemoryJupyterPathsHelper : IJupyterKernelSpec + public class InMemoryJupyterKernelSpec : IJupyterKernelSpec { - public async Task ExecuteCommand(string args) + private CommandLineResult installResult; + private CommandLineResult listResult; + + public InMemoryJupyterKernelSpec(DirectoryInfo installationDirectory) { + if(installationDirectory!=null) + { + var installOutput = +$@"[InstallKernelSpec] Installed kernelspec .net in {installationDirectory.FullName}".Split("\n"); + installResult = new CommandLineResult(0, installOutput); + + var listOutput = +$@"Available kernels: +.net {installationDirectory.FullName}".Split("\n"); + listResult = new CommandLineResult(0, listOutput); + } + else + { + installResult = new CommandLineResult(1); + listResult = new CommandLineResult(1); + } + } + + public async Task ExecuteCommand(string command, string args) + { + if(command == "install") + { + return installResult; + } + + else if(command =="list") + { + return listResult; + } + throw new NotImplementedException(); } } diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index 260140b53..ac01c9a14 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -2,29 +2,22 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using FluentAssertions; -using Microsoft.DotNet.Try.Markdown; -using MLS.Agent.Tools; -using System; using System.CommandLine; using System.IO; -using System.Linq; using System.Threading.Tasks; -using WorkspaceServer; using Xunit; -using static MLS.Agent.JupyterCommandLine; namespace MLS.Agent.Tests { public abstract class JupyterCommandLineTests { - public abstract IJupyterKernelSpec GetJupyterKernelSpec(CommandLineResult commandLineResult); + public abstract IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo installationDirectory); [Fact] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); - var commandLineResult = new CommandLineResult(1); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(commandLineResult)); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(null)); await jupyterCommandLine.InvokeAsync(); console.Error.ToString().Should().Contain(".NET kernel installation failed"); } @@ -33,8 +26,8 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() public async Task Prints_to_console_when_kernel_installation_succeded() { var console = new TestConsole(); - var commandLineResult = new CommandLineResult(0); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(commandLineResult)); + var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); + var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(directory)); await jupyterCommandLine.InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } @@ -42,11 +35,10 @@ public async Task Prints_to_console_when_kernel_installation_succeded() [Fact] public async Task After_installation_kernelspec_list_gives_dotnet() { - var dataDirectory = Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\share\jupyter"); - var console = new TestConsole(); - var commandLineResult = new CommandLineResult(0); - var jupyterPathsHelper = GetJupyterKernelSpec(commandLineResult); + var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); + + var jupyterPathsHelper = GetJupyterKernelSpec(directory); var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); @@ -57,7 +49,7 @@ public async Task After_installation_kernelspec_list_gives_dotnet() public class JupyterCommandLineIntegrationTests: JupyterCommandLineTests { - public override IJupyterKernelSpec GetJupyterKernelSpec(CommandLineResult commandLineResult) + public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) { return new JupyterKernelSpec(); } @@ -65,9 +57,9 @@ public override IJupyterKernelSpec GetJupyterKernelSpec(CommandLineResult comman public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests { - public override IJupyterKernelSpec GetJupyterKernelSpec(CommandLineResult commandLineResult) + public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) { - throw new NotImplementedException(); + return new InMemoryJupyterKernelSpec(dir); } } } \ No newline at end of file diff --git a/MLS.Agent/IJupyterKernelSpec.cs b/MLS.Agent/IJupyterKernelSpec.cs index 0303f4da2..291d573d8 100644 --- a/MLS.Agent/IJupyterKernelSpec.cs +++ b/MLS.Agent/IJupyterKernelSpec.cs @@ -9,6 +9,6 @@ namespace MLS.Agent { public interface IJupyterKernelSpec { - Task ExecuteCommand(string command); + Task ExecuteCommand(string command, string args=""); } } \ No newline at end of file diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index 9d076d9a4..d30e5f8e9 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -45,7 +45,7 @@ public async Task InvokeAsync() var dotnetDirectory = disposableDirectory.Directory.CreateSubdirectory(".NET"); ZipFile.ExtractToDirectory(zipPath, dotnetDirectory.FullName); - var result = await _jupyterPathsHelper.ExecuteCommand($"install {dotnetDirectory.FullName} --user"); + var result = await _jupyterPathsHelper.ExecuteCommand("install", $"{dotnetDirectory.FullName} --user"); if (result.ExitCode == 0) { _console.Out.WriteLine(string.Join('\n', result.Output)); diff --git a/MLS.Agent/JupyterKernelSpec.cs b/MLS.Agent/JupyterKernelSpec.cs index 2e2e5d892..3b5d71609 100644 --- a/MLS.Agent/JupyterKernelSpec.cs +++ b/MLS.Agent/JupyterKernelSpec.cs @@ -17,9 +17,9 @@ public JupyterKernelSpec() _jupyterKernelSpec = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\Scripts\jupyter-kernelspec.exe")); } - public Task ExecuteCommand(string args) + public Task ExecuteCommand(string command, string args="") { - return Tools.CommandLine.Execute(_jupyterKernelSpec, args); + return Tools.CommandLine.Execute(_jupyterKernelSpec, $"{command} {args}"); } } } \ No newline at end of file From b464aedd62bf83ddcfab93838e0a2da32ec6bd27 Mon Sep 17 00:00:00 2001 From: Akshita Date: Wed, 31 Jul 2019 15:40:34 -0700 Subject: [PATCH 27/47] clean up --- .../Markdown/DirectoryAccessorTests.cs | 1 - MLS.Agent.Tools/CommandLine.cs | 2 +- MLS.Agent/Markdown/MarkdownProject.cs | 1 + MLS.Agent/StringExtensions.cs | 1 - ...ft.DotNet.Interactive.Jupyter.Tests.csproj | 1 - .../JupyterCommandLine.cs | 24 ------------------- .../InMemoryDirectoryAccessor.cs | 1 - WorkspaceServer/DirectoryAccessor.cs | 6 ----- .../FileSystemDirectoryAccessor.cs | 9 ------- 9 files changed, 2 insertions(+), 44 deletions(-) delete mode 100644 Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs diff --git a/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs b/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs index 1e19cff54..128ff70e4 100644 --- a/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs +++ b/MLS.Agent.Tests/Markdown/DirectoryAccessorTests.cs @@ -3,7 +3,6 @@ using System; using System.IO; -using System.Linq; using System.Runtime.CompilerServices; using FluentAssertions; using Microsoft.DotNet.PlatformAbstractions; diff --git a/MLS.Agent.Tools/CommandLine.cs b/MLS.Agent.Tools/CommandLine.cs index 5ff7268bf..7a925eba3 100644 --- a/MLS.Agent.Tools/CommandLine.cs +++ b/MLS.Agent.Tools/CommandLine.cs @@ -20,7 +20,7 @@ public static Task Execute( FileInfo exePath, string args, DirectoryInfo workingDir = null, - Budget budget = null) => + Budget budget = null) => Execute(exePath.FullName, args, workingDir, diff --git a/MLS.Agent/Markdown/MarkdownProject.cs b/MLS.Agent/Markdown/MarkdownProject.cs index deea1c935..74c0b16e9 100644 --- a/MLS.Agent/Markdown/MarkdownProject.cs +++ b/MLS.Agent/Markdown/MarkdownProject.cs @@ -72,6 +72,7 @@ public void WriteAllText(RelativeFilePath path, string text) { } } + internal IDirectoryAccessor DirectoryAccessor { get; } private readonly PackageRegistry _packageRegistry; diff --git a/MLS.Agent/StringExtensions.cs b/MLS.Agent/StringExtensions.cs index c9bb9ee17..1b3064551 100644 --- a/MLS.Agent/StringExtensions.cs +++ b/MLS.Agent/StringExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Globalization; using System.Web; using Microsoft.AspNetCore.Html; diff --git a/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj b/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj index d6cc90e35..28875454a 100644 --- a/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj +++ b/Microsoft.DotNet.Interactive.Jupyter.Tests/Microsoft.DotNet.Interactive.Jupyter.Tests.csproj @@ -35,7 +35,6 @@ - diff --git a/Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs b/Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs deleted file mode 100644 index 18154ea93..000000000 --- a/Microsoft.DotNet.Try.Jupyter/JupyterCommandLine.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.CommandLine; -using System.Threading.Tasks; - -namespace Microsoft.DotNet.Try.Jupyter -{ - internal class JupyterCommandLine - { - private IConsole console; - - public JupyterCommandLine(IConsole console) - { - this.console = console; - } - - internal Task InvokeAsync() - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs index 712fffd91..41836df8c 100644 --- a/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs +++ b/WorkspaceServer.Tests/InMemoryDirectoryAccessor.cs @@ -144,7 +144,6 @@ public IEnumerator GetEnumerator() public IDirectoryAccessor GetDirectoryAccessorForRelativePath(RelativeDirectoryPath relativePath) { var newPath = WorkingDirectory.Combine(relativePath); - return new InMemoryDirectoryAccessor(newPath) { _files = _files diff --git a/WorkspaceServer/DirectoryAccessor.cs b/WorkspaceServer/DirectoryAccessor.cs index b30a97599..e93241900 100644 --- a/WorkspaceServer/DirectoryAccessor.cs +++ b/WorkspaceServer/DirectoryAccessor.cs @@ -58,11 +58,5 @@ public static FileInfo GetFullyQualifiedFilePath(this IDirectoryAccessor directo public static FileInfo GetFullyQualifiedFilePath(this IDirectoryAccessor directoryAccessor, RelativeFilePath relativePath) => (FileInfo) directoryAccessor.GetFullyQualifiedPath(relativePath); - - public static bool RootDirectoryExists(this IDirectoryAccessor directoryAccessor) => - directoryAccessor.DirectoryExists("."); - - public static void EnsureRootDirectoryExists(this IDirectoryAccessor directoryAccessor) => - directoryAccessor.EnsureDirectoryExists("."); } } \ No newline at end of file diff --git a/WorkspaceServer/FileSystemDirectoryAccessor.cs b/WorkspaceServer/FileSystemDirectoryAccessor.cs index eb54b067a..db8ce597b 100644 --- a/WorkspaceServer/FileSystemDirectoryAccessor.cs +++ b/WorkspaceServer/FileSystemDirectoryAccessor.cs @@ -103,14 +103,5 @@ public IEnumerable GetAllFiles() } public override string ToString() => _rootDirectory.FullName; - - public void CopyFileFromDirectory(IDirectoryAccessor directoryAccessor, string filename, bool overwrite) - { - var file= directoryAccessor.GetAllFiles().FirstOrDefault(file => file.FileName == filename); - if(file!=null) - { - File.Copy(directoryAccessor.GetFullyQualifiedFilePath(file.FileName).FullName, GetFullyQualifiedPath( new RelativeFilePath(filename)).FullName, overwrite); - } - } } } From 01c0e9e4aa4d9ae17e161c66ca433859d04f0001 Mon Sep 17 00:00:00 2001 From: Akshita Date: Wed, 31 Jul 2019 16:24:59 -0700 Subject: [PATCH 28/47] added a fact attribute --- .../FactSkippedForIntegrationAttribute.cs | 50 +++++++++++++++++++ MLS.Agent.Tests/JupyterCommandLineTests.cs | 6 ++- MLS.Agent/JupyterKernelSpec.cs | 2 +- WorkspaceServer/Paths.cs | 3 ++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs diff --git a/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs b/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs new file mode 100644 index 000000000..d40ee8d16 --- /dev/null +++ b/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs @@ -0,0 +1,50 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.IO; +using WorkspaceServer; +using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace MLS.Agent.Tests +{ + [XunitTestCaseDiscoverer("MLS.Agent.Tests.TestCaseDiscoverer", "MLS.Agent.Tests")] + public class FactSkippedForIntegrationAttribute : FactAttribute + { + } + + public class TestCaseDiscoverer : IXunitTestCaseDiscoverer + { + private readonly IMessageSink messageSink; + + public TestCaseDiscoverer(IMessageSink messageSink) + { + this.messageSink = messageSink; + } + + public IEnumerable Discover( + ITestFrameworkDiscoveryOptions discoveryOptions, + ITestMethod testMethod, + IAttributeInfo factAttribute) + { + if (!File.Exists(Paths.JupyterKernelSpecPath)) + { + yield break; + } + + yield return new XunitTestCase( + messageSink, + TestMethodDisplay.ClassAndMethod, + new TestMethodDisplayOptions(), + testMethod + ); + } + + public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index ac01c9a14..04ddaa691 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -2,10 +2,14 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using FluentAssertions; +using System.Collections.Generic; using System.CommandLine; using System.IO; using System.Threading.Tasks; +using WorkspaceServer; using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; namespace MLS.Agent.Tests { @@ -13,7 +17,7 @@ public abstract class JupyterCommandLineTests { public abstract IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo installationDirectory); - [Fact] + [FactSkippedForIntegration] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); diff --git a/MLS.Agent/JupyterKernelSpec.cs b/MLS.Agent/JupyterKernelSpec.cs index 3b5d71609..06f78f364 100644 --- a/MLS.Agent/JupyterKernelSpec.cs +++ b/MLS.Agent/JupyterKernelSpec.cs @@ -14,7 +14,7 @@ public class JupyterKernelSpec : IJupyterKernelSpec public JupyterKernelSpec() { - _jupyterKernelSpec = new FileInfo(Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\Scripts\jupyter-kernelspec.exe")); + _jupyterKernelSpec = new FileInfo(Paths.JupyterKernelSpecPath); } public Task ExecuteCommand(string command, string args="") diff --git a/WorkspaceServer/Paths.cs b/WorkspaceServer/Paths.cs index 27030de94..77b6b8699 100644 --- a/WorkspaceServer/Paths.cs +++ b/WorkspaceServer/Paths.cs @@ -24,6 +24,8 @@ static Paths() NugetCache = String.IsNullOrWhiteSpace(nugetPackagesEnvironmentVariable) ? Path.Combine(UserProfile, ".nuget", "packages") : nugetPackagesEnvironmentVariable; + + JupyterKernelSpecPath = Path.Combine(UserProfile, @"AppData\Local\Continuum\anaconda3\Scripts\jupyter-kernelspec.exe"); } public static string DotnetToolsPath { get; } @@ -31,6 +33,7 @@ static Paths() public static string UserProfile { get; } public static string NugetCache { get; } + public static string JupyterKernelSpecPath { get; } public static string ExecutableName(this string withoutExtension) => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) From 1aaa80c2b9770acb977c618513bbb58f1e3ff874 Mon Sep 17 00:00:00 2001 From: Akshita Date: Wed, 31 Jul 2019 17:53:36 -0700 Subject: [PATCH 29/47] add list install --- .../FactSkippedForIntegrationAttribute.cs | 5 --- MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs | 37 ++++--------------- MLS.Agent.Tests/JupyterCommandLineTests.cs | 4 +- MLS.Agent/IJupyterKernelSpec.cs | 4 +- MLS.Agent/JupyterCommandLine.cs | 8 ++-- MLS.Agent/JupyterKernelSpec.cs | 33 +++++++++++++++-- 6 files changed, 45 insertions(+), 46 deletions(-) diff --git a/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs b/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs index d40ee8d16..b5ab39bab 100644 --- a/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs +++ b/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs @@ -41,10 +41,5 @@ public IEnumerable Discover( testMethod ); } - - public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) - { - throw new System.NotImplementedException(); - } } } \ No newline at end of file diff --git a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs index a4aec4b56..bbc9014ab 100644 --- a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs +++ b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs @@ -3,6 +3,7 @@ using MLS.Agent.Tools; using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -10,41 +11,17 @@ namespace MLS.Agent.Tests { public class InMemoryJupyterKernelSpec : IJupyterKernelSpec { - private CommandLineResult installResult; - private CommandLineResult listResult; - - public InMemoryJupyterKernelSpec(DirectoryInfo installationDirectory) + public InMemoryJupyterKernelSpec(bool successfulInstall) { - if(installationDirectory!=null) - { - var installOutput = -$@"[InstallKernelSpec] Installed kernelspec .net in {installationDirectory.FullName}".Split("\n"); - installResult = new CommandLineResult(0, installOutput); - - var listOutput = -$@"Available kernels: -.net {installationDirectory.FullName}".Split("\n"); - listResult = new CommandLineResult(0, listOutput); - } - else - { - installResult = new CommandLineResult(1); - listResult = new CommandLineResult(1); - } } - public async Task ExecuteCommand(string command, string args) + public Task InstallKernel(DirectoryInfo sourceDirectory) { - if(command == "install") - { - return installResult; - } - - else if(command =="list") - { - return listResult; - } + throw new NotImplementedException(); + } + public Task> ListInstalledKernels() + { throw new NotImplementedException(); } } diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index 04ddaa691..d8cf4d1b3 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -46,8 +46,8 @@ public async Task After_installation_kernelspec_list_gives_dotnet() var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); await jupyterCommandLine.InvokeAsync(); - var installedKernels = await jupyterPathsHelper.ExecuteCommand("list"); - installedKernels.Output.Should().Contain(line => line.Contains(".net")); + var installedKernels = await jupyterPathsHelper.ListInstalledKernels(); + installedKernels.Keys.Should().Contain(".net"); } } diff --git a/MLS.Agent/IJupyterKernelSpec.cs b/MLS.Agent/IJupyterKernelSpec.cs index 291d573d8..c40786322 100644 --- a/MLS.Agent/IJupyterKernelSpec.cs +++ b/MLS.Agent/IJupyterKernelSpec.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using MLS.Agent.Tools; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -9,6 +10,7 @@ namespace MLS.Agent { public interface IJupyterKernelSpec { - Task ExecuteCommand(string command, string args=""); + Task InstallKernel(DirectoryInfo sourceDirectory); + Task> ListInstalledKernels(); } } \ No newline at end of file diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index d30e5f8e9..c8296e4df 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -19,12 +19,12 @@ namespace MLS.Agent public class JupyterCommandLine { private readonly IConsole _console; - private readonly IJupyterKernelSpec _jupyterPathsHelper; + private readonly IJupyterKernelSpec _jupyterKernelSpec; - public JupyterCommandLine(IConsole console, IJupyterKernelSpec jupyterPathsHelper) + public JupyterCommandLine(IConsole console, IJupyterKernelSpec jupyterKernelSpec) { _console = console; - _jupyterPathsHelper = jupyterPathsHelper; + _jupyterKernelSpec = jupyterKernelSpec; } public async Task InvokeAsync() @@ -45,7 +45,7 @@ public async Task InvokeAsync() var dotnetDirectory = disposableDirectory.Directory.CreateSubdirectory(".NET"); ZipFile.ExtractToDirectory(zipPath, dotnetDirectory.FullName); - var result = await _jupyterPathsHelper.ExecuteCommand("install", $"{dotnetDirectory.FullName} --user"); + var result = await _jupyterKernelSpec.InstallKernel(dotnetDirectory); if (result.ExitCode == 0) { _console.Out.WriteLine(string.Join('\n', result.Output)); diff --git a/MLS.Agent/JupyterKernelSpec.cs b/MLS.Agent/JupyterKernelSpec.cs index 06f78f364..4ad4c1379 100644 --- a/MLS.Agent/JupyterKernelSpec.cs +++ b/MLS.Agent/JupyterKernelSpec.cs @@ -2,7 +2,11 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using MLS.Agent.Tools; +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using WorkspaceServer; @@ -10,16 +14,37 @@ namespace MLS.Agent { public class JupyterKernelSpec : IJupyterKernelSpec { - private readonly FileInfo _jupyterKernelSpec; + private readonly FileInfo _executableFile; public JupyterKernelSpec() { - _jupyterKernelSpec = new FileInfo(Paths.JupyterKernelSpecPath); + _executableFile = new FileInfo(Paths.JupyterKernelSpecPath); } - public Task ExecuteCommand(string command, string args="") + private Task ExecuteCommand(string command, string args = "") { - return Tools.CommandLine.Execute(_jupyterKernelSpec, $"{command} {args}"); + return Tools.CommandLine.Execute(_executableFile, $"{command} {args}"); + } + + public Task InstallKernel(DirectoryInfo sourceDirectory) + { + return ExecuteCommand($"install {sourceDirectory.FullName} --user"); + } + + public async Task> ListInstalledKernels() + { + var result = await ExecuteCommand("list"); + var installedKernels = new Dictionary(); + if (result.ExitCode == 0) + { + foreach (var line in result.Output.Skip(1).Where(s => !string.IsNullOrWhiteSpace(s))) + { + var bits = line.Split(new char[] { '\t', ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); + installedKernels.Add(bits[0], new DirectoryInfo(bits[1])); + } + } + + return installedKernels; } } } \ No newline at end of file From 6365501e1a9840a570492243e250a67587188cae Mon Sep 17 00:00:00 2001 From: Akshita Date: Wed, 31 Jul 2019 18:06:33 -0700 Subject: [PATCH 30/47] add inmemory kernel specs --- MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs | 19 +++++++-- MLS.Agent.Tests/JupyterCommandLineTests.cs | 45 ++++++++++---------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs index bbc9014ab..12f81b7a3 100644 --- a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs +++ b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs @@ -11,18 +11,29 @@ namespace MLS.Agent.Tests { public class InMemoryJupyterKernelSpec : IJupyterKernelSpec { + private bool _successfulInstall; + private Dictionary _installedKernels; + public InMemoryJupyterKernelSpec(bool successfulInstall) { + _successfulInstall = successfulInstall; + _installedKernels = new Dictionary(); } - public Task InstallKernel(DirectoryInfo sourceDirectory) + public async Task InstallKernel(DirectoryInfo sourceDirectory) { - throw new NotImplementedException(); + if(_successfulInstall) + { + _installedKernels.Add(".net", new DirectoryInfo(Directory.GetCurrentDirectory())); + return new CommandLineResult(0); + } + + return new CommandLineResult(1); } - public Task> ListInstalledKernels() + public async Task> ListInstalledKernels() { - throw new NotImplementedException(); + return _installedKernels; } } } \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index d8cf4d1b3..6c0ac60f5 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using FluentAssertions; +using Markdig.Syntax.Inlines; using System.Collections.Generic; using System.CommandLine; using System.IO; @@ -13,15 +14,13 @@ namespace MLS.Agent.Tests { - public abstract class JupyterCommandLineTests + public class JupyterCommandLineTests { - public abstract IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo installationDirectory); - - [FactSkippedForIntegration] + [Fact] public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() { var console = new TestConsole(); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(null)); + var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterKernelSpec(false)); await jupyterCommandLine.InvokeAsync(); console.Error.ToString().Should().Contain(".NET kernel installation failed"); } @@ -31,7 +30,7 @@ public async Task Prints_to_console_when_kernel_installation_succeded() { var console = new TestConsole(); var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - var jupyterCommandLine = new JupyterCommandLine(console, GetJupyterKernelSpec(directory)); + var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterKernelSpec(true)); await jupyterCommandLine.InvokeAsync(); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } @@ -42,28 +41,28 @@ public async Task After_installation_kernelspec_list_gives_dotnet() var console = new TestConsole(); var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - var jupyterPathsHelper = GetJupyterKernelSpec(directory); - var jupyterCommandLine = new JupyterCommandLine(console, jupyterPathsHelper); + var jupyterKernelSpec = new InMemoryJupyterKernelSpec(true); + var jupyterCommandLine = new JupyterCommandLine(console, jupyterKernelSpec); await jupyterCommandLine.InvokeAsync(); - var installedKernels = await jupyterPathsHelper.ListInstalledKernels(); + var installedKernels = await jupyterKernelSpec.ListInstalledKernels(); installedKernels.Keys.Should().Contain(".net"); } } - public class JupyterCommandLineIntegrationTests: JupyterCommandLineTests - { - public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) - { - return new JupyterKernelSpec(); - } - } + //public class JupyterCommandLineIntegrationTests: JupyterCommandLineTests + //{ + // public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) + // { + // return new JupyterKernelSpec(); + // } + //} - public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests - { - public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) - { - return new InMemoryJupyterKernelSpec(dir); - } - } + //public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests + //{ + // public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) + // { + // return new InMemoryJupyterKernelSpec(dir); + // } + //} } \ No newline at end of file From 3ad83f8a56f2b85e749829b7a3eadcc09e04cc7c Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 12:20:19 -0700 Subject: [PATCH 31/47] add test for the jupyter command line --- MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs | 18 ++--- MLS.Agent.Tests/JupyterCommandLineTests.cs | 32 +-------- MLS.Agent.Tests/JupyterKernelSpecTests.cs | 67 +++++++++++++++++++ MLS.Agent/CommandLine/CommandLineParser.cs | 2 +- ...Spec.cs => FileSystemJupyterKernelSpec.cs} | 10 +-- MLS.Agent/IJupyterKernelSpec.cs | 4 +- MLS.Agent/JupyterCommandLine.cs | 1 + 7 files changed, 87 insertions(+), 47 deletions(-) create mode 100644 MLS.Agent.Tests/JupyterKernelSpecTests.cs rename MLS.Agent/{JupyterKernelSpec.cs => FileSystemJupyterKernelSpec.cs} (85%) diff --git a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs index 12f81b7a3..fac189b40 100644 --- a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs +++ b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs @@ -3,8 +3,10 @@ using MLS.Agent.Tools; using System; +using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; namespace MLS.Agent.Tests @@ -20,20 +22,20 @@ public InMemoryJupyterKernelSpec(bool successfulInstall) _installedKernels = new Dictionary(); } - public async Task InstallKernel(DirectoryInfo sourceDirectory) + public Task ExecuteCommand(string command, string args = "") + { + throw new NotImplementedException(); + } + + public async Task InstallKernel(DirectoryInfo sourceDirectory, string args ="") { if(_successfulInstall) { - _installedKernels.Add(".net", new DirectoryInfo(Directory.GetCurrentDirectory())); - return new CommandLineResult(0); + var installPath = Path.Combine(Directory.GetCurrentDirectory(), sourceDirectory.Name.ToLower()); + return new CommandLineResult(0, "".Split("\n"), $"[InstallKernelSpec] Installed kernelspec {sourceDirectory.Name} in {installPath}".Split("\n")); } return new CommandLineResult(1); } - - public async Task> ListInstalledKernels() - { - return _installedKernels; - } } } \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index 6c0ac60f5..8e89cec2a 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -29,40 +29,10 @@ public async Task Returns_error_when_jupyter_paths_could_not_be_obtained() public async Task Prints_to_console_when_kernel_installation_succeded() { var console = new TestConsole(); - var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); var jupyterCommandLine = new JupyterCommandLine(console, new InMemoryJupyterKernelSpec(true)); await jupyterCommandLine.InvokeAsync(); + console.Out.ToString().Should().MatchEquivalentOf($"*[InstallKernelSpec] Installed kernelspec .net in *.net *"); console.Out.ToString().Should().Contain(".NET kernel installation succeded"); } - - [Fact] - public async Task After_installation_kernelspec_list_gives_dotnet() - { - var console = new TestConsole(); - var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); - - var jupyterKernelSpec = new InMemoryJupyterKernelSpec(true); - var jupyterCommandLine = new JupyterCommandLine(console, jupyterKernelSpec); - await jupyterCommandLine.InvokeAsync(); - - var installedKernels = await jupyterKernelSpec.ListInstalledKernels(); - installedKernels.Keys.Should().Contain(".net"); - } } - - //public class JupyterCommandLineIntegrationTests: JupyterCommandLineTests - //{ - // public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) - // { - // return new JupyterKernelSpec(); - // } - //} - - //public class InMemoryJupyterCommandLineTests : JupyterCommandLineTests - //{ - // public override IJupyterKernelSpec GetJupyterKernelSpec(DirectoryInfo dir) - // { - // return new InMemoryJupyterKernelSpec(dir); - // } - //} } \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterKernelSpecTests.cs b/MLS.Agent.Tests/JupyterKernelSpecTests.cs new file mode 100644 index 000000000..d9b8eaf2d --- /dev/null +++ b/MLS.Agent.Tests/JupyterKernelSpecTests.cs @@ -0,0 +1,67 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using WorkspaceServer.Tests; +using Xunit; + +namespace MLS.Agent.Tests +{ + public abstract class JupyterKernelSpecTests: IAsyncDisposable + { + protected List _installedKernels; + + public JupyterKernelSpecTests() + { + _installedKernels = new List(); + } + + public abstract IJupyterKernelSpec GetJupyterKernelSpec(); + + [Fact] + public async Task Returns_sucess_output_when_kernel_installation_succeded() + { + var kernelSpec = GetJupyterKernelSpec(); + var kernelDir = Create.EmptyWorkspace().Directory; + + var result = await kernelSpec.InstallKernel(kernelDir); + result.ExitCode.Should().Be(0); + _installedKernels.Add(kernelDir.Name.ToLower()); + + //The actual jupyter instance is returning the output in the error field + result.Error.First().Should().MatchEquivalentOf($"[InstallKernelSpec] Installed kernelspec {kernelDir.Name} in *{kernelDir.Name}"); + } + + + public async ValueTask DisposeAsync() + { + var kernelSpec = GetJupyterKernelSpec(); + foreach (var kernel in _installedKernels) + { + await kernelSpec.ExecuteCommand("uninstall", kernel); + } + } + } + + public class FileSystemJupyterKernelSpecTests : JupyterKernelSpecTests + { + + public override IJupyterKernelSpec GetJupyterKernelSpec() + { + return new FileSystemJupyterKernelSpec(); + } + } + + public class InMemoryJupyterKernelSpecTests : JupyterKernelSpecTests + { + public override IJupyterKernelSpec GetJupyterKernelSpec() + { + return new InMemoryJupyterKernelSpec(true); + } + } +} \ No newline at end of file diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index 142242fb7..05903e348 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -395,7 +395,7 @@ Command Jupyter() var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); installCommand.Handler = CommandHandler.Create(async (console) => { - return await new JupyterCommandLine(console, new JupyterKernelSpec()).InvokeAsync(); + return await new JupyterCommandLine(console, new FileSystemJupyterKernelSpec()).InvokeAsync(); }); jupyterCommand.AddCommand(installCommand); diff --git a/MLS.Agent/JupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs similarity index 85% rename from MLS.Agent/JupyterKernelSpec.cs rename to MLS.Agent/FileSystemJupyterKernelSpec.cs index 4ad4c1379..34f37f3ed 100644 --- a/MLS.Agent/JupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -12,23 +12,23 @@ namespace MLS.Agent { - public class JupyterKernelSpec : IJupyterKernelSpec + public class FileSystemJupyterKernelSpec : IJupyterKernelSpec { private readonly FileInfo _executableFile; - public JupyterKernelSpec() + public FileSystemJupyterKernelSpec() { _executableFile = new FileInfo(Paths.JupyterKernelSpecPath); } - private Task ExecuteCommand(string command, string args = "") + public Task ExecuteCommand(string command, string args = "") { return Tools.CommandLine.Execute(_executableFile, $"{command} {args}"); } - public Task InstallKernel(DirectoryInfo sourceDirectory) + public Task InstallKernel(DirectoryInfo sourceDirectory, string args="") { - return ExecuteCommand($"install {sourceDirectory.FullName} --user"); + return ExecuteCommand($"install {sourceDirectory.FullName} {args}"); } public async Task> ListInstalledKernels() diff --git a/MLS.Agent/IJupyterKernelSpec.cs b/MLS.Agent/IJupyterKernelSpec.cs index c40786322..a53a0cd16 100644 --- a/MLS.Agent/IJupyterKernelSpec.cs +++ b/MLS.Agent/IJupyterKernelSpec.cs @@ -10,7 +10,7 @@ namespace MLS.Agent { public interface IJupyterKernelSpec { - Task InstallKernel(DirectoryInfo sourceDirectory); - Task> ListInstalledKernels(); + Task ExecuteCommand(string command, string args=""); + Task InstallKernel(DirectoryInfo sourceDirectory, string args=""); } } \ No newline at end of file diff --git a/MLS.Agent/JupyterCommandLine.cs b/MLS.Agent/JupyterCommandLine.cs index c8296e4df..3d49fb94d 100644 --- a/MLS.Agent/JupyterCommandLine.cs +++ b/MLS.Agent/JupyterCommandLine.cs @@ -49,6 +49,7 @@ public async Task InvokeAsync() if (result.ExitCode == 0) { _console.Out.WriteLine(string.Join('\n', result.Output)); + _console.Out.WriteLine(string.Join('\n', result.Error)); _console.Out.WriteLine(".NET kernel installation succeded"); return 0; } From d374684cac878ff176ee0bc0f4dbbff48b8a997e Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 13:24:30 -0700 Subject: [PATCH 32/47] added the new fact attribues and all tests passing --- ...FactRunWhenJupyterIsInstalledAttribute.cs} | 10 ++--- ...ctRunWhenJupyterIsNotInstalledAttribute.cs | 45 +++++++++++++++++++ MLS.Agent.Tests/JupyterKernelSpecTests.cs | 26 +++++++---- 3 files changed, 68 insertions(+), 13 deletions(-) rename MLS.Agent.Tests/{FactSkippedForIntegrationAttribute.cs => FactRunWhenJupyterIsInstalledAttribute.cs} (68%) create mode 100644 MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs diff --git a/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs similarity index 68% rename from MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs rename to MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs index b5ab39bab..edefa8141 100644 --- a/MLS.Agent.Tests/FactSkippedForIntegrationAttribute.cs +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs @@ -10,16 +10,16 @@ namespace MLS.Agent.Tests { - [XunitTestCaseDiscoverer("MLS.Agent.Tests.TestCaseDiscoverer", "MLS.Agent.Tests")] - public class FactSkippedForIntegrationAttribute : FactAttribute + [XunitTestCaseDiscoverer("MLS.Agent.Tests.JupyterInstalledTestCaseDiscoverer", "MLS.Agent.Tests")] + public class FactRunWhenJupyterIsInstalledAttribute : FactAttribute { } - public class TestCaseDiscoverer : IXunitTestCaseDiscoverer + public class JupyterInstalledTestCaseDiscoverer : IXunitTestCaseDiscoverer { private readonly IMessageSink messageSink; - public TestCaseDiscoverer(IMessageSink messageSink) + public JupyterInstalledTestCaseDiscoverer(IMessageSink messageSink) { this.messageSink = messageSink; } @@ -29,7 +29,7 @@ public IEnumerable Discover( ITestMethod testMethod, IAttributeInfo factAttribute) { - if (!File.Exists(Paths.JupyterKernelSpecPath)) + if (testMethod.TestClass.Class.Name.Contains("Integration") && !File.Exists(Paths.JupyterKernelSpecPath)) { yield break; } diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs new file mode 100644 index 000000000..0d25b8880 --- /dev/null +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs @@ -0,0 +1,45 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.IO; +using WorkspaceServer; +using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace MLS.Agent.Tests +{ + [XunitTestCaseDiscoverer("MLS.Agent.Tests.JupyterNotInstalledTestCaseDiscover", "MLS.Agent.Tests")] + public class FactRunWhenJupyterIsNotInstalledAttribute : FactAttribute + { + } + + public class JupyterNotInstalledTestCaseDiscover : IXunitTestCaseDiscoverer + { + private readonly IMessageSink messageSink; + + public JupyterNotInstalledTestCaseDiscover(IMessageSink messageSink) + { + this.messageSink = messageSink; + } + + public IEnumerable Discover( + ITestFrameworkDiscoveryOptions discoveryOptions, + ITestMethod testMethod, + IAttributeInfo factAttribute) + { + if (testMethod.TestClass.Class.Name.Contains("Integration") && File.Exists(Paths.JupyterKernelSpecPath)) + { + yield break; + } + + yield return new XunitTestCase( + messageSink, + TestMethodDisplay.ClassAndMethod, + new TestMethodDisplayOptions(), + testMethod + ); + } + } +} \ No newline at end of file diff --git a/MLS.Agent.Tests/JupyterKernelSpecTests.cs b/MLS.Agent.Tests/JupyterKernelSpecTests.cs index d9b8eaf2d..d7b70708a 100644 --- a/MLS.Agent.Tests/JupyterKernelSpecTests.cs +++ b/MLS.Agent.Tests/JupyterKernelSpecTests.cs @@ -21,12 +21,12 @@ public JupyterKernelSpecTests() _installedKernels = new List(); } - public abstract IJupyterKernelSpec GetJupyterKernelSpec(); + public abstract IJupyterKernelSpec GetJupyterKernelSpec(bool success); - [Fact] + [FactRunWhenJupyterIsInstalled] public async Task Returns_sucess_output_when_kernel_installation_succeded() { - var kernelSpec = GetJupyterKernelSpec(); + var kernelSpec = GetJupyterKernelSpec(true); var kernelDir = Create.EmptyWorkspace().Directory; var result = await kernelSpec.InstallKernel(kernelDir); @@ -37,10 +37,20 @@ public async Task Returns_sucess_output_when_kernel_installation_succeded() result.Error.First().Should().MatchEquivalentOf($"[InstallKernelSpec] Installed kernelspec {kernelDir.Name} in *{kernelDir.Name}"); } + [FactRunWhenJupyterIsNotInstalled] + public async Task Returns_failure_when_kernel_installation_did_not_succeed() + { + var kernelSpec = GetJupyterKernelSpec(false); + var kernelDir = Create.EmptyWorkspace().Directory; + + var result = await kernelSpec.InstallKernel(kernelDir); + result.ExitCode.Should().Be(1); + } + public async ValueTask DisposeAsync() { - var kernelSpec = GetJupyterKernelSpec(); + var kernelSpec = GetJupyterKernelSpec(true); foreach (var kernel in _installedKernels) { await kernelSpec.ExecuteCommand("uninstall", kernel); @@ -48,10 +58,10 @@ public async ValueTask DisposeAsync() } } - public class FileSystemJupyterKernelSpecTests : JupyterKernelSpecTests + public class FileSystemJupyterKernelSpecIntegrationTests : JupyterKernelSpecTests { - public override IJupyterKernelSpec GetJupyterKernelSpec() + public override IJupyterKernelSpec GetJupyterKernelSpec(bool success) { return new FileSystemJupyterKernelSpec(); } @@ -59,9 +69,9 @@ public override IJupyterKernelSpec GetJupyterKernelSpec() public class InMemoryJupyterKernelSpecTests : JupyterKernelSpecTests { - public override IJupyterKernelSpec GetJupyterKernelSpec() + public override IJupyterKernelSpec GetJupyterKernelSpec(bool success) { - return new InMemoryJupyterKernelSpec(true); + return new InMemoryJupyterKernelSpec(success); } } } \ No newline at end of file From 282b5f6bfd73993ff38623184df94965394e0084 Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 13:33:27 -0700 Subject: [PATCH 33/47] add the thing so that it gives error when the file is not found --- MLS.Agent.Tests/JupyterKernelSpecTests.cs | 2 +- MLS.Agent/FileSystemJupyterKernelSpec.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/MLS.Agent.Tests/JupyterKernelSpecTests.cs b/MLS.Agent.Tests/JupyterKernelSpecTests.cs index d7b70708a..5245d1230 100644 --- a/MLS.Agent.Tests/JupyterKernelSpecTests.cs +++ b/MLS.Agent.Tests/JupyterKernelSpecTests.cs @@ -17,7 +17,7 @@ public abstract class JupyterKernelSpecTests: IAsyncDisposable protected List _installedKernels; public JupyterKernelSpecTests() - { + { _installedKernels = new List(); } diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index 34f37f3ed..baa18ecee 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -21,9 +21,14 @@ public FileSystemJupyterKernelSpec() _executableFile = new FileInfo(Paths.JupyterKernelSpecPath); } - public Task ExecuteCommand(string command, string args = "") + public async Task ExecuteCommand(string command, string args = "") { - return Tools.CommandLine.Execute(_executableFile, $"{command} {args}"); + if(!_executableFile.Exists) + { + return new CommandLineResult(1, error: new List { $"Could not find the file: {_executableFile.FullName}" }); + } + + return await Tools.CommandLine.Execute(_executableFile, $"{command} {args}"); } public Task InstallKernel(DirectoryInfo sourceDirectory, string args="") From 1209a750faf1dc8fb0fb7cf83c3aaf72c5d3d372 Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 13:34:14 -0700 Subject: [PATCH 34/47] clean up --- MLS.Agent.Tests/JupyterCommandLineTests.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MLS.Agent.Tests/JupyterCommandLineTests.cs b/MLS.Agent.Tests/JupyterCommandLineTests.cs index 8e89cec2a..ad4637460 100644 --- a/MLS.Agent.Tests/JupyterCommandLineTests.cs +++ b/MLS.Agent.Tests/JupyterCommandLineTests.cs @@ -2,15 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using FluentAssertions; -using Markdig.Syntax.Inlines; -using System.Collections.Generic; using System.CommandLine; -using System.IO; using System.Threading.Tasks; -using WorkspaceServer; using Xunit; -using Xunit.Abstractions; -using Xunit.Sdk; namespace MLS.Agent.Tests { From 1c40d0a64f6595f6952979c45fbdef6ff28eaa5e Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 13:40:12 -0700 Subject: [PATCH 35/47] clean up --- .../FactRunWhenJupyterIsInstalledAttribute.cs | 2 +- .../FactRunWhenJupyterIsNotInstalledAttribute.cs | 2 +- MLS.Agent/FileSystemJupyterKernelSpec.cs | 13 ++++--------- WorkspaceServer/Paths.cs | 3 --- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs index edefa8141..2af01b759 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs @@ -29,7 +29,7 @@ public IEnumerable Discover( ITestMethod testMethod, IAttributeInfo factAttribute) { - if (testMethod.TestClass.Class.Name.Contains("Integration") && !File.Exists(Paths.JupyterKernelSpecPath)) + if (testMethod.TestClass.Class.Name.Contains("Integration") && !File.Exists(FileSystemJupyterKernelSpec.JupyterKernelSpecPath)) { yield break; } diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs index 0d25b8880..eb5cc77db 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs @@ -29,7 +29,7 @@ public IEnumerable Discover( ITestMethod testMethod, IAttributeInfo factAttribute) { - if (testMethod.TestClass.Class.Name.Contains("Integration") && File.Exists(Paths.JupyterKernelSpecPath)) + if (testMethod.TestClass.Class.Name.Contains("Integration") && File.Exists(FileSystemJupyterKernelSpec.JupyterKernelSpecPath)) { yield break; } diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index baa18ecee..33e448d7e 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -14,21 +14,16 @@ namespace MLS.Agent { public class FileSystemJupyterKernelSpec : IJupyterKernelSpec { - private readonly FileInfo _executableFile; - - public FileSystemJupyterKernelSpec() - { - _executableFile = new FileInfo(Paths.JupyterKernelSpecPath); - } + public static string JupyterKernelSpecPath = Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\Scripts\jupyter-kernelspec.exe"); public async Task ExecuteCommand(string command, string args = "") { - if(!_executableFile.Exists) + if(File.Exists(JupyterKernelSpecPath)) { - return new CommandLineResult(1, error: new List { $"Could not find the file: {_executableFile.FullName}" }); + return new CommandLineResult(1, error: new List { $"Could not find the file: {JupyterKernelSpecPath}" }); } - return await Tools.CommandLine.Execute(_executableFile, $"{command} {args}"); + return await Tools.CommandLine.Execute(JupyterKernelSpecPath, $"{command} {args}"); } public Task InstallKernel(DirectoryInfo sourceDirectory, string args="") diff --git a/WorkspaceServer/Paths.cs b/WorkspaceServer/Paths.cs index 77b6b8699..27030de94 100644 --- a/WorkspaceServer/Paths.cs +++ b/WorkspaceServer/Paths.cs @@ -24,8 +24,6 @@ static Paths() NugetCache = String.IsNullOrWhiteSpace(nugetPackagesEnvironmentVariable) ? Path.Combine(UserProfile, ".nuget", "packages") : nugetPackagesEnvironmentVariable; - - JupyterKernelSpecPath = Path.Combine(UserProfile, @"AppData\Local\Continuum\anaconda3\Scripts\jupyter-kernelspec.exe"); } public static string DotnetToolsPath { get; } @@ -33,7 +31,6 @@ static Paths() public static string UserProfile { get; } public static string NugetCache { get; } - public static string JupyterKernelSpecPath { get; } public static string ExecutableName(this string withoutExtension) => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) From ec002a296a5e9dbf23d8e9fc268707ee6f31b61c Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 14:06:40 -0700 Subject: [PATCH 36/47] do not use the path, use the command directly --- .../FactRunWhenJupyterIsInstalledAttribute.cs | 2 +- ...ctRunWhenJupyterIsNotInstalledAttribute.cs | 2 +- MLS.Agent/FileSystemJupyterKernelSpec.cs | 30 +++++-------------- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs index 2af01b759..32b190e06 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs @@ -29,7 +29,7 @@ public IEnumerable Discover( ITestMethod testMethod, IAttributeInfo factAttribute) { - if (testMethod.TestClass.Class.Name.Contains("Integration") && !File.Exists(FileSystemJupyterKernelSpec.JupyterKernelSpecPath)) + if (testMethod.TestClass.Class.Name.Contains("Integration") && !FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists().Result) { yield break; } diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs index eb5cc77db..e23a55f23 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs @@ -29,7 +29,7 @@ public IEnumerable Discover( ITestMethod testMethod, IAttributeInfo factAttribute) { - if (testMethod.TestClass.Class.Name.Contains("Integration") && File.Exists(FileSystemJupyterKernelSpec.JupyterKernelSpecPath)) + if (testMethod.TestClass.Class.Name.Contains("Integration") && FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists().Result) { yield break; } diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index 33e448d7e..c7c722358 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -2,28 +2,22 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using MLS.Agent.Tools; -using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using WorkspaceServer; namespace MLS.Agent { public class FileSystemJupyterKernelSpec : IJupyterKernelSpec { - public static string JupyterKernelSpecPath = Path.Combine(Paths.UserProfile, @"AppData\Local\Continuum\anaconda3\Scripts\jupyter-kernelspec.exe"); - public async Task ExecuteCommand(string command, string args = "") { - if(File.Exists(JupyterKernelSpecPath)) + if (!await CheckIfJupyterKernelSpecExists()) { - return new CommandLineResult(1, error: new List { $"Could not find the file: {JupyterKernelSpecPath}" }); + return new CommandLineResult(1, new List() { "Could not find jupyter kernelspec module" }); } - return await Tools.CommandLine.Execute(JupyterKernelSpecPath, $"{command} {args}"); + return await Tools.CommandLine.Execute("jupyter kernelspec", $"{command} {args}"); } public Task InstallKernel(DirectoryInfo sourceDirectory, string args="") @@ -31,20 +25,10 @@ public Task InstallKernel(DirectoryInfo sourceDirectory, stri return ExecuteCommand($"install {sourceDirectory.FullName} {args}"); } - public async Task> ListInstalledKernels() + public static async Task CheckIfJupyterKernelSpecExists() { - var result = await ExecuteCommand("list"); - var installedKernels = new Dictionary(); - if (result.ExitCode == 0) - { - foreach (var line in result.Output.Skip(1).Where(s => !string.IsNullOrWhiteSpace(s))) - { - var bits = line.Split(new char[] { '\t', ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); - installedKernels.Add(bits[0], new DirectoryInfo(bits[1])); - } - } - - return installedKernels; + var checkJupyterInstall = await Tools.CommandLine.Execute("where", "jupyter-kernelspec"); + return checkJupyterInstall.ExitCode == 0; } } -} \ No newline at end of file +} From 8f77b9584df03328c18e1a1c41fd11c56c0561e3 Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 14:08:32 -0700 Subject: [PATCH 37/47] clean up --- MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs | 4 ++-- MLS.Agent/FileSystemJupyterKernelSpec.cs | 4 ++-- MLS.Agent/IJupyterKernelSpec.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs index fac189b40..bd8267ebf 100644 --- a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs +++ b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs @@ -27,12 +27,12 @@ public Task ExecuteCommand(string command, string args = "") throw new NotImplementedException(); } - public async Task InstallKernel(DirectoryInfo sourceDirectory, string args ="") + public async Task InstallKernel(DirectoryInfo sourceDirectory) { if(_successfulInstall) { var installPath = Path.Combine(Directory.GetCurrentDirectory(), sourceDirectory.Name.ToLower()); - return new CommandLineResult(0, "".Split("\n"), $"[InstallKernelSpec] Installed kernelspec {sourceDirectory.Name} in {installPath}".Split("\n")); + return new CommandLineResult(0, error: new List { $"[InstallKernelSpec] Installed kernelspec {sourceDirectory.Name} in {installPath}" }); } return new CommandLineResult(1); diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index c7c722358..912f5b647 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -20,9 +20,9 @@ public async Task ExecuteCommand(string command, string args return await Tools.CommandLine.Execute("jupyter kernelspec", $"{command} {args}"); } - public Task InstallKernel(DirectoryInfo sourceDirectory, string args="") + public Task InstallKernel(DirectoryInfo sourceDirectory) { - return ExecuteCommand($"install {sourceDirectory.FullName} {args}"); + return ExecuteCommand($"install {sourceDirectory.FullName}"); } public static async Task CheckIfJupyterKernelSpecExists() diff --git a/MLS.Agent/IJupyterKernelSpec.cs b/MLS.Agent/IJupyterKernelSpec.cs index a53a0cd16..a25f92450 100644 --- a/MLS.Agent/IJupyterKernelSpec.cs +++ b/MLS.Agent/IJupyterKernelSpec.cs @@ -11,6 +11,6 @@ namespace MLS.Agent public interface IJupyterKernelSpec { Task ExecuteCommand(string command, string args=""); - Task InstallKernel(DirectoryInfo sourceDirectory, string args=""); + Task InstallKernel(DirectoryInfo sourceDirectory); } } \ No newline at end of file From 60c2e9f26105cfd0efe087117c003132add2decb Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 14:35:38 -0700 Subject: [PATCH 38/47] make the test pass --- MLS.Agent/FileSystemJupyterKernelSpec.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index 912f5b647..1cc3f069c 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -17,7 +17,7 @@ public async Task ExecuteCommand(string command, string args return new CommandLineResult(1, new List() { "Could not find jupyter kernelspec module" }); } - return await Tools.CommandLine.Execute("jupyter kernelspec", $"{command} {args}"); + return await Tools.CommandLine.Execute("jupyter", $"kernelspec {command} {args}"); } public Task InstallKernel(DirectoryInfo sourceDirectory) From ae474b85a67ebf412cf23efa3d65c6fa05bde19b Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 14:36:41 -0700 Subject: [PATCH 39/47] add comment --- MLS.Agent.Tests/JupyterKernelSpecTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MLS.Agent.Tests/JupyterKernelSpecTests.cs b/MLS.Agent.Tests/JupyterKernelSpecTests.cs index 5245d1230..f6b66e21b 100644 --- a/MLS.Agent.Tests/JupyterKernelSpecTests.cs +++ b/MLS.Agent.Tests/JupyterKernelSpecTests.cs @@ -26,6 +26,8 @@ public JupyterKernelSpecTests() [FactRunWhenJupyterIsInstalled] public async Task Returns_sucess_output_when_kernel_installation_succeded() { + //For real implementation run this test inside anaconda prompt or if jupyter is on path + var kernelSpec = GetJupyterKernelSpec(true); var kernelDir = Create.EmptyWorkspace().Directory; From 68aaff5b95902fa71082a4da96d241e35bc49f6b Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 15:29:46 -0700 Subject: [PATCH 40/47] remove async --- MLS.Agent/CommandLine/CommandLineParser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index 05903e348..c593e2fdd 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -393,9 +393,9 @@ Command Jupyter() }); var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); - installCommand.Handler = CommandHandler.Create(async (console) => + installCommand.Handler = CommandHandler.Create((console) => { - return await new JupyterCommandLine(console, new FileSystemJupyterKernelSpec()).InvokeAsync(); + return new JupyterCommandLine(console, new FileSystemJupyterKernelSpec()).InvokeAsync(); }); jupyterCommand.AddCommand(installCommand); From a19f7a6005e0eebb5716c42b0cfe24571dfe6147 Mon Sep 17 00:00:00 2001 From: Akshita Date: Thu, 1 Aug 2019 16:00:56 -0700 Subject: [PATCH 41/47] make connection file optional and clean up --- MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs | 2 -- MLS.Agent/CommandLine/CommandLineParser.cs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs index bd8267ebf..67ccadebe 100644 --- a/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs +++ b/MLS.Agent.Tests/InMemoryJupyterKernelSpec.cs @@ -14,12 +14,10 @@ namespace MLS.Agent.Tests public class InMemoryJupyterKernelSpec : IJupyterKernelSpec { private bool _successfulInstall; - private Dictionary _installedKernels; public InMemoryJupyterKernelSpec(bool successfulInstall) { _successfulInstall = successfulInstall; - _installedKernels = new Dictionary(); } public Task ExecuteCommand(string command, string args = "") diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs index c593e2fdd..e6be9b71d 100644 --- a/MLS.Agent/CommandLine/CommandLineParser.cs +++ b/MLS.Agent/CommandLine/CommandLineParser.cs @@ -360,7 +360,8 @@ Command Jupyter() }; var connectionFileArgument = new Argument { - Name = "ConnectionFile" + Name = "ConnectionFile", + Arity = ArgumentArity.ZeroOrOne //should be removed once the commandlineapi allows subcommands to not have arguments from the main command }.ExistingOnly(); jupyterCommand.AddArgument(connectionFileArgument); From b3b7e93cb2424a22c2045247610b640659a9ed67 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 2 Aug 2019 10:06:39 -0700 Subject: [PATCH 42/47] use which command to execute --- MLS.Agent/FileSystemJupyterKernelSpec.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index 1cc3f069c..19a6d4652 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -2,8 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using MLS.Agent.Tools; +using System; using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; using System.Threading.Tasks; namespace MLS.Agent @@ -27,7 +29,8 @@ public Task InstallKernel(DirectoryInfo sourceDirectory) public static async Task CheckIfJupyterKernelSpecExists() { - var checkJupyterInstall = await Tools.CommandLine.Execute("where", "jupyter-kernelspec"); + var command = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "where" : "which"; + var checkJupyterInstall = await Tools.CommandLine.Execute(command, "jupyter-kernelspec"); return checkJupyterInstall.ExitCode == 0; } } From bb7c461add9213d4a96951435a07d42c4f3f388a Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 2 Aug 2019 10:24:44 -0700 Subject: [PATCH 43/47] use Task.Run --- .../FactRunWhenJupyterIsInstalledAttribute.cs | 2 +- .../FactRunWhenJupyterIsNotInstalledAttribute.cs | 2 +- MLS.Agent/FileSystemJupyterKernelSpec.cs | 14 ++++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs index 32b190e06..4bd54b1f6 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs @@ -29,7 +29,7 @@ public IEnumerable Discover( ITestMethod testMethod, IAttributeInfo factAttribute) { - if (testMethod.TestClass.Class.Name.Contains("Integration") && !FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists().Result) + if (testMethod.TestClass.Class.Name.Contains("Integration") && !FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists()) { yield break; } diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs index e23a55f23..66a2cbee6 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs @@ -29,7 +29,7 @@ public IEnumerable Discover( ITestMethod testMethod, IAttributeInfo factAttribute) { - if (testMethod.TestClass.Class.Name.Contains("Integration") && FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists().Result) + if (testMethod.TestClass.Class.Name.Contains("Integration") && FileSystemJupyterKernelSpec.CheckIfJupyterKernelSpecExists()) { yield break; } diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index 19a6d4652..0334156cc 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -14,7 +14,7 @@ public class FileSystemJupyterKernelSpec : IJupyterKernelSpec { public async Task ExecuteCommand(string command, string args = "") { - if (!await CheckIfJupyterKernelSpecExists()) + if (!CheckIfJupyterKernelSpecExists()) { return new CommandLineResult(1, new List() { "Could not find jupyter kernelspec module" }); } @@ -27,11 +27,17 @@ public Task InstallKernel(DirectoryInfo sourceDirectory) return ExecuteCommand($"install {sourceDirectory.FullName}"); } - public static async Task CheckIfJupyterKernelSpecExists() + public static bool CheckIfJupyterKernelSpecExists() { var command = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "where" : "which"; - var checkJupyterInstall = await Tools.CommandLine.Execute(command, "jupyter-kernelspec"); - return checkJupyterInstall.ExitCode == 0; + bool jupyterKernelSpecExists = false ; + + Task.Run(async ()=> { + var result = await Tools.CommandLine.Execute(command, "jupyter-kernelspec"); + jupyterKernelSpecExists = result.ExitCode == 0; + }).Wait(); + + return jupyterKernelSpecExists; } } } From dc2101c58f9d5208c15356df3eba4222704eaa07 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 2 Aug 2019 10:33:55 -0700 Subject: [PATCH 44/47] add --user --- MLS.Agent/FileSystemJupyterKernelSpec.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index 0334156cc..a350983e3 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -24,7 +24,7 @@ public async Task ExecuteCommand(string command, string args public Task InstallKernel(DirectoryInfo sourceDirectory) { - return ExecuteCommand($"install {sourceDirectory.FullName}"); + return ExecuteCommand($"install {sourceDirectory.FullName}", "--user"); } public static bool CheckIfJupyterKernelSpecExists() From af00826d8bf537cc03e11a746ee51e98ad19bfdd Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 2 Aug 2019 11:17:05 -0700 Subject: [PATCH 45/47] skip the test --- MLS.Agent.Tests/CommandLine/CommandLineParserTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MLS.Agent.Tests/CommandLine/CommandLineParserTests.cs b/MLS.Agent.Tests/CommandLine/CommandLineParserTests.cs index 6e8ab05c3..440a297ba 100644 --- a/MLS.Agent.Tests/CommandLine/CommandLineParserTests.cs +++ b/MLS.Agent.Tests/CommandLine/CommandLineParserTests.cs @@ -383,7 +383,7 @@ public async Task jupyter_returns_error_if_connection_file_path_does_not_exits() testConsole.Error.ToString().Should().Contain("File does not exist: not_exist.json"); } - [Fact] + [Fact(Skip ="Skipped until System.CommandLine allows subcommands to skip the arguments from the main command")] public async Task jupyter_returns_error_if_connection_file_path_is_not_passed() { var testConsole = new TestConsole(); From b59b1f6ef661ef8516d591e0def31df306e63765 Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 2 Aug 2019 11:29:00 -0700 Subject: [PATCH 46/47] add timeout --- MLS.Agent/FileSystemJupyterKernelSpec.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MLS.Agent/FileSystemJupyterKernelSpec.cs b/MLS.Agent/FileSystemJupyterKernelSpec.cs index a350983e3..fc7e0bd9d 100644 --- a/MLS.Agent/FileSystemJupyterKernelSpec.cs +++ b/MLS.Agent/FileSystemJupyterKernelSpec.cs @@ -7,6 +7,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; +using Clockwise; namespace MLS.Agent { @@ -35,7 +36,7 @@ public static bool CheckIfJupyterKernelSpecExists() Task.Run(async ()=> { var result = await Tools.CommandLine.Execute(command, "jupyter-kernelspec"); jupyterKernelSpecExists = result.ExitCode == 0; - }).Wait(); + }).Wait(2000); return jupyterKernelSpecExists; } From 22b2318d344271cde0ab047f68b469971a3dbb1e Mon Sep 17 00:00:00 2001 From: Akshita Date: Fri, 2 Aug 2019 13:27:25 -0700 Subject: [PATCH 47/47] rename the classes and add comment --- ...ibute.cs => FactDependsOnJupyterNotOnPathAttribute.cs} | 2 +- ...ttribute.cs => FactDependsOnJupyterOnPathAttribute.cs} | 2 +- MLS.Agent.Tests/JupyterKernelSpecTests.cs | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) rename MLS.Agent.Tests/{FactRunWhenJupyterIsNotInstalledAttribute.cs => FactDependsOnJupyterNotOnPathAttribute.cs} (94%) rename MLS.Agent.Tests/{FactRunWhenJupyterIsInstalledAttribute.cs => FactDependsOnJupyterOnPathAttribute.cs} (94%) diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs b/MLS.Agent.Tests/FactDependsOnJupyterNotOnPathAttribute.cs similarity index 94% rename from MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs rename to MLS.Agent.Tests/FactDependsOnJupyterNotOnPathAttribute.cs index 66a2cbee6..21c68961e 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsNotInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactDependsOnJupyterNotOnPathAttribute.cs @@ -11,7 +11,7 @@ namespace MLS.Agent.Tests { [XunitTestCaseDiscoverer("MLS.Agent.Tests.JupyterNotInstalledTestCaseDiscover", "MLS.Agent.Tests")] - public class FactRunWhenJupyterIsNotInstalledAttribute : FactAttribute + public class FactDependsOnJupyterNotOnPathAttribute : FactAttribute { } diff --git a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs b/MLS.Agent.Tests/FactDependsOnJupyterOnPathAttribute.cs similarity index 94% rename from MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs rename to MLS.Agent.Tests/FactDependsOnJupyterOnPathAttribute.cs index 4bd54b1f6..1c7cc6ab2 100644 --- a/MLS.Agent.Tests/FactRunWhenJupyterIsInstalledAttribute.cs +++ b/MLS.Agent.Tests/FactDependsOnJupyterOnPathAttribute.cs @@ -11,7 +11,7 @@ namespace MLS.Agent.Tests { [XunitTestCaseDiscoverer("MLS.Agent.Tests.JupyterInstalledTestCaseDiscoverer", "MLS.Agent.Tests")] - public class FactRunWhenJupyterIsInstalledAttribute : FactAttribute + public class FactDependsOnJupyterOnPathAttribute : FactAttribute { } diff --git a/MLS.Agent.Tests/JupyterKernelSpecTests.cs b/MLS.Agent.Tests/JupyterKernelSpecTests.cs index f6b66e21b..004fd780f 100644 --- a/MLS.Agent.Tests/JupyterKernelSpecTests.cs +++ b/MLS.Agent.Tests/JupyterKernelSpecTests.cs @@ -23,10 +23,12 @@ public JupyterKernelSpecTests() public abstract IJupyterKernelSpec GetJupyterKernelSpec(bool success); - [FactRunWhenJupyterIsInstalled] + [FactDependsOnJupyterOnPath] public async Task Returns_sucess_output_when_kernel_installation_succeded() { - //For real implementation run this test inside anaconda prompt or if jupyter is on path + //For the FileSystemJupyterKernelSpec, this fact needs jupyter to be on the path + //To run this test for FileSystemJupyterKernelSpec open Visual Studio inside anaconda prompt or in a terminal with + //path containing the environment variables for jupyter var kernelSpec = GetJupyterKernelSpec(true); var kernelDir = Create.EmptyWorkspace().Directory; @@ -39,7 +41,7 @@ public async Task Returns_sucess_output_when_kernel_installation_succeded() result.Error.First().Should().MatchEquivalentOf($"[InstallKernelSpec] Installed kernelspec {kernelDir.Name} in *{kernelDir.Name}"); } - [FactRunWhenJupyterIsNotInstalled] + [FactDependsOnJupyterNotOnPath] public async Task Returns_failure_when_kernel_installation_did_not_succeed() { var kernelSpec = GetJupyterKernelSpec(false);