diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 855541357..0988307b9 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -22,18 +22,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestPackages", "TestPackage EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{89905EC4-BC0F-443B-8ADF-691321F10108}" ProjectSection(SolutionItems) = preProject + build\AppHostTemplate.proj = build\AppHostTemplate.proj build\AzureInfo.props = build\AzureInfo.props build\BackwardsCompatibilityRuntimes.props = build\BackwardsCompatibilityRuntimes.props build\BranchInfo.props = build\BranchInfo.props build\Branding.props = build\Branding.props build\BuildDefaults.props = build\BuildDefaults.props build\BuildInfo.targets = build\BuildInfo.targets + build\BundledDotnetTools.proj = build\BundledDotnetTools.proj + build\BundledDotnetTools.props = build\BundledDotnetTools.props build\BundledRuntimes.props = build\BundledRuntimes.props build\BundledSdks.props = build\BundledSdks.props build\BundledTemplates.proj = build\BundledTemplates.proj build\BundledTemplates.props = build\BundledTemplates.props build\BundledTools.props = build\BundledTools.props - build\BundledVersions.targets = build\BundledVersions.targets build\Compile.targets = build\Compile.targets build\CrossGen.props = build\CrossGen.props build\DependencyVersions.props = build\DependencyVersions.props diff --git a/TestAssets/TestProjects/TestAppSimple/TestAppSimple.csproj b/TestAssets/TestProjects/TestAppSimple/TestAppSimple.csproj index f99d38872..9c5f2a885 100755 --- a/TestAssets/TestProjects/TestAppSimple/TestAppSimple.csproj +++ b/TestAssets/TestProjects/TestAppSimple/TestAppSimple.csproj @@ -4,7 +4,5 @@ netcoreapp2.1 Exe - - true \ No newline at end of file diff --git a/build/AppHostTemplate.proj b/build/AppHostTemplate.proj new file mode 100644 index 000000000..598f250b6 --- /dev/null +++ b/build/AppHostTemplate.proj @@ -0,0 +1,49 @@ + + + + + + .exe + AppHost$(NativeExecutableExtension) + + + + + + + + + + + + + + + + + + + + + + --runtime $(Rid) + $(AppHostTemplateRestoreAdditionalParameters) /p:TargetFramework=$(CliTargetFramework) + $(AppHostTemplateRestoreAdditionalParameters) /p:TemplateFillInPackageName=$(TemplateFillInPackageName) + $(AppHostTemplateRestoreAdditionalParameters) /p:TemplateFillInPackageVersion=$(TemplateFillInPackageVersion) + $(AppHostTemplateRestoreAdditionalParameters) /p:RestorePackagesPath=$(AppHostIntermediateDirectory) + + + + + diff --git a/build/DependencyVersions.props b/build/DependencyVersions.props index cbb609c87..3acab50fa 100644 --- a/build/DependencyVersions.props +++ b/build/DependencyVersions.props @@ -4,12 +4,12 @@ 2.1.0-preview2-30475 2.1.0-preview3-26405-02 $(MicrosoftNETCoreAppPackageVersion) - 15.7.0-preview-000127 + 15.7.0-preview-000144 $(MicrosoftBuildPackageVersion) $(MicrosoftBuildPackageVersion) $(MicrosoftBuildPackageVersion) $(MicrosoftBuildPackageVersion) - 10.1.4-rtm-180213-0 + 10.1.4-rtm-180403-0 2.8.0-beta4-62805-01 $(MicrosoftCodeAnalysisCSharpPackageVersion) $(MicrosoftCodeAnalysisCSharpPackageVersion) @@ -17,25 +17,24 @@ 2.1.300-preview3-62804-06 $(MicrosoftNETSdkPackageVersion) $(MicrosoftAspNetCoreAppPackageVersion) - 2.1.300-preview2-20180306-1448279 + 2.1.300-preview2-20180403-1549509 $(MicrosoftNETSdkWebPackageVersion) $(MicrosoftNETSdkWebPackageVersion) - 1.0.1-beta3-20180104-1263555 + 1.0.2-beta3-20180403-1549505 $(MicrosoftDotNetCommonItemTemplatesPackageVersion) - 1.0.1-beta3-20180227-1423805 - 1.0.0-beta3-20171204-315 + 1.0.2-beta3-20180403-1549505 + 1.0.2-beta3-20180403-1549505 $(MicrosoftTemplateEngineCliPackageVersion) $(MicrosoftTemplateEngineCliPackageVersion) $(MicrosoftTemplateEngineCliPackageVersion) $(MicrosoftTemplateEngineCliPackageVersion) 2.1.0-preview3-26405-02 2.1.0-preview3-26405-02 - 0.1.1-alpha-174 - 1.2.1-alpha-002133 + 0.2.1-alpha-62803-03 + 1.3.1-alpha-62803-04 $(MicrosoftDotNetProjectJsonMigrationPackageVersion) 0.2.0-beta-62628-01 - 1.6.0-beta2-25304 - 4.7.0-preview3.5039 + 4.7.0-preview4.5065 $(NuGetBuildTasksPackageVersion) $(NuGetBuildTasksPackageVersion) $(NuGetBuildTasksPackageVersion) diff --git a/build/MSBuildExtensions.targets b/build/MSBuildExtensions.targets index 25d8db231..74401de5e 100644 --- a/build/MSBuildExtensions.targets +++ b/build/MSBuildExtensions.targets @@ -142,6 +142,11 @@ Copyright (c) .NET Foundation. All rights reserved. $(_NETCorePlatformsPackageVersion) $(SdkVersion) <_NETCoreSdkIsPreview>$(_NETCoreSdkIsPreview) + + + 1.0.10 + 1.1.7 + 2.0.6 ]]> diff --git a/build_projects/update-dependencies/Config.cs b/build_projects/update-dependencies/Config.cs index 88c47ee94..474d7a32a 100644 --- a/build_projects/update-dependencies/Config.cs +++ b/build_projects/update-dependencies/Config.cs @@ -5,6 +5,8 @@ using System; using System.IO; using System.Linq; using System.Xml.Linq; +using System.Collections; +using System.Collections.Generic; namespace Microsoft.DotNet.Scripts { @@ -38,9 +40,7 @@ namespace Microsoft.DotNet.Scripts private Lazy _password = new Lazy(() => GetEnvironmentVariable("GITHUB_PASSWORD")); private Lazy _dotNetVersionUrl = new Lazy(() => GetEnvironmentVariable("DOTNET_VERSION_URL", "https://raw.githubusercontent.com/dotnet/versions/master/build-info")); - private Lazy _coreSetupVersionFragment = new Lazy(() => GetEnvironmentVariable("CORESETUP_VERSION_FRAGMENT", GetDefaultCoreSetupVersionFragment())); - private Lazy _roslynVersionFragment = new Lazy(() => GetEnvironmentVariable("ROSLYN_VERSION_FRAGMENT")); private Lazy _gitHubUpstreamOwner = new Lazy(() => GetEnvironmentVariable("GITHUB_UPSTREAM_OWNER", "dotnet")); private Lazy _gitHubProject = new Lazy(() => GetEnvironmentVariable("GITHUB_PROJECT", "cli")); private Lazy _gitHubUpstreamBranch = new Lazy(() => GetEnvironmentVariable("GITHUB_UPSTREAM_BRANCH", GetDefaultUpstreamBranch())); @@ -48,6 +48,9 @@ namespace Microsoft.DotNet.Scripts GetEnvironmentVariable("GITHUB_PULL_REQUEST_NOTIFICATIONS", "") .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); + Lazy> _versionFragments = new Lazy>(() => + System.Environment.GetEnvironmentVariables().Cast().Where(entry => ((string)entry.Key).EndsWith("_VERSION_FRAGMENT")).ToDictionary(entry => + ((string)entry.Key).Replace("_VERSION_FRAGMENT","").ToLowerInvariant(), entry => (string)entry.Value, StringComparer.OrdinalIgnoreCase)); private Config() { } @@ -56,9 +59,8 @@ namespace Microsoft.DotNet.Scripts public string Email => _email.Value; public string Password => _password.Value; public string DotNetVersionUrl => _dotNetVersionUrl.Value; - public string CoreSetupVersionFragment => _coreSetupVersionFragment.Value; - public string RoslynVersionFragment => _roslynVersionFragment.Value; - public bool HasRoslynVersionFragment => !string.IsNullOrEmpty(RoslynVersionFragment); + public Dictionary VersionFragments => _versionFragments.Value; + public bool HasVersionFragment(string repoName) => _versionFragments.Value.ContainsKey(repoName); public string GitHubUpstreamOwner => _gitHubUpstreamOwner.Value; public string GitHubProject => _gitHubProject.Value; public string GitHubUpstreamBranch => _gitHubUpstreamBranch.Value; diff --git a/build_projects/update-dependencies/Program.cs b/build_projects/update-dependencies/Program.cs index 99b77691e..47c787fc6 100644 --- a/build_projects/update-dependencies/Program.cs +++ b/build_projects/update-dependencies/Program.cs @@ -24,15 +24,8 @@ namespace Microsoft.DotNet.Scripts bool onlyUpdate = args.Length > 0 && string.Equals("--Update", args[0], StringComparison.OrdinalIgnoreCase); - List buildInfos = new List(); - - buildInfos.Add(GetBuildInfo("CoreSetup", s_config.CoreSetupVersionFragment, fetchLatestReleaseFile: false)); - - if (s_config.HasRoslynVersionFragment) - { - buildInfos.Add(GetBuildInfo("Roslyn", s_config.RoslynVersionFragment, fetchLatestReleaseFile: false)); - } - + List buildInfos = new List(s_config.VersionFragments.Select, BuildInfo>(fragment => + GetBuildInfo(fragment.Key, fragment.Value, fetchLatestReleaseFile: false))); IEnumerable updaters = GetUpdaters(); var dependencyBuildInfos = buildInfos.Select(buildInfo => new BuildDependencyInfo( @@ -90,14 +83,55 @@ namespace Microsoft.DotNet.Scripts private static IEnumerable GetUpdaters() { string dependencyVersionsPath = Path.Combine("build", "DependencyVersions.props"); - yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftNETCoreAppPackageVersion", "Microsoft.NETCore.App"); - yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftDotNetPlatformAbstractionsPackageVersion", "Microsoft.DotNet.PlatformAbstractions"); - yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftExtensionsDependencyModelPackageVersion", "Microsoft.Extensions.DependencyModel"); - - if (s_config.HasRoslynVersionFragment) + + if (s_config.HasVersionFragment("aspnet")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftAspNetCoreAppPackageVersion", "Microsoft.AspNetCore.App"); + } + if (s_config.HasVersionFragment("clicommandlineparser")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftDotNetCliCommandLinePackageVersion", "Microsoft.DotNet.Cli.CommandLine"); + } + if (s_config.HasVersionFragment("climigrate")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftDotNetProjectJsonMigrationPackageVersion", "Microsoft.DotNet.ProjectJsonMigration"); + } + if (s_config.HasVersionFragment("coresetup")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftNETCoreAppPackageVersion", "Microsoft.NETCore.App"); + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftDotNetPlatformAbstractionsPackageVersion", "Microsoft.DotNet.PlatformAbstractions"); + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftExtensionsDependencyModelPackageVersion", "Microsoft.Extensions.DependencyModel"); + } + if (s_config.HasVersionFragment("fsharp")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftFSharpCompilerPackageVersion", "Microsoft.FSharp.Compiler"); + } + if (s_config.HasVersionFragment("msbuild")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftBuildPackageVersion", "Microsoft.Build"); + } + if (s_config.HasVersionFragment("nugetclient")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "NuGetBuildTasksPackageVersion", "NuGet.Build.Tasks"); + } + if (s_config.HasVersionFragment("roslyn")) { yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftCodeAnalysisCSharpPackageVersion", "Microsoft.CodeAnalysis.CSharp"); } + if (s_config.HasVersionFragment("sdk")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftNETSdkPackageVersion", "Microsoft.NET.Sdk"); + } + if (s_config.HasVersionFragment("templating")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftDotNetCommonItemTemplatesPackageVersion", "Microsoft.DotNet.Common.ItemTemplates"); + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftDotNetTestProjectTemplates20PackageVersion", "Microsoft.DotNet.Test.ProjectTemplates.2.0"); + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftTemplateEngineCliPackageVersion", "Microsoft.TemplateEngine.Cli"); + } + if (s_config.HasVersionFragment("websdk")) + { + yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftNETSdkWebPackageVersion", "Microsoft.NET.Sdk.Web"); + } } private static IDependencyUpdater CreateRegexUpdater(string repoRelativePath, string propertyName, string packageId) diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs index f5473c278..3d201158d 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs @@ -114,7 +114,7 @@ namespace Microsoft.DotNet.Cli.Utils { _projectRoot = msBuildExePath; - var globalProperties = new Dictionary() + var globalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "MSBuildExtensionsPath", Path.GetDirectoryName(msBuildExePath) } }; diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs index aa26a9366..9a24f4212 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs @@ -399,6 +399,9 @@ namespace Microsoft.DotNet.Cli.Utils Path.Combine(AppContext.BaseDirectory, "MSBuild.dll") : msBuildExePath; + Reporter.Verbose.WriteLine(string.Format(LocalizableStrings.MSBuildArgs, + ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(args))); + var result = new MSBuildForwardingAppWithoutLogging(args, msBuildExePath) .GetProcessStartInfo() .ExecuteAndCaptureOutput(out string stdOut, out string stdErr); diff --git a/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHost.cs b/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHost.cs new file mode 100644 index 000000000..3b5547af8 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHost.cs @@ -0,0 +1,152 @@ +// 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.IO; +using System.Text; + +namespace Microsoft.DotNet.Cli.Utils +{ + /// + /// Embeds the App Name into the AppHost.exe + /// + public static class EmbedAppNameInHost + { + private static string _placeHolder = "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"; //hash value embedded in default apphost executable + private static byte[] _bytesToSearch = Encoding.UTF8.GetBytes(_placeHolder); + + /// + /// Create an AppHost with embedded configuration of app binary location + /// + /// The path of AppHost template, which has the place holder + /// The destination path for desired location to place, including the file name + /// Full path to app binary or relative path to appHostDestinationFilePath + public static void EmbedAndReturnModifiedAppHostPath( + string appHostSourceFilePath, + string appHostDestinationFilePath, + string appBinaryFilePath) + { + var hostExtension = Path.GetExtension(appHostSourceFilePath); + var appbaseName = Path.GetFileNameWithoutExtension(appBinaryFilePath); + var bytesToWrite = Encoding.UTF8.GetBytes(appBinaryFilePath); + var destinationDirectory = new FileInfo(appHostDestinationFilePath).Directory.FullName; + + if (File.Exists(appHostDestinationFilePath)) + { + //We have already done the required modification to apphost.exe + return; + } + + if (bytesToWrite.Length > 1024) + { + throw new EmbedAppNameInHostException(string.Format(LocalizableStrings.EmbedAppNameInHostFileNameIsTooLong, appBinaryFilePath)); + } + + var array = File.ReadAllBytes(appHostSourceFilePath); + + SearchAndReplace(array, _bytesToSearch, bytesToWrite, appHostSourceFilePath); + + if (!Directory.Exists(destinationDirectory)) + { + Directory.CreateDirectory(destinationDirectory); + } + + // Copy AppHostSourcePath to ModifiedAppHostPath so it inherits the same attributes\permissions. + File.Copy(appHostSourceFilePath, appHostDestinationFilePath); + + // Re-write ModifiedAppHostPath with the proper contents. + using (FileStream fs = new FileStream(appHostDestinationFilePath, FileMode.Truncate, FileAccess.ReadWrite, FileShare.Read)) + { + fs.Write(array, 0, array.Length); + } + } + + // See: https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm + private static int[] ComputeKMPFailureFunction(byte[] pattern) + { + int[] table = new int[pattern.Length]; + if (pattern.Length >= 1) + { + table[0] = -1; + } + if (pattern.Length >= 2) + { + table[1] = 0; + } + + int pos = 2; + int cnd = 0; + while (pos < pattern.Length) + { + if (pattern[pos - 1] == pattern[cnd]) + { + table[pos] = cnd + 1; + cnd++; + pos++; + } + else if (cnd > 0) + { + cnd = table[cnd]; + } + else + { + table[pos] = 0; + pos++; + } + } + return table; + } + + // See: https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm + private static int KMPSearch(byte[] pattern, byte[] bytes) + { + int m = 0; + int i = 0; + int[] table = ComputeKMPFailureFunction(pattern); + + while (m + i < bytes.Length) + { + if (pattern[i] == bytes[m + i]) + { + if (i == pattern.Length - 1) + { + return m; + } + i++; + } + else + { + if (table[i] > -1) + { + m = m + i - table[i]; + i = table[i]; + } + else + { + m++; + i = 0; + } + } + } + return -1; + } + + private static void SearchAndReplace(byte[] array, byte[] searchPattern, byte[] patternToReplace, string appHostSourcePath) + { + int offset = KMPSearch(searchPattern, array); + if (offset < 0) + { + throw new EmbedAppNameInHostException(string.Format(LocalizableStrings.EmbedAppNameInHostAppHostHasBeenModified, appHostSourcePath, _placeHolder)); + } + + patternToReplace.CopyTo(array, offset); + + if (patternToReplace.Length < searchPattern.Length) + { + for (int i = patternToReplace.Length; i < searchPattern.Length; i++) + { + array[i + offset] = 0x0; + } + } + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHostException.cs b/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHostException.cs new file mode 100644 index 000000000..a20432d42 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHostException.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 System; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class EmbedAppNameInHostException : Exception + { + public EmbedAppNameInHostException() + { + } + + public EmbedAppNameInHostException(string message) : base(message) + { + } + + public EmbedAppNameInHostException(string message, Exception innerException) : base(message, innerException) + { + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs b/src/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs index b8d85b3b7..f0a9fefbe 100644 --- a/src/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs +++ b/src/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs @@ -47,6 +47,7 @@ namespace Microsoft.DotNet.Cli.Utils .GetEnvironmentVariable("PATH") .Split(s_pathSeparator) .Select(p => p.Trim(s_quote)) + .Where(p => !string.IsNullOrWhiteSpace(p)) .Select(p => ExpandTildeSlash(p))); _searchPaths = searchPaths; @@ -141,5 +142,14 @@ namespace Microsoft.DotNet.Cli.Utils } } + public string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target) + { + return Environment.GetEnvironmentVariable(variable, target); + } + + public void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) + { + Environment.SetEnvironmentVariable(variable, value, target); + } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/IEnvironmentProvider.cs b/src/Microsoft.DotNet.Cli.Utils/IEnvironmentProvider.cs index 43830b6f5..17355e4a0 100644 --- a/src/Microsoft.DotNet.Cli.Utils/IEnvironmentProvider.cs +++ b/src/Microsoft.DotNet.Cli.Utils/IEnvironmentProvider.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; using System.Collections.Generic; namespace Microsoft.DotNet.Cli.Utils @@ -18,5 +19,9 @@ namespace Microsoft.DotNet.Cli.Utils bool GetEnvironmentVariableAsBool(string name, bool defaultValue); string GetEnvironmentVariable(string name); + + string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target); + + void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target); } } diff --git a/src/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx b/src/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx index 2ebbb5fe9..435a26de9 100644 --- a/src/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx +++ b/src/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx @@ -206,7 +206,7 @@ Generating deps.json at: {0} - unable to generate deps.json, it may have been already generated: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} Unable to find deps.json generator project. @@ -262,4 +262,13 @@ Unable to invoke {0} after the command has been run - \ No newline at end of file + + MSBuild arguments: {0} + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + Given file name '{0}' is longer than 1024 bytes + + diff --git a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj index 0a124d605..14d2eb2c2 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj +++ b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj @@ -29,7 +29,6 @@ - diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf index 449c774d4..e344ea524 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - Soubor deps.json se nepodařilo vygenerovat, protože už je pravděpodobně vygenerovaný: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + Soubor deps.json se nepodařilo vygenerovat, protože už je pravděpodobně vygenerovaný: {0} @@ -244,6 +244,21 @@ Běhové prostředí: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf index 17866d663..61e4513d5 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - "deps.json" kann nicht erzeugt werden; sie wurde vielleicht bereits erzeugt: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + "deps.json" kann nicht erzeugt werden; sie wurde vielleicht bereits erzeugt: {0} @@ -244,6 +244,21 @@ Laufzeitumgebung: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf index b3ee8513f..6c204f324 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - no se puede generar deps.json; es posible que ya se haya generado: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + no se puede generar deps.json; es posible que ya se haya generado: {0} @@ -244,6 +244,21 @@ Entorno de tiempo de ejecución: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf index 184e19566..88aad3035 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - impossible de générer deps.json, il a peut-être été déjà généré : {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + impossible de générer deps.json, il a peut-être été déjà généré : {0} @@ -244,6 +244,21 @@ Environnement d'exécution : + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf index 15ece9a24..ca4052e06 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - non è possibile generare deps.json. Potrebbe essere già stato generato: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + non è possibile generare deps.json. Potrebbe essere già stato generato: {0} @@ -244,6 +244,21 @@ Ambiente di runtime: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf index 7b9a7a89c..b4a5d5c52 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - deps.json を生成できません。既に生成されている可能性があります: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + deps.json を生成できません。既に生成されている可能性があります: {0} @@ -244,6 +244,21 @@ ランタイム環境: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf index d6e82782e..9dfca8978 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - deps.json을 생성할 수 없습니다. 이미 생성되었을 수 있습니다. {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + deps.json을 생성할 수 없습니다. 이미 생성되었을 수 있습니다. {0} @@ -244,6 +244,21 @@ 런타임 환경: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf index 25e6b67e0..ef52ffcc3 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - nie można wygenerować pliku deps.json, być może został już wygenerowany: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + nie można wygenerować pliku deps.json, być może został już wygenerowany: {0} @@ -244,6 +244,21 @@ Środowisko uruchomieniowe: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf index 2b4d00938..fd20f0ffa 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - não é possível gerar deps.json; ele pode já ter sido gerado: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + não é possível gerar deps.json; ele pode já ter sido gerado: {0} @@ -244,6 +244,21 @@ Ambiente de tempo de execução: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf index 844433601..35d41a676 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - не удается создать deps.json, возможно, он уже создан: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + не удается создать deps.json, возможно, он уже создан: {0} @@ -244,6 +244,21 @@ Среда выполнения: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf index 56d05c817..b1afa5763 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - deps.json oluşturulamadı, zaten oluşturulmuş olabilir: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + deps.json oluşturulamadı, zaten oluşturulmuş olabilir: {0} @@ -244,6 +244,21 @@ Çalışma Zamanı Ortamı: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf index da9efabae..c30d33e41 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - 无法生成 deps.json,该文件可能已生成: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + 无法生成 deps.json,该文件可能已生成: {0} @@ -244,6 +244,21 @@ 运行时环境: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf index 7fa3da3f4..d56372b1f 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf @@ -140,8 +140,8 @@ - unable to generate deps.json, it may have been already generated: {0} - 無法產生 deps.json,可能已產生過: {0} + Unable to generate deps.json, it may have been already generated. You can specify the "-d" option before the tool name for diagnostic output (for example, "dotnet -d <toolname>": {0} + 無法產生 deps.json,可能已產生過: {0} @@ -244,6 +244,21 @@ 執行階段環境: + + MSBuild arguments: {0} + MSBuild arguments: {0} + + + + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written. + + + + Given file name '{0}' is longer than 1024 bytes + Given file name '{0}' is longer than 1024 bytes + + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs b/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs index 584ae0923..966bd0d80 100644 --- a/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs +++ b/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs @@ -18,6 +18,7 @@ namespace Microsoft.DotNet.Configurer private IFirstTimeUseNoticeSentinel _firstTimeUseNoticeSentinel; private IAspNetCertificateSentinel _aspNetCertificateSentinel; private IAspNetCoreCertificateGenerator _aspNetCoreCertificateGenerator; + private IFileSentinel _toolPathSentinel; private string _cliFallbackFolderPath; private readonly IEnvironmentPath _pathAdder; @@ -27,6 +28,7 @@ namespace Microsoft.DotNet.Configurer IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel, IAspNetCertificateSentinel aspNetCertificateSentinel, IAspNetCoreCertificateGenerator aspNetCoreCertificateGenerator, + IFileSentinel toolPathSentinel, IEnvironmentProvider environmentProvider, IReporter reporter, string cliFallbackFolderPath, @@ -37,6 +39,7 @@ namespace Microsoft.DotNet.Configurer _firstTimeUseNoticeSentinel = firstTimeUseNoticeSentinel; _aspNetCertificateSentinel = aspNetCertificateSentinel; _aspNetCoreCertificateGenerator = aspNetCoreCertificateGenerator; + _toolPathSentinel = toolPathSentinel; _environmentProvider = environmentProvider; _reporter = reporter; _cliFallbackFolderPath = cliFallbackFolderPath; @@ -45,7 +48,10 @@ namespace Microsoft.DotNet.Configurer public void Configure() { - AddPackageExecutablePath(); + if (ShouldAddPackageExecutablePath()) + { + AddPackageExecutablePath(); + } if (ShouldPrintFirstTimeUseNotice()) { @@ -66,7 +72,7 @@ namespace Microsoft.DotNet.Configurer } } - if(ShouldGenerateAspNetCertificate()) + if (ShouldGenerateAspNetCertificate()) { GenerateAspNetCertificate(); } @@ -92,21 +98,16 @@ namespace Microsoft.DotNet.Configurer !_aspNetCertificateSentinel.Exists(); } + private bool ShouldAddPackageExecutablePath() + { + return ShouldRunFirstRunExperience() && !_toolPathSentinel.Exists(); + } + private void AddPackageExecutablePath() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - if (!_firstTimeUseNoticeSentinel.Exists()) - { - // Invoke when Windows first run - _pathAdder.AddPackageExecutablePathToUserPath(); - } - } - else - { - // Invoke during installer, otherwise, _pathAdder will be no op object that this point - _pathAdder.AddPackageExecutablePathToUserPath(); - } + _pathAdder.AddPackageExecutablePathToUserPath(); + + _toolPathSentinel.Create(); } private bool ShouldPrintFirstTimeUseNotice() diff --git a/src/Microsoft.DotNet.Configurer/FileSentinel.cs b/src/Microsoft.DotNet.Configurer/FileSentinel.cs new file mode 100644 index 000000000..d9c997004 --- /dev/null +++ b/src/Microsoft.DotNet.Configurer/FileSentinel.cs @@ -0,0 +1,46 @@ +// 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.IO; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.Configurer +{ + public class FileSentinel : IFileSentinel + { + private readonly FilePath _file; + private readonly IFileSystem _fileSystem; + + public FileSentinel(FilePath file) : + this(file, fileSystem: null) + { + } + + internal FileSentinel(FilePath file, IFileSystem fileSystem) + { + _file = file; + _fileSystem = fileSystem ?? FileSystemWrapper.Default; + } + + public bool Exists() + { + return _fileSystem.File.Exists(_file.Value); + } + + public void Create() + { + if (Exists()) + { + return; + } + + var directory = _file.GetDirectoryPath(); + if (!_fileSystem.Directory.Exists(directory.Value)) + { + _fileSystem.Directory.CreateDirectory(directory.Value); + } + + _fileSystem.File.CreateEmptyFile(_file.Value); + } + } +} diff --git a/src/Microsoft.DotNet.Configurer/IFileSentinel.cs b/src/Microsoft.DotNet.Configurer/IFileSentinel.cs new file mode 100644 index 000000000..f8fd8c702 --- /dev/null +++ b/src/Microsoft.DotNet.Configurer/IFileSentinel.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 System; + +namespace Microsoft.DotNet.Configurer +{ + public interface IFileSentinel + { + bool Exists(); + + void Create(); + } +} diff --git a/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx b/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx index 0f3baa4dd..95a181a0c 100644 --- a/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx +++ b/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx @@ -151,7 +151,7 @@ Here are some options to fix this error: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. - \ No newline at end of file + diff --git a/src/Microsoft.DotNet.Configurer/NoOpFileSentinel.cs b/src/Microsoft.DotNet.Configurer/NoOpFileSentinel.cs new file mode 100644 index 000000000..e77097011 --- /dev/null +++ b/src/Microsoft.DotNet.Configurer/NoOpFileSentinel.cs @@ -0,0 +1,19 @@ +// 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.IO; + +namespace Microsoft.DotNet.Configurer +{ + public class NoOpFileSentinel : IFileSentinel + { + public bool Exists() + { + return true; + } + + public void Create() + { + } + } +} diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.cs.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.cs.xlf index 6c8a84691..1508e819e 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.cs.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.cs.xlf @@ -62,7 +62,7 @@ Tuto chybu můžete opravit pomocí některé z těchto možností: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.de.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.de.xlf index ff35f87f0..4cf68ba6b 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.de.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.de.xlf @@ -62,7 +62,7 @@ Im Folgenden finden Sie einige Optionen, um diesen Fehler zu beheben: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.es.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.es.xlf index 44c0389eb..8e638b180 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.es.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.es.xlf @@ -61,7 +61,7 @@ Estas son algunas opciones para corregir este error: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.fr.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.fr.xlf index 95953db3f..89cdfdc54 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.fr.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.fr.xlf @@ -62,7 +62,7 @@ Voici quelques options pour corriger cette erreur : ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.it.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.it.xlf index b359ffe68..17ec98fe3 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.it.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.it.xlf @@ -62,7 +62,7 @@ Ecco alcune opzioni per correggere questo errore: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ja.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ja.xlf index 2632c0543..816ad1e0b 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ja.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ja.xlf @@ -62,7 +62,7 @@ Here are some options to fix this error: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ko.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ko.xlf index ab5a0750d..63a682827 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ko.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ko.xlf @@ -62,7 +62,7 @@ Here are some options to fix this error: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pl.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pl.xlf index 96a9a22de..49e5fd1d5 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pl.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pl.xlf @@ -62,7 +62,7 @@ Oto kilka opcji naprawiania tego błędu: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pt-BR.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pt-BR.xlf index 9a26ac428..a3830c761 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.pt-BR.xlf @@ -62,7 +62,7 @@ Aqui estão algumas opções para corrigir este erro: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ru.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ru.xlf index 7d539fe75..633685670 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ru.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.ru.xlf @@ -62,7 +62,7 @@ Here are some options to fix this error: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.tr.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.tr.xlf index 10d1e33a4..a7d99a398 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.tr.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.tr.xlf @@ -62,7 +62,7 @@ Bu hatayı düzeltmek için bazı seçenekler: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hans.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hans.xlf index 43c95f582..1d338304e 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hans.xlf @@ -62,7 +62,7 @@ Here are some options to fix this error: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hant.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hant.xlf index 6277f3a67..16d3d50d8 100644 --- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.zh-Hant.xlf @@ -62,7 +62,7 @@ Here are some options to fix this error: ASP.NET Core ------------ Successfully installed the ASP.NET Core HTTPS Development Certificate. -To trust the certificate (Windows and macOS only) first install the dev-certs tool by running 'dotnet tool install dotnet-dev-certs -g --version 2.1.0-preview1-final' and then run 'dotnet-dev-certs https --trust'. +To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054. ASP.NET Core ------------ diff --git a/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs b/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs index 2c790b156..c66b03f24 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs +++ b/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs @@ -19,6 +19,11 @@ namespace Microsoft.Extensions.EnvironmentAbstractions return new TemporaryDirectory(); } + public IEnumerable EnumerateFiles(string path, string searchPattern) + { + return Directory.EnumerateFiles(path, searchPattern); + } + public IEnumerable EnumerateFileSystemEntries(string path) { return Directory.EnumerateFileSystemEntries(path); diff --git a/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs b/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs index 1660bcfa4..04526de37 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs +++ b/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs @@ -11,6 +11,8 @@ namespace Microsoft.Extensions.EnvironmentAbstractions ITemporaryDirectory CreateTemporaryDirectory(); + IEnumerable EnumerateFiles(string path, string searchPattern); + IEnumerable EnumerateFileSystemEntries(string path); IEnumerable EnumerateFileSystemEntries(string path, string searchPattern); diff --git a/src/dotnet/BuildServer/IBuildServerManager.cs b/src/dotnet/BuildServer/IBuildServerManager.cs new file mode 100644 index 000000000..76d11a4be --- /dev/null +++ b/src/dotnet/BuildServer/IBuildServerManager.cs @@ -0,0 +1,15 @@ +// 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.Threading.Tasks; + +namespace Microsoft.DotNet.BuildServer +{ + internal interface IBuildServerManager + { + string ServerName { get; } + + Task ShutdownServerAsync(); + } +} diff --git a/src/dotnet/BuildServer/IRazorAssemblyResolver.cs b/src/dotnet/BuildServer/IRazorAssemblyResolver.cs new file mode 100644 index 000000000..31ad1a3e1 --- /dev/null +++ b/src/dotnet/BuildServer/IRazorAssemblyResolver.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 System; +using System.Collections.Generic; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.BuildServer +{ + internal interface IRazorAssemblyResolver + { + IEnumerable EnumerateRazorToolAssemblies(); + } +} diff --git a/src/dotnet/BuildServer/LocalizableStrings.resx b/src/dotnet/BuildServer/LocalizableStrings.resx new file mode 100644 index 000000000..198c6ee2e --- /dev/null +++ b/src/dotnet/BuildServer/LocalizableStrings.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + MSBuild server + + + VB/C# compiler server + + + Razor build server + + + a Razor project was not found in the current directory. + + diff --git a/src/dotnet/BuildServer/MSBuildServerManager.cs b/src/dotnet/BuildServer/MSBuildServerManager.cs new file mode 100644 index 000000000..d0667a600 --- /dev/null +++ b/src/dotnet/BuildServer/MSBuildServerManager.cs @@ -0,0 +1,29 @@ +// 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.Threading.Tasks; +using Microsoft.Build.Execution; + +namespace Microsoft.DotNet.BuildServer +{ + internal class MSBuildServerManager : IBuildServerManager + { + public string ServerName => LocalizableStrings.MSBuildServer; + + public Task ShutdownServerAsync() + { + return Task.Run(() => { + try + { + BuildManager.DefaultBuildManager.ShutdownAllNodes(); + return new Result(ResultKind.Success); + } + catch (Exception ex) + { + return new Result(ex); + } + }); + } + } +} diff --git a/src/dotnet/BuildServer/RazorAssemblyResolver.cs b/src/dotnet/BuildServer/RazorAssemblyResolver.cs new file mode 100644 index 000000000..517fc2830 --- /dev/null +++ b/src/dotnet/BuildServer/RazorAssemblyResolver.cs @@ -0,0 +1,52 @@ +// 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 Microsoft.DotNet.Cli.Utils; +using Microsoft.Build.Execution; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.BuildServer +{ + internal class RazorAssemblyResolver : IRazorAssemblyResolver + { + private readonly IDirectory _directory; + + public RazorAssemblyResolver(IDirectory directory = null) + { + _directory = directory ?? FileSystemWrapper.Default.Directory; + } + + public IEnumerable EnumerateRazorToolAssemblies() + { + HashSet seen = new HashSet(); + + var globalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + // This property disables default item globbing to improve performance + // This should be safe because we are not evaluating items, only properties + { Constants.EnableDefaultItems, "false" } + }; + + foreach (var projectFile in _directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.*proj")) + { + var project = new ProjectInstance(projectFile, globalProperties, null); + var path = project.GetPropertyValue("_RazorToolAssembly"); + if (string.IsNullOrEmpty(path)) + { + continue; + } + + if (!seen.Add(path)) + { + continue; + } + + yield return new FilePath(path); + } + } + } +} diff --git a/src/dotnet/BuildServer/RazorServerManager.cs b/src/dotnet/BuildServer/RazorServerManager.cs new file mode 100644 index 000000000..526724d6e --- /dev/null +++ b/src/dotnet/BuildServer/RazorServerManager.cs @@ -0,0 +1,65 @@ +// 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.IO; +using System.Threading.Tasks; +using Microsoft.Build.Exceptions; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.BuildServer +{ + internal class RazorServerManager : IBuildServerManager + { + private readonly IRazorAssemblyResolver _resolver; + private readonly ICommandFactory _commandFactory; + + public RazorServerManager(IRazorAssemblyResolver resolver = null, ICommandFactory commandFactory = null) + { + _resolver = resolver ?? new RazorAssemblyResolver(); + _commandFactory = commandFactory ?? new DotNetCommandFactory(alwaysRunOutOfProc: true); + } + + public string ServerName => LocalizableStrings.RazorServer; + + public Task ShutdownServerAsync() + { + return Task.Run(() => { + try + { + bool haveRazorAssembly = false; + + foreach (var toolAssembly in _resolver.EnumerateRazorToolAssemblies()) + { + haveRazorAssembly = true; + + var command = _commandFactory + .Create("exec", new string[] { toolAssembly.Value, "shutdown" }) + .CaptureStdOut() + .CaptureStdErr(); + + var result = command.Execute(); + if (result.ExitCode != 0) + { + return new Result(ResultKind.Failure, result.StdErr); + } + } + + if (!haveRazorAssembly) + { + return new Result(ResultKind.Skipped, LocalizableStrings.NoRazorProjectFound); + } + + return new Result(ResultKind.Success); + } + catch (InvalidProjectFileException ex) + { + return new Result(ex); + } + }); + } + } +} diff --git a/src/dotnet/BuildServer/Result.cs b/src/dotnet/BuildServer/Result.cs new file mode 100644 index 000000000..5962fa145 --- /dev/null +++ b/src/dotnet/BuildServer/Result.cs @@ -0,0 +1,37 @@ +// 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; + +namespace Microsoft.DotNet.BuildServer +{ + internal enum ResultKind + { + Success, + Failure, + Skipped + } + + internal struct Result + { + public Result(ResultKind kind, string message = null) + { + Kind = kind; + Message = message; + Exception = null; + } + + public Result(Exception exception) + { + Kind = ResultKind.Failure; + Message = exception.Message; + Exception = exception; + } + + public ResultKind Kind { get; private set; } + + public string Message { get; private set; } + + public Exception Exception { get; private set; } + } +} diff --git a/src/dotnet/BuildServer/VBCSCompilerServerManager.cs b/src/dotnet/BuildServer/VBCSCompilerServerManager.cs new file mode 100644 index 000000000..12b7bc111 --- /dev/null +++ b/src/dotnet/BuildServer/VBCSCompilerServerManager.cs @@ -0,0 +1,48 @@ +// 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.IO; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.BuildServer +{ + internal class VBCSCompilerServerManager : IBuildServerManager + { + internal static readonly string VBCSCompilerPath = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "Roslyn", + "bincore", + "VBCSCompiler.dll"); + + private readonly ICommandFactory _commandFactory; + + public VBCSCompilerServerManager(ICommandFactory commandFactory = null) + { + _commandFactory = commandFactory ?? new DotNetCommandFactory(alwaysRunOutOfProc: true); + } + + public string ServerName => LocalizableStrings.VBCSCompilerServer; + + public Task ShutdownServerAsync() + { + return Task.Run(() => { + var command = _commandFactory + .Create("exec", new[] { VBCSCompilerPath, "-shutdown" }) + .CaptureStdOut() + .CaptureStdErr(); + + var result = command.Execute(); + if (result.ExitCode != 0) + { + return new Result(ResultKind.Failure, result.StdErr); + } + + return new Result(ResultKind.Success); + }); + } + } +} diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.cs.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.cs.xlf new file mode 100644 index 000000000..3064a54dc --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.cs.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.de.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.de.xlf new file mode 100644 index 000000000..162b689a5 --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.de.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.es.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.es.xlf new file mode 100644 index 000000000..28ee2c3ce --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.es.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.fr.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.fr.xlf new file mode 100644 index 000000000..64b184f72 --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.fr.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.it.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.it.xlf new file mode 100644 index 000000000..816bdc16b --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.it.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.ja.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.ja.xlf new file mode 100644 index 000000000..1f143937f --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.ja.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.ko.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.ko.xlf new file mode 100644 index 000000000..61d5383c1 --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.ko.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.pl.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.pl.xlf new file mode 100644 index 000000000..93089c95e --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.pl.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.pt-BR.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.pt-BR.xlf new file mode 100644 index 000000000..6aeb12866 --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.pt-BR.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.ru.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.ru.xlf new file mode 100644 index 000000000..a16008670 --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.ru.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.tr.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.tr.xlf new file mode 100644 index 000000000..addbfafa2 --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.tr.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.zh-Hans.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.zh-Hans.xlf new file mode 100644 index 000000000..7f3a039bc --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.zh-Hans.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuildServer/xlf/LocalizableStrings.zh-Hant.xlf b/src/dotnet/BuildServer/xlf/LocalizableStrings.zh-Hant.xlf new file mode 100644 index 000000000..0f9fdc61b --- /dev/null +++ b/src/dotnet/BuildServer/xlf/LocalizableStrings.zh-Hant.xlf @@ -0,0 +1,27 @@ + + + + + + MSBuild server + MSBuild server + + + + VB/C# compiler server + VB/C# compiler server + + + + Razor build server + Razor build server + + + + a Razor project was not found in the current directory. + a Razor project was not found in the current directory. + + + + + \ No newline at end of file diff --git a/src/dotnet/BuiltInCommandsCatalog.cs b/src/dotnet/BuiltInCommandsCatalog.cs index 3ec1db6ec..e649f6cc7 100644 --- a/src/dotnet/BuiltInCommandsCatalog.cs +++ b/src/dotnet/BuiltInCommandsCatalog.cs @@ -3,6 +3,7 @@ using Microsoft.DotNet.Tools.Add; using Microsoft.DotNet.Tools.Build; +using Microsoft.DotNet.Tools.BuildServer; using Microsoft.DotNet.Tools.Clean; using Microsoft.DotNet.Tools.Help; using Microsoft.DotNet.Tools.List; @@ -149,6 +150,10 @@ namespace Microsoft.DotNet.Cli { Command = ToolCommand.Run }, + ["buildserver"] = new BuiltInCommandMetadata + { + Command = BuildServerCommand.Run + }, ["internal-reportinstallsuccess"] = new BuiltInCommandMetadata { Command = InternalReportinstallsuccess.Run diff --git a/src/dotnet/CommonLocalizableStrings.resx b/src/dotnet/CommonLocalizableStrings.resx index e06ee07c0..ad89d2c03 100644 --- a/src/dotnet/CommonLocalizableStrings.resx +++ b/src/dotnet/CommonLocalizableStrings.resx @@ -595,6 +595,9 @@ setx PATH "%PATH%;{0}" Since you just installed the .NET Core SDK, you will need to reopen the Command Prompt window before running the tool you installed. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to create tool shim for command '{0}': {1} diff --git a/src/dotnet/Parser.cs b/src/dotnet/Parser.cs index 59d356094..644ddd5c0 100644 --- a/src/dotnet/Parser.cs +++ b/src/dotnet/Parser.cs @@ -56,6 +56,7 @@ namespace Microsoft.DotNet.Cli CompleteCommandParser.Complete(), InternalReportinstallsuccessCommandParser.InternalReportinstallsuccess(), ToolCommandParser.Tool(), + BuildServerCommandParser.CreateCommand(), CommonOptions.HelpOption(), Create.Option("--info", ""), Create.Option("-d", ""), diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs index 4283bb96a..6ae1409ce 100644 --- a/src/dotnet/Program.cs +++ b/src/dotnet/Program.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -23,6 +24,8 @@ namespace Microsoft.DotNet.Cli { public class Program { + private static readonly string ToolPathSentinelFileName = $"{Product.Version}.toolpath.sentinel"; + public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); @@ -94,6 +97,12 @@ namespace Microsoft.DotNet.Cli { IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = disposableFirstTimeUseNoticeSentinel; IAspNetCertificateSentinel aspNetCertificateSentinel = new AspNetCertificateSentinel(cliFallbackFolderPathCalculator); + IFileSentinel toolPathSentinel = new FileSentinel( + new FilePath( + Path.Combine( + CliFolderPathCalculator.DotnetUserProfileFolderPath, + ToolPathSentinelFileName))); + for (; lastArg < args.Length; lastArg++) { if (IsArg(args[lastArg], "d", "diagnostics")) @@ -138,6 +147,7 @@ namespace Microsoft.DotNet.Cli { aspNetCertificateSentinel = new NoOpAspNetCertificateSentinel(); firstTimeUseNoticeSentinel = new NoOpFirstTimeUseNoticeSentinel(); + toolPathSentinel = new NoOpFileSentinel(); hasSuperUserAccess = true; } @@ -145,6 +155,7 @@ namespace Microsoft.DotNet.Cli nugetCacheSentinel, firstTimeUseNoticeSentinel, aspNetCertificateSentinel, + toolPathSentinel, cliFallbackFolderPathCalculator, hasSuperUserAccess); @@ -209,6 +220,7 @@ namespace Microsoft.DotNet.Cli INuGetCacheSentinel nugetCacheSentinel, IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel, IAspNetCertificateSentinel aspNetCertificateSentinel, + IFileSentinel toolPathSentinel, CliFolderPathCalculator cliFolderPathCalculator, bool hasSuperUserAccess) { @@ -231,6 +243,7 @@ namespace Microsoft.DotNet.Cli firstTimeUseNoticeSentinel, aspNetCertificateSentinel, aspnetCertificateGenerator, + toolPathSentinel, environmentProvider, Reporter.Output, cliFolderPathCalculator.CliFallbackFolderPath, diff --git a/src/dotnet/ShellShim/EnvironmentPathFactory.cs b/src/dotnet/ShellShim/EnvironmentPathFactory.cs index a60a4ba86..13123fe62 100644 --- a/src/dotnet/ShellShim/EnvironmentPathFactory.cs +++ b/src/dotnet/ShellShim/EnvironmentPathFactory.cs @@ -33,14 +33,16 @@ namespace Microsoft.DotNet.ShellShim { environmentPath = new WindowsEnvironmentPath( cliFolderPathCalculator.ToolsShimPath, - Reporter.Output); + Reporter.Output, + environmentProvider); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && hasSuperUserAccess) { environmentPath = new LinuxEnvironmentPath( cliFolderPathCalculator.ToolsShimPathInUnix, Reporter.Output, - environmentProvider, new FileWrapper()); + environmentProvider, + new FileWrapper()); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && hasSuperUserAccess) { diff --git a/src/dotnet/ShellShim/LinuxEnvironmentPath.cs b/src/dotnet/ShellShim/LinuxEnvironmentPath.cs index 3ddde8308..b3142ed91 100644 --- a/src/dotnet/ShellShim/LinuxEnvironmentPath.cs +++ b/src/dotnet/ShellShim/LinuxEnvironmentPath.cs @@ -18,9 +18,9 @@ namespace Microsoft.DotNet.ShellShim private const string PathName = "PATH"; private readonly BashPathUnderHomeDirectory _packageExecutablePath; - private readonly string _profiledDotnetCliToolsPath - = Environment.GetEnvironmentVariable("DOTNET_CLI_TEST_LINUX_PROFILED_PATH") - ?? @"/etc/profile.d/dotnet-cli-tools-bin-path.sh"; + internal static readonly string DotnetCliToolsProfilePath = + Environment.GetEnvironmentVariable("DOTNET_CLI_TEST_LINUX_PROFILED_PATH") ?? + @"/etc/profile.d/dotnet-cli-tools-bin-path.sh"; internal LinuxEnvironmentPath( BashPathUnderHomeDirectory packageExecutablePath, @@ -44,28 +44,27 @@ namespace Microsoft.DotNet.ShellShim } var script = $"export PATH=\"$PATH:{_packageExecutablePath.PathWithDollar}\""; - _fileSystem.WriteAllText(_profiledDotnetCliToolsPath, script); + _fileSystem.WriteAllText(DotnetCliToolsProfilePath, script); } private bool PackageExecutablePathExists() { - var environmentVariable = _environmentProvider - .GetEnvironmentVariable(PathName); - - if (environmentVariable == null) + var value = _environmentProvider.GetEnvironmentVariable(PathName); + if (value == null) { return false; } - return environmentVariable - .Split(':').Contains(_packageExecutablePath.Path); + return value + .Split(':') + .Any(p => p == _packageExecutablePath.Path || p == _packageExecutablePath.PathWithTilde); } public void PrintAddPathInstructionIfPathDoesNotExist() { if (!PackageExecutablePathExists()) { - if (_fileSystem.Exists(_profiledDotnetCliToolsPath)) + if (_fileSystem.Exists(DotnetCliToolsProfilePath)) { _reporter.WriteLine( CommonLocalizableStrings.EnvironmentPathLinuxNeedLogout); diff --git a/src/dotnet/ShellShim/OsxEnvironmentPath.cs b/src/dotnet/ShellShim/OsxEnvironmentPath.cs index 7b64f01c3..12e843bd0 100644 --- a/src/dotnet/ShellShim/OsxEnvironmentPath.cs +++ b/src/dotnet/ShellShim/OsxEnvironmentPath.cs @@ -18,7 +18,7 @@ namespace Microsoft.DotNet.ShellShim private readonly IEnvironmentProvider _environmentProvider; private readonly IReporter _reporter; - private static readonly string PathDDotnetCliToolsPath + internal static readonly string DotnetCliToolsPathsDPath = Environment.GetEnvironmentVariable("DOTNET_CLI_TEST_OSX_PATHSD_PATH") ?? @"/etc/paths.d/dotnet-cli-tools"; @@ -44,28 +44,27 @@ namespace Microsoft.DotNet.ShellShim return; } - var script = $"{_packageExecutablePath.PathWithTilde}"; - _fileSystem.WriteAllText(PathDDotnetCliToolsPath, script); + _fileSystem.WriteAllText(DotnetCliToolsPathsDPath, _packageExecutablePath.PathWithTilde); } private bool PackageExecutablePathExists() { - var environmentVariable = _environmentProvider.GetEnvironmentVariable(PathName); - - if (environmentVariable == null) + var value = _environmentProvider.GetEnvironmentVariable(PathName); + if (value == null) { return false; } - return environmentVariable.Split(':').Contains(_packageExecutablePath.PathWithTilde) - || environmentVariable.Split(':').Contains(_packageExecutablePath.Path); + return value + .Split(':') + .Any(p => p == _packageExecutablePath.Path || p == _packageExecutablePath.PathWithTilde); } public void PrintAddPathInstructionIfPathDoesNotExist() { if (!PackageExecutablePathExists()) { - if (_fileSystem.Exists(PathDDotnetCliToolsPath)) + if (_fileSystem.Exists(DotnetCliToolsPathsDPath)) { _reporter.WriteLine( CommonLocalizableStrings.EnvironmentPathOSXNeedReopen); diff --git a/src/dotnet/ShellShim/ShellShimRepository.cs b/src/dotnet/ShellShim/ShellShimRepository.cs index 92bb55f4b..a7b890525 100644 --- a/src/dotnet/ShellShim/ShellShimRepository.cs +++ b/src/dotnet/ShellShim/ShellShimRepository.cs @@ -6,25 +6,28 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Xml.Linq; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.PlatformAbstractions; using Microsoft.DotNet.Tools; +using Microsoft.DotNet.Tools.Common; using Microsoft.Extensions.EnvironmentAbstractions; +using Newtonsoft.Json; namespace Microsoft.DotNet.ShellShim { internal class ShellShimRepository : IShellShimRepository { - private const string LauncherExeResourceName = "Microsoft.DotNet.Tools.Launcher.Executable"; - private const string LauncherConfigResourceName = "Microsoft.DotNet.Tools.Launcher.Config"; + private const string ApphostNameWithoutExtension = "apphost"; private readonly DirectoryPath _shimsDirectory; + private readonly string _appHostSourceDirectory; - public ShellShimRepository(DirectoryPath shimsDirectory) + public ShellShimRepository(DirectoryPath shimsDirectory, string appHostSourcePath = null) { _shimsDirectory = shimsDirectory; + _appHostSourceDirectory = appHostSourcePath ?? Path.Combine(ApplicationEnvironment.ApplicationBasePath, + "AppHostTemplate"); } public void CreateShim(FilePath targetExecutablePath, string commandName) @@ -47,7 +50,8 @@ namespace Microsoft.DotNet.ShellShim } TransactionalAction.Run( - action: () => { + action: () => + { try { if (!Directory.Exists(_shimsDirectory.Value)) @@ -55,29 +59,13 @@ namespace Microsoft.DotNet.ShellShim Directory.CreateDirectory(_shimsDirectory.Value); } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + CreateApphostShim( + commandName, + entryPoint: targetExecutablePath); + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - CreateConfigFile( - outputPath: GetWindowsConfigPath(commandName), - entryPoint: targetExecutablePath, - runner: "dotnet"); - - using (var shim = File.Create(GetWindowsShimPath(commandName).Value)) - using (var resource = typeof(ShellShimRepository).Assembly.GetManifestResourceStream(LauncherExeResourceName)) - { - resource.CopyTo(shim); - } - } - else - { - var script = new StringBuilder(); - script.AppendLine("#!/bin/sh"); - script.AppendLine($"dotnet {targetExecutablePath.ToQuotedString()} \"$@\""); - - var shimPath = GetPosixShimPath(commandName); - File.WriteAllText(shimPath.Value, script.ToString()); - - SetUserExecutionPermission(shimPath); + SetUserExecutionPermission(GetShimPath(commandName)); } } catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException) @@ -138,18 +126,35 @@ namespace Microsoft.DotNet.ShellShim }); } - internal void CreateConfigFile(FilePath outputPath, FilePath entryPoint, string runner) + private void CreateApphostShim(string commandName, FilePath entryPoint) { - XDocument config; - using (var resource = typeof(ShellShimRepository).Assembly.GetManifestResourceStream(LauncherConfigResourceName)) + string appHostSourcePath; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - config = XDocument.Load(resource); + appHostSourcePath = Path.Combine(_appHostSourceDirectory, ApphostNameWithoutExtension + ".exe"); + } + else + { + appHostSourcePath = Path.Combine(_appHostSourceDirectory, ApphostNameWithoutExtension); } - var appSettings = config.Descendants("appSettings").First(); - appSettings.Add(new XElement("add", new XAttribute("key", "entryPoint"), new XAttribute("value", entryPoint.Value))); - appSettings.Add(new XElement("add", new XAttribute("key", "runner"), new XAttribute("value", runner ?? string.Empty))); - config.Save(outputPath.Value); + var appHostDestinationFilePath = GetShimPath(commandName).Value; + var appBinaryFilePath = PathUtility.GetRelativePath(appHostDestinationFilePath, entryPoint.Value); + + EmbedAppNameInHost.EmbedAndReturnModifiedAppHostPath( + appHostSourceFilePath: appHostSourcePath, + appHostDestinationFilePath: appHostDestinationFilePath, + appBinaryFilePath: appBinaryFilePath); + } + + private class StartupOptions + { + public string appRoot { get; set; } + } + + private class RootObject + { + public StartupOptions startupOptions { get; set; } } private bool ShimExists(string commandName) @@ -164,32 +169,21 @@ namespace Microsoft.DotNet.ShellShim yield break; } + yield return GetShimPath(commandName); + } + + private FilePath GetShimPath(string commandName) + { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - yield return GetWindowsShimPath(commandName); - yield return GetWindowsConfigPath(commandName); + return new FilePath(_shimsDirectory.WithFile(commandName).Value +".exe"); } else { - yield return GetPosixShimPath(commandName); + return _shimsDirectory.WithFile(commandName); } } - private FilePath GetPosixShimPath(string commandName) - { - return _shimsDirectory.WithFile(commandName); - } - - private FilePath GetWindowsShimPath(string commandName) - { - return new FilePath(_shimsDirectory.WithFile(commandName).Value + ".exe"); - } - - private FilePath GetWindowsConfigPath(string commandName) - { - return new FilePath(GetWindowsShimPath(commandName).Value + ".config"); - } - private static void SetUserExecutionPermission(FilePath path) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) diff --git a/src/dotnet/ShellShim/WindowsEnvironmentPath.cs b/src/dotnet/ShellShim/WindowsEnvironmentPath.cs index 530f7c5bf..4c98f42fd 100644 --- a/src/dotnet/ShellShim/WindowsEnvironmentPath.cs +++ b/src/dotnet/ShellShim/WindowsEnvironmentPath.cs @@ -14,14 +14,13 @@ namespace Microsoft.DotNet.ShellShim private readonly IReporter _reporter; private const string PathName = "PATH"; private readonly string _packageExecutablePath; + private readonly IEnvironmentProvider _environmentProvider; - public WindowsEnvironmentPath( - string packageExecutablePath, IReporter reporter) + public WindowsEnvironmentPath(string packageExecutablePath, IReporter reporter, IEnvironmentProvider environmentProvider) { - _packageExecutablePath - = packageExecutablePath ?? throw new ArgumentNullException(nameof(packageExecutablePath)); - _reporter - = reporter ?? throw new ArgumentNullException(nameof(reporter)); + _packageExecutablePath = packageExecutablePath ?? throw new ArgumentNullException(nameof(packageExecutablePath)); + _reporter = reporter ?? throw new ArgumentNullException(nameof(reporter)); + _environmentProvider = environmentProvider ?? throw new ArgumentNullException(nameof(environmentProvider)); } public void AddPackageExecutablePathToUserPath() @@ -31,12 +30,37 @@ namespace Microsoft.DotNet.ShellShim return; } - var existingUserEnvPath = Environment.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.User); + var existingUserEnvPath = _environmentProvider.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.User); - Environment.SetEnvironmentVariable( - PathName, - $"{existingUserEnvPath};{_packageExecutablePath}", - EnvironmentVariableTarget.User); + try + { + if (existingUserEnvPath == null) + { + _environmentProvider.SetEnvironmentVariable( + PathName, + _packageExecutablePath, + EnvironmentVariableTarget.User); + } + else + { + if (existingUserEnvPath.EndsWith(';')) + { + existingUserEnvPath = existingUserEnvPath.Substring(0, (existingUserEnvPath.Length - 1)); + } + + _environmentProvider.SetEnvironmentVariable( + PathName, + $"{existingUserEnvPath};{_packageExecutablePath}", + EnvironmentVariableTarget.User); + } + } + catch (System.Security.SecurityException) + { + _reporter.WriteLine( + string.Format( + CommonLocalizableStrings.FailedToSetToolsPathEnvironmentVariable, + _packageExecutablePath).Yellow()); + } } private bool PackageExecutablePathExists() @@ -46,13 +70,13 @@ namespace Microsoft.DotNet.ShellShim private bool PackageExecutablePathWillExistForFutureNewProcess() { - return EnvironmentVariableConatinsPackageExecutablePath(Environment.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.User)) - || EnvironmentVariableConatinsPackageExecutablePath(Environment.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.Machine)); + return EnvironmentVariableConatinsPackageExecutablePath(_environmentProvider.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.User)) + || EnvironmentVariableConatinsPackageExecutablePath(_environmentProvider.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.Machine)); } private bool PackageExecutablePathExistsForCurrentProcess() { - return EnvironmentVariableConatinsPackageExecutablePath(Environment.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.Process)); + return EnvironmentVariableConatinsPackageExecutablePath(_environmentProvider.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.Process)); } private bool EnvironmentVariableConatinsPackageExecutablePath(string environmentVariable) @@ -62,15 +86,16 @@ namespace Microsoft.DotNet.ShellShim return false; } - return environmentVariable.Split(';').Contains(_packageExecutablePath); + return environmentVariable + .Split(';') + .Any(p => string.Equals(p, _packageExecutablePath, StringComparison.OrdinalIgnoreCase)); } public void PrintAddPathInstructionIfPathDoesNotExist() { if (!PackageExecutablePathExistsForCurrentProcess() && PackageExecutablePathWillExistForFutureNewProcess()) { - _reporter.WriteLine( - CommonLocalizableStrings.EnvironmentPathWindowsNeedReopen); + _reporter.WriteLine(CommonLocalizableStrings.EnvironmentPathWindowsNeedReopen); } else if (!PackageExecutablePathWillExistForFutureNewProcess()) { diff --git a/src/dotnet/commands/dotnet-buildserver/BuildServerCommand.cs b/src/dotnet/commands/dotnet-buildserver/BuildServerCommand.cs new file mode 100644 index 000000000..e45302274 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/BuildServerCommand.cs @@ -0,0 +1,33 @@ +// 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 Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools.BuildServer.Shutdown; + +namespace Microsoft.DotNet.Tools.BuildServer +{ + public class BuildServerCommand : DotNetTopLevelCommandBase + { + protected override string CommandName => "buildserver"; + protected override string FullCommandNameLocalized => LocalizableStrings.BuildServerCommandName; + protected override string ArgumentName => ""; + protected override string ArgumentDescriptionLocalized => ""; + + internal override Dictionary> SubCommands => + new Dictionary> + { + ["shutdown"] = appliedOption => new BuildServerShutdownCommand( + appliedOption["shutdown"], + ParseResult), + }; + + public static int Run(string[] args) + { + return new BuildServerCommand().RunCommand(args); + } + } +} diff --git a/src/dotnet/commands/dotnet-buildserver/BuildServerCommandParser.cs b/src/dotnet/commands/dotnet-buildserver/BuildServerCommandParser.cs new file mode 100644 index 000000000..a7693c2d7 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/BuildServerCommandParser.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 Microsoft.DotNet.Cli.CommandLine; +using LocalizableStrings = Microsoft.DotNet.Tools.BuildServer.LocalizableStrings; + +namespace Microsoft.DotNet.Cli +{ + internal static class BuildServerCommandParser + { + public static Command CreateCommand() + { + return Create.Command( + "buildserver", + LocalizableStrings.CommandDescription, + Accept.NoArguments(), + CommonOptions.HelpOption(), + ServerShutdownCommandParser.CreateCommand()); + } + } +} diff --git a/src/dotnet/commands/dotnet-buildserver/LocalizableStrings.resx b/src/dotnet/commands/dotnet-buildserver/LocalizableStrings.resx new file mode 100644 index 000000000..edd71c926 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/LocalizableStrings.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + .NET Build Server Command + + + Interact with servers started from a build. + + diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/BuildServerShutdownCommand.cs b/src/dotnet/commands/dotnet-buildserver/shutdown/BuildServerShutdownCommand.cs new file mode 100644 index 000000000..300223e90 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/BuildServerShutdownCommand.cs @@ -0,0 +1,144 @@ +// 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.Linq; +using System.Threading.Tasks; +using Microsoft.DotNet.BuildServer; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Tools.BuildServer.Shutdown +{ + internal class BuildServerShutdownCommand : CommandBase + { + private readonly bool _useOrderedWait; + private readonly IReporter _reporter; + private readonly IReporter _errorReporter; + + public BuildServerShutdownCommand( + AppliedOption options, + ParseResult result, + IEnumerable managers = null, + bool useOrderedWait = false, + IReporter reporter = null) + : base(result) + { + if (managers == null) + { + bool msbuild = options.ValueOrDefault("msbuild"); + bool vbcscompiler = options.ValueOrDefault("vbcscompiler"); + bool razor = options.ValueOrDefault("razor"); + bool all = !msbuild && !vbcscompiler && !razor; + + var enabledManagers = new List(); + if (msbuild || all) + { + enabledManagers.Add(new MSBuildServerManager()); + } + + if (vbcscompiler || all) + { + enabledManagers.Add(new VBCSCompilerServerManager()); + } + + if (razor || all) + { + enabledManagers.Add(new RazorServerManager()); + } + + managers = enabledManagers; + } + + Managers = managers; + _useOrderedWait = useOrderedWait; + _reporter = reporter ?? Reporter.Output; + _errorReporter = reporter ?? Reporter.Error; + } + + public IEnumerable Managers { get; } + + public override int Execute() + { + bool success = true; + + var tasks = StartShutdown(); + + while (tasks.Count > 0) + { + var index = WaitForResult(tasks.Select(t => t.Item2).ToArray()); + var (manager, task) = tasks[index]; + + success &= HandleResult(manager, task.Result); + + tasks.RemoveAt(index); + } + + return success ? 0 : 1; + } + + private List<(IBuildServerManager, Task)> StartShutdown() + { + var tasks = new List<(IBuildServerManager, Task)>(); + foreach (var manager in Managers) + { + _reporter.WriteLine(string.Format(LocalizableStrings.ShuttingDownServer, manager.ServerName)); + tasks.Add((manager, manager.ShutdownServerAsync())); + } + return tasks; + } + + private int WaitForResult(Task[] tasks) + { + if (_useOrderedWait) + { + tasks[0].Wait(); + return 0; + } + return Task.WaitAny(tasks); + } + + private bool HandleResult(IBuildServerManager manager, Result result) + { + switch (result.Kind) + { + case ResultKind.Success: + _reporter.WriteLine( + string.Format( + LocalizableStrings.ShutDownSucceeded, + manager.ServerName).Green()); + return true; + + case ResultKind.Skipped: + _reporter.WriteLine( + string.Format( + LocalizableStrings.ShutDownSkipped, + manager.ServerName, + result.Message).Cyan()); + return true; + + case ResultKind.Failure: + _errorReporter.WriteLine( + string.Format( + LocalizableStrings.ShutDownFailed, + manager.ServerName, + result.Message).Red()); + + if (Reporter.IsVerbose && result.Exception != null) + { + Reporter.Verbose.WriteLine(result.Exception.ToString().Red()); + } + return false; + + default: + throw new NotSupportedException( + string.Format( + LocalizableStrings.UnsupportedEnumValue, + result.Kind.ToString(), + nameof(ResultKind))); + } + } + } +} diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/BuildServerShutdownCommandParser.cs b/src/dotnet/commands/dotnet-buildserver/shutdown/BuildServerShutdownCommandParser.cs new file mode 100644 index 000000000..c813772fc --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/BuildServerShutdownCommandParser.cs @@ -0,0 +1,31 @@ +// 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 Microsoft.DotNet.Cli.CommandLine; +using LocalizableStrings = Microsoft.DotNet.Tools.BuildServer.Shutdown.LocalizableStrings; + +namespace Microsoft.DotNet.Cli +{ + internal static class ServerShutdownCommandParser + { + public static Command CreateCommand() + { + return Create.Command( + "shutdown", + LocalizableStrings.CommandDescription, + Create.Option( + "--msbuild", + LocalizableStrings.MSBuildOptionDescription, + Accept.NoArguments()), + Create.Option( + "--vbcscompiler", + LocalizableStrings.VBCSCompilerOptionDescription, + Accept.NoArguments()), + Create.Option( + "--razor", + LocalizableStrings.RazorOptionDescription, + Accept.NoArguments()), + CommonOptions.HelpOption()); + } + } +} diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/LocalizableStrings.resx b/src/dotnet/commands/dotnet-buildserver/shutdown/LocalizableStrings.resx new file mode 100644 index 000000000..edac1e52c --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/LocalizableStrings.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + Shuts down the MSBuild build server. + + + Shuts down the VB/C# compiler build server. + + + Shuts down the Razor build server. + + + Shutting down {0}... + + + {0} shut down successfully. + + + {0} failed to shut down: {1} + + + {0} shut down was skipped: {1} + + + The value '{0}' for enum type '{1}' is not supported. + + diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.cs.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.cs.xlf new file mode 100644 index 000000000..bb9a12c8c --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.cs.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.de.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.de.xlf new file mode 100644 index 000000000..4f07f6028 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.de.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.es.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.es.xlf new file mode 100644 index 000000000..47a9ad7c2 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.es.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.fr.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.fr.xlf new file mode 100644 index 000000000..e5a20083c --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.fr.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.it.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.it.xlf new file mode 100644 index 000000000..f48e4c3e0 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.it.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ja.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ja.xlf new file mode 100644 index 000000000..2b49a95ea --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ja.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ko.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ko.xlf new file mode 100644 index 000000000..40ca6507c --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ko.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.pl.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.pl.xlf new file mode 100644 index 000000000..625d93493 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.pl.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.pt-BR.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.pt-BR.xlf new file mode 100644 index 000000000..35cf7d075 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.pt-BR.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ru.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ru.xlf new file mode 100644 index 000000000..b6fdacbd6 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.ru.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.tr.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.tr.xlf new file mode 100644 index 000000000..acde159fc --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.tr.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.zh-Hans.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.zh-Hans.xlf new file mode 100644 index 000000000..b9e0a6c1c --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.zh-Hans.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.zh-Hant.xlf b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.zh-Hant.xlf new file mode 100644 index 000000000..a5a9c0cfc --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/shutdown/xlf/LocalizableStrings.zh-Hant.xlf @@ -0,0 +1,52 @@ + + + + + + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + Shuts down build servers that are started from dotnet. By default, all servers are shut down. + + + + Shuts down the MSBuild build server. + Shuts down the MSBuild build server. + + + + Shuts down the VB/C# compiler build server. + Shuts down the VB/C# compiler build server. + + + + Shuts down the Razor build server. + Shuts down the Razor build server. + + + + Shutting down {0}... + Shutting down {0}... + + + + {0} shut down successfully. + {0} shut down successfully. + + + + {0} failed to shut down: {1} + {0} failed to shut down: {1} + + + + {0} shut down was skipped: {1} + {0} shut down was skipped: {1} + + + + The value '{0}' for enum type '{1}' is not supported. + The value '{0}' for enum type '{1}' is not supported. + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.cs.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.cs.xlf new file mode 100644 index 000000000..5d129801c --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.cs.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.de.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.de.xlf new file mode 100644 index 000000000..98138e81b --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.de.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.es.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.es.xlf new file mode 100644 index 000000000..e81f02741 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.es.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.fr.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.fr.xlf new file mode 100644 index 000000000..17adb4387 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.fr.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.it.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.it.xlf new file mode 100644 index 000000000..e18631c38 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.it.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ja.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ja.xlf new file mode 100644 index 000000000..93021b724 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ja.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ko.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ko.xlf new file mode 100644 index 000000000..dbaea7baa --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ko.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.pl.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.pl.xlf new file mode 100644 index 000000000..4eea609ca --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.pl.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.pt-BR.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.pt-BR.xlf new file mode 100644 index 000000000..42d1bd160 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.pt-BR.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ru.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ru.xlf new file mode 100644 index 000000000..837af6754 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.ru.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.tr.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.tr.xlf new file mode 100644 index 000000000..55dd68623 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.tr.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.zh-Hans.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.zh-Hans.xlf new file mode 100644 index 000000000..b9e19d9f2 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.zh-Hans.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.zh-Hant.xlf b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.zh-Hant.xlf new file mode 100644 index 000000000..b9bf11b38 --- /dev/null +++ b/src/dotnet/commands/dotnet-buildserver/xlf/LocalizableStrings.zh-Hant.xlf @@ -0,0 +1,17 @@ + + + + + + Interact with servers started from a build. + Interact with servers started from a build. + + + + .NET Build Server Command + .NET Build Server Command + + + + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/HelpUsageText.cs b/src/dotnet/commands/dotnet-help/HelpUsageText.cs index ae461c33a..afb84106f 100644 --- a/src/dotnet/commands/dotnet-help/HelpUsageText.cs +++ b/src/dotnet/commands/dotnet-help/HelpUsageText.cs @@ -29,6 +29,7 @@ path-to-application: vstest {LocalizableStrings.VsTestDefinition} store {LocalizableStrings.StoreDefinition} tool {LocalizableStrings.ToolDefinition} + buildserver {LocalizableStrings.BuildServerDefinition} help {LocalizableStrings.HelpDefinition} {LocalizableStrings.CommonOptions}: diff --git a/src/dotnet/commands/dotnet-help/LocalizableStrings.resx b/src/dotnet/commands/dotnet-help/LocalizableStrings.resx index 42ff73843..87a781848 100644 --- a/src/dotnet/commands/dotnet-help/LocalizableStrings.resx +++ b/src/dotnet/commands/dotnet-help/LocalizableStrings.resx @@ -270,4 +270,7 @@ Modify tools. + + Interact with servers started by a build. + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf index 7cdeaed19..9b8a0c214 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.cs.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.de.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.de.xlf index 2bd3c69dc..df32954c2 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.de.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.de.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.es.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.es.xlf index 754433d94..1ba51c59a 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.es.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.es.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.fr.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.fr.xlf index 2fc2bf937..ed6cff4a7 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.fr.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.fr.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.it.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.it.xlf index 9dd3c00a4..678a1dfce 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.it.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.it.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ja.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ja.xlf index 7301eb539..3f0e97b11 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ja.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ja.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ko.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ko.xlf index 75296417f..366c4c1a4 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ko.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ko.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pl.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pl.xlf index a0409336b..b35cbe1cb 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pl.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pl.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pt-BR.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pt-BR.xlf index 5f76a9088..86bda21d2 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.pt-BR.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ru.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ru.xlf index 923b0180f..094767b66 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ru.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.ru.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.tr.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.tr.xlf index 28aba82ee..2f555f8a5 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.tr.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.tr.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hans.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hans.xlf index cd96243fa..6732ed858 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hans.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hant.xlf b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hant.xlf index 4662fc371..de2e7e1f4 100644 --- a/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/dotnet/commands/dotnet-help/xlf/LocalizableStrings.zh-Hant.xlf @@ -257,6 +257,11 @@ Modify tools. + + Interact with servers started by a build. + Interact with servers started by a build. + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-run/RunCommand.cs b/src/dotnet/commands/dotnet-run/RunCommand.cs index 4d8aecc46..307a2fff7 100644 --- a/src/dotnet/commands/dotnet-run/RunCommand.cs +++ b/src/dotnet/commands/dotnet-run/RunCommand.cs @@ -182,7 +182,7 @@ namespace Microsoft.DotNet.Tools.Run private ICommand GetRunCommand() { - var globalProperties = new Dictionary + var globalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase) { // This property disables default item globbing to improve performance // This should be safe because we are not evaluating items, only properties diff --git a/src/dotnet/commands/dotnet-tool/install/LocalizableStrings.resx b/src/dotnet/commands/dotnet-tool/install/LocalizableStrings.resx index af448e1e9..9705509b6 100644 --- a/src/dotnet/commands/dotnet-tool/install/LocalizableStrings.resx +++ b/src/dotnet/commands/dotnet-tool/install/LocalizableStrings.resx @@ -161,6 +161,9 @@ Tool '{1}' (version '{2}') was successfully installed. The settings file in the tool's NuGet package is invalid: {0} + Tool '{0}' failed to install. + + Tool '{0}' failed to install. You may need to specify the version using dotnet tool install -g {0} --version <version> @@ -189,4 +192,4 @@ Tool '{1}' (version '{2}') was successfully installed. Location where the tool will be installed. - \ No newline at end of file + diff --git a/src/dotnet/commands/dotnet-tool/install/ToolInstallCommandLowLevelErrorConverter.cs b/src/dotnet/commands/dotnet-tool/install/ToolInstallCommandLowLevelErrorConverter.cs index e1596b0bb..b73409a32 100644 --- a/src/dotnet/commands/dotnet-tool/install/ToolInstallCommandLowLevelErrorConverter.cs +++ b/src/dotnet/commands/dotnet-tool/install/ToolInstallCommandLowLevelErrorConverter.cs @@ -18,7 +18,7 @@ namespace Microsoft.DotNet.Tools.Tool.Install userFacingMessages = new[] { ex.Message, - string.Format(LocalizableStrings.ToolInstallationFailed, packageId), + string.Format(LocalizableStrings.ToolInstallationFailedWithExplicitVersionGuide, packageId), }; } else if (ex is ToolConfigurationException) diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.cs.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.cs.xlf index 6d683ff31..d75c80df3 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.cs.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.cs.xlf @@ -59,13 +59,6 @@ Nástroj {1} (verze {2}) byl úspěšně nainstalován. Soubor nastavení v balíčku NuGet nástroje je neplatný: {0}. - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - Nástroj {0} se nepodařilo nainstalovat. - - Tool '{0}' failed to install. Please contact the tool author for assistance. Nástroj {0} se nepodařilo nainstalovat. Obraťte se prosím s žádostí o pomoc na autora nástroje. @@ -121,6 +114,20 @@ Nástroj {1} (verze {2}) byl úspěšně nainstalován. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.de.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.de.xlf index c96dd1df9..c6d33bcb1 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.de.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.de.xlf @@ -59,13 +59,6 @@ Das Tool "{1}" (Version "{2}") wurde erfolgreich installiert. Die Einstellungsdatei im NuGet-Paket des Tools ist ungültig: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - Fehler bei der Installation des Tools "{0}". - - Tool '{0}' failed to install. Please contact the tool author for assistance. Fehler bei der Installation des Tools "{0}". Wenden Sie sich an den Verfasser des Tools, um Unterstützung zu erhalten. @@ -121,6 +114,20 @@ Das Tool "{1}" (Version "{2}") wurde erfolgreich installiert. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.es.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.es.xlf index 1978faa6f..9fc9f6efa 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.es.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.es.xlf @@ -59,13 +59,6 @@ La herramienta "{1}" (versión "{2}") se instaló correctamente. El archivo de configuración del paquete NuGet de la herramienta no es válido: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - No se pudo instalar la herramienta “{0}”. - - Tool '{0}' failed to install. Please contact the tool author for assistance. No se pudo instalar la herramienta “{0}”. Póngase en contacto con su creador para obtener asistencia. @@ -121,6 +114,20 @@ La herramienta "{1}" (versión "{2}") se instaló correctamente. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.fr.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.fr.xlf index fb105c682..6c63fcdb3 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.fr.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.fr.xlf @@ -59,13 +59,6 @@ L'outil '{1}' (version '{2}') a été installé. Le fichier de paramètres dans le package NuGet de l'outil n'est pas valide : {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - Impossible d'installer l'outil '{0}'. - - Tool '{0}' failed to install. Please contact the tool author for assistance. Impossible d'installer l'outil '{0}'. Contactez le créateur de l'outil pour obtenir de l'aide. @@ -121,6 +114,20 @@ L'outil '{1}' (version '{2}') a été installé. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.it.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.it.xlf index 972f85489..15307c595 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.it.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.it.xlf @@ -59,13 +59,6 @@ Lo strumento '{1}' (versione '{2}') è stato installato. Il file di impostazioni nel pacchetto NuGet dello strumento non è valido: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - Non è stato possibile installare lo strumento '{0}'. - - Tool '{0}' failed to install. Please contact the tool author for assistance. Non è stato possibile installare lo strumento '{0}'. Per assistenza, contattare l'autore dello strumento. @@ -121,6 +114,20 @@ Lo strumento '{1}' (versione '{2}') è stato installato. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ja.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ja.xlf index d04d679cd..f989e2181 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ja.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ja.xlf @@ -59,13 +59,6 @@ Tool '{1}' (version '{2}') was successfully installed. ツールの NuGet パッケージ内の設定ファイルが無効です: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - ツール '{0}' をインストールできませんでした。 - - Tool '{0}' failed to install. Please contact the tool author for assistance. ツール '{0}' をインストールできませんでした。ツールの作成者にお問い合わせください。 @@ -121,6 +114,20 @@ Tool '{1}' (version '{2}') was successfully installed. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ko.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ko.xlf index 36543e273..da7b4fe75 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ko.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ko.xlf @@ -59,13 +59,6 @@ Tool '{1}' (version '{2}') was successfully installed. 도구의 NuGet 패키지에 있는 설정 파일이 잘못되었습니다. {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - '{0}' 도구를 설치하지 못했습니다. - - Tool '{0}' failed to install. Please contact the tool author for assistance. '{0}' 도구를 설치하지 못했습니다. 도구 작성자에게 문의하세요. @@ -121,6 +114,20 @@ Tool '{1}' (version '{2}') was successfully installed. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pl.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pl.xlf index 57ac9d21f..30cad7df8 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pl.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pl.xlf @@ -59,13 +59,6 @@ Pomyślnie zainstalowano narzędzie „{1}” (wersja: „{2}”). Plik ustawień w pakiecie NuGet narzędzia jest nieprawidłowy: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - Zainstalowanie narzędzia „{0}” nie powiodło się. - - Tool '{0}' failed to install. Please contact the tool author for assistance. Zainstalowanie narzędzia „{0}” nie powiodło się. Skontaktuj się z autorem narzędzia w celu uzyskania pomocy. @@ -121,6 +114,20 @@ Pomyślnie zainstalowano narzędzie „{1}” (wersja: „{2}”). SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pt-BR.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pt-BR.xlf index 961c58a9a..798cf6891 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.pt-BR.xlf @@ -59,13 +59,6 @@ A ferramenta '{1}' (versão '{2}') foi instalada com êxito. O arquivo de configurações no pacote NuGet da ferramenta é inválido: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - Não foi possível instalar a ferramenta '{0}'. - - Tool '{0}' failed to install. Please contact the tool author for assistance. Não foi possível instalar a ferramenta '{0}'. Entre em contato com o autor da ferramenta para obter assistência. @@ -121,6 +114,20 @@ A ferramenta '{1}' (versão '{2}') foi instalada com êxito. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ru.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ru.xlf index f953077a3..138bd23f3 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ru.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.ru.xlf @@ -59,13 +59,6 @@ Tool '{1}' (version '{2}') was successfully installed. Недопустимый файл параметров в пакете NuGet инструмента: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - Не удалось установить инструмент "{0}". - - Tool '{0}' failed to install. Please contact the tool author for assistance. Не удалось установить инструмент "{0}". Обратитесь за помощью к его разработчику. @@ -121,6 +114,20 @@ Tool '{1}' (version '{2}') was successfully installed. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.tr.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.tr.xlf index f596ce661..9066f34cd 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.tr.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.tr.xlf @@ -59,13 +59,6 @@ Tool '{1}' (version '{2}') was successfully installed. Aracın NuGet paketindeki ayar dosyası geçersiz: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - '{0}' aracı yüklenemedi. - - Tool '{0}' failed to install. Please contact the tool author for assistance. '{0}' aracı yüklenemedi. Lütfen yardım için araç sahibiyle iletişime geçin. @@ -121,6 +114,20 @@ Tool '{1}' (version '{2}') was successfully installed. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hans.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hans.xlf index ede31a8f7..91ca03055 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hans.xlf @@ -59,13 +59,6 @@ Tool '{1}' (version '{2}') was successfully installed. 工具的 NuGet 包中的设置文件无效: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - 工具“{0}”安装失败。 - - Tool '{0}' failed to install. Please contact the tool author for assistance. 工具“{0}”安装失败。请联系工具作者获取帮助。 @@ -121,6 +114,20 @@ Tool '{1}' (version '{2}') was successfully installed. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hant.xlf b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hant.xlf index 3c41fffe8..9dd1605ef 100644 --- a/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/dotnet/commands/dotnet-tool/install/xlf/LocalizableStrings.zh-Hant.xlf @@ -59,13 +59,6 @@ Tool '{1}' (version '{2}') was successfully installed. 工具之 NuGet 套件中的設定檔案無效: {0} - - Tool '{0}' failed to install. You may need to specify the version using - - dotnet tool install -g {0} --version <version> - 工具 '{0}' 無法安裝。 - - Tool '{0}' failed to install. Please contact the tool author for assistance. 工具 '{0}' 無法安裝。請連絡工具作者尋求協助。 @@ -121,6 +114,20 @@ Tool '{1}' (version '{2}') was successfully installed. SOURCE_FEED + + Tool '{0}' failed to install. + Tool '{0}' failed to install. + + + + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + Tool '{0}' failed to install. You may need to specify the version using + + dotnet tool install -g {0} --version <version> + + \ No newline at end of file diff --git a/src/dotnet/dotnet.csproj b/src/dotnet/dotnet.csproj index 9705c5802..b7d26a073 100644 --- a/src/dotnet/dotnet.csproj +++ b/src/dotnet/dotnet.csproj @@ -16,10 +16,13 @@ + + + @@ -76,5 +79,5 @@ - - \ No newline at end of file + + diff --git a/src/dotnet/dotnet.win.targets b/src/dotnet/dotnet.win.targets deleted file mode 100644 index d46555d09..000000000 --- a/src/dotnet/dotnet.win.targets +++ /dev/null @@ -1,25 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - - - - - - - - - - - - - - diff --git a/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf b/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf index 1ad8c87ba..aa36da3b1 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.de.xlf b/src/dotnet/xlf/CommonLocalizableStrings.de.xlf index fd08ba0ae..c944f6a40 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.de.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.de.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.es.xlf b/src/dotnet/xlf/CommonLocalizableStrings.es.xlf index ff8efe426..58718eb15 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.es.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.es.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf b/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf index 30ba594d4..8b6d109c8 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.it.xlf b/src/dotnet/xlf/CommonLocalizableStrings.it.xlf index 73a334fac..7d37d0324 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.it.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.it.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf index 923244e61..f3806381e 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf index b8769753f..18e4e1ebc 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf b/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf index e06525415..c93085baa 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf b/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf index 5bac8fb07..64d6bb597 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf index a356ca731..84a2a6885 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf b/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf index 5cd7faabb..158df3e77 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf index c0f3a3706..bb980cac5 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf index c8312b3c9..a8751bbee 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf @@ -878,6 +878,11 @@ setx PATH "%PATH%;{0}" Format version is missing. This tool may not be supported in this SDK version. Please contact the author of the tool. + + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + Failed to add '{0}' to the PATH environment variable. Please add this directory to your PATH to use tools installed with 'dotnet tool install'. + + \ No newline at end of file diff --git a/src/redist/redist.csproj b/src/redist/redist.csproj index cd3ca221e..e3f051a92 100644 --- a/src/redist/redist.csproj +++ b/src/redist/redist.csproj @@ -193,6 +193,7 @@ @@ -211,6 +212,44 @@ + + + + Microsoft.NETCore.DotNetAppHost + + + + + + + + + + <_NETCoreDotNetAppHostPackageVersion>@(NETCoreDotNetAppHostPackageVersions->Distinct()) + + + + + + AppHostTemplatePath=$(SdkOutputDirectory)/AppHostTemplate; + TemplateFillInPackageName=$(NETCoreDotNetAppHostPackageName); + TemplateFillInPackageVersion=$(_NETCoreDotNetAppHostPackageVersion); + PreviousStageDirectory=$(PreviousStageDirectory); + AppHostIntermediateDirectory=$(IntermediateDirectory)/AppHostIntermediate + + + + + + + + + - /// The app is simple shim into launching arbitrary command line processes. - /// It is configured via app settings .NET config file. (See app.config). - /// - /// - /// Launching new processes using cmd.exe and .cmd files causes issues for long-running process - /// because CTRL+C always hangs on interrupt with the prompt "Terminate Y/N". This can lead to - /// orphaned processes. - /// - class Program - { - private const string TRACE = "DOTNET_LAUNCHER_TRACE"; - private const int ERR_FAILED = -1; - private static bool _trace; - - public static int Main(string[] argsToForward) - { - bool.TryParse(Environment.GetEnvironmentVariable(TRACE), out _trace); - - try - { - var appSettings = ConfigurationManager.AppSettings; - - var entryPoint = appSettings["entryPoint"]; - if (string.IsNullOrEmpty(entryPoint)) - { - LogError("The launcher must specify a non-empty appSetting value for 'entryPoint'."); - return ERR_FAILED; - } - - var exePath = entryPoint; - var runner = appSettings["runner"]; - - var args = new List(); - - if (!string.IsNullOrEmpty(runner)) - { - args.Add(entryPoint); - exePath = runner; - } - - args.AddRange(argsToForward); - - var argString = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(args); - - using (var process = new Process - { - StartInfo = - { - FileName = exePath, - Arguments = argString, - CreateNoWindow = false, - UseShellExecute = false, - } - }) - { - LogTrace("Starting a new process."); - LogTrace("filename = " + process.StartInfo.FileName); - LogTrace("args = " + process.StartInfo.Arguments); - LogTrace("cwd = " + process.StartInfo.WorkingDirectory); - - try - { - process.Start(); - } - catch (Win32Exception ex) - { - LogTrace(ex.ToString()); - LogError($"Failed to start '{process.StartInfo.FileName}'. " + ex.Message); - return ERR_FAILED; - } - - process.WaitForExit(); - - LogTrace("Exited code " + process.ExitCode); - - return process.ExitCode; - } - } - catch (Exception ex) - { - LogError("Unexpected error launching a new process. Run with the environment variable " + TRACE + "='true' for details."); - LogTrace(ex.ToString()); - return ERR_FAILED; - } - } - - private static void LogError(string message) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.BackgroundColor = ConsoleColor.Black; - Console.Error.WriteLine("ERROR: " + message); - Console.ResetColor(); - } - - private static void LogTrace(string message) - { - if (!_trace) - return; - - Console.ForegroundColor = ConsoleColor.DarkGray; - Console.BackgroundColor = ConsoleColor.Black; - Console.WriteLine("[dotnet-launcher] " + message); - Console.ResetColor(); - } - } -} diff --git a/src/tool_launcher/app.config b/src/tool_launcher/app.config deleted file mode 100644 index 14df07456..000000000 --- a/src/tool_launcher/app.config +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - diff --git a/src/tool_launcher/tool_launcher.csproj b/src/tool_launcher/tool_launcher.csproj deleted file mode 100644 index 26cd41b46..000000000 --- a/src/tool_launcher/tool_launcher.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - net35 - AnyCPU - exe - false - Microsoft.DotNet.Tools.Launcher - dotnet-tool-launcher - - A simple Windows-only shim for launching new processes. - - - - - - - - - - - - - $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client - - - - - - diff --git a/test/EndToEnd/GivenSelfContainedAppsRollForward.cs b/test/EndToEnd/GivenSelfContainedAppsRollForward.cs new file mode 100644 index 000000000..4bc4464bf --- /dev/null +++ b/test/EndToEnd/GivenSelfContainedAppsRollForward.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using FluentAssertions; +using Microsoft.DotNet.TestFramework; +using Microsoft.DotNet.Tools.Test.Utilities; +using NuGet.ProjectModel; +using NuGet.Versioning; +using Xunit; + +namespace EndToEnd +{ + public class GivenSelfContainedAppsRollForward : TestBase + { + + [Theory] + // MemberData is used instead of InlineData here so we can access it in another test to + // verify that we are covering the latest release of .NET Core + [MemberData(nameof(SupportedNetCoreAppVersions))] + public void ItRollsForwardToTheLatestVersion(string minorVersion) + { + var _testInstance = TestAssets.Get("TestAppSimple") + .CreateInstance(identifier: minorVersion) + .WithSourceFiles(); + + string projectDirectory = _testInstance.Root.FullName; + + string projectPath = Path.Combine(projectDirectory, "TestAppSimple.csproj"); + + var project = XDocument.Load(projectPath); + var ns = project.Root.Name.Namespace; + + // Update TargetFramework to the right version of .NET Core + project.Root.Element(ns + "PropertyGroup") + .Element(ns + "TargetFramework") + .Value = "netcoreapp" + minorVersion; + + var rid = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier(); + + // Set RuntimeIdentifier to opt in to roll-forward behavior + project.Root.Element(ns + "PropertyGroup") + .Add(new XElement(ns + "RuntimeIdentifier", rid)); + + project.Save(projectPath); + + // Get the version rolled forward to + new RestoreCommand() + .WithWorkingDirectory(projectDirectory) + .Execute() + .Should().Pass(); + + string assetsFilePath = Path.Combine(projectDirectory, "obj", "project.assets.json"); + var assetsFile = new LockFileFormat().Read(assetsFilePath); + + var rolledForwardVersion = GetNetCoreAppVersion(assetsFile); + rolledForwardVersion.Should().NotBeNull(); + + if (rolledForwardVersion.IsPrerelease) + { + // If this version of .NET Core is still prerelease, then: + // - Floating the patch by adding ".*" to the major.minor version won't work, but + // - There aren't any patches to roll-forward to, so we skip testing this until the version + // leaves prerelease. + return; + } + + // Float the RuntimeFrameworkVersion to get the latest version of the runtime available from feeds + Directory.Delete(Path.Combine(projectDirectory, "obj"), true); + project.Root.Element(ns + "PropertyGroup") + .Add(new XElement(ns + "RuntimeFrameworkVersion", $"{minorVersion}.*")); + project.Save(projectPath); + + new RestoreCommand() + .WithWorkingDirectory(projectDirectory) + .Execute() + .Should().Pass(); + + var floatedAssetsFile = new LockFileFormat().Read(assetsFilePath); + + var floatedVersion = GetNetCoreAppVersion(floatedAssetsFile); + floatedVersion.Should().NotBeNull(); + + rolledForwardVersion.ToNormalizedString().Should().BeEquivalentTo(floatedVersion.ToNormalizedString(), + "the latest patch version properties in Microsoft.NETCoreSdk.BundledVersions.props need to be updated " + + "(see MSBuildExtensions.targets in this repo)"); + } + + private NuGetVersion GetNetCoreAppVersion(LockFile lockFile) + { + return lockFile?.Targets?.SingleOrDefault(t => t.RuntimeIdentifier != null) + ?.Libraries?.SingleOrDefault(l => + string.Compare(l.Name, "Microsoft.NETCore.App", StringComparison.CurrentCultureIgnoreCase) == 0) + ?.Version; + } + + [Fact] + public void WeCoverLatestNetCoreAppRollForward() + { + // Run "dotnet new console", get TargetFramework property, and make sure it's covered in SupportedNetCoreAppVersions + using (DisposableDirectory directory = Temp.CreateDirectory()) + { + string projectDirectory = directory.Path; + + new NewCommandShim() + .WithWorkingDirectory(projectDirectory) + .Execute("console --no-restore") + .Should().Pass(); + + string projectPath = Path.Combine(projectDirectory, Path.GetFileName(projectDirectory) + ".csproj"); + + var project = XDocument.Load(projectPath); + var ns = project.Root.Name.Namespace; + + string targetFramework = project.Root.Element(ns + "PropertyGroup") + .Element(ns + "TargetFramework") + .Value; + + SupportedNetCoreAppVersions.Select(v => $"netcoreapp{v[0]}") + .Should().Contain(targetFramework, $"the {nameof(SupportedNetCoreAppVersions)} property should include the default version " + + "of .NET Core created by \"dotnet new\""); + + } + } + + public static IEnumerable SupportedNetCoreAppVersions + { + get + { + return new[] + { + "1.0", + "1.1", + "2.0", + "2.1" + }.Select(version => new object[] { version }); + } + } + } +} diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/PathUtilityTests.cs b/test/Microsoft.DotNet.Cli.Utils.Tests/PathUtilityTests.cs index 70e7768c7..2951ba9e7 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/PathUtilityTests.cs +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/PathUtilityTests.cs @@ -21,6 +21,32 @@ namespace Microsoft.DotNet.Cli.Utils Assert.Equal(@"d:\foo\", PathUtility.GetRelativePath(@"C:\foo\", @"d:\foo\")); } + [WindowsOnlyFact] + public void GetRelativePathForFilePath() + { + Assert.Equal( + @"mytool\1.0.1\mytool\1.0.1\tools\netcoreapp2.1\any\mytool.dll", + PathUtility.GetRelativePath( + @"C:\Users\myuser\.dotnet\tools\mytool.exe", + @"C:\Users\myuser\.dotnet\tools\mytool\1.0.1\mytool\1.0.1\tools\netcoreapp2.1\any\mytool.dll")); + } + + [WindowsOnlyFact] + public void GetRelativePathRequireTrailingSlashForDirectoryPath() + { + Assert.NotEqual( + @"mytool\1.0.1\mytool\1.0.1\tools\netcoreapp2.1\any\mytool.dll", + PathUtility.GetRelativePath( + @"C:\Users\myuser\.dotnet\tools", + @"C:\Users\myuser\.dotnet\tools\mytool\1.0.1\mytool\1.0.1\tools\netcoreapp2.1\any\mytool.dll")); + + Assert.Equal( + @"mytool\1.0.1\mytool\1.0.1\tools\netcoreapp2.1\any\mytool.dll", + PathUtility.GetRelativePath( + @"C:\Users\myuser\.dotnet\tools\", + @"C:\Users\myuser\.dotnet\tools\mytool\1.0.1\mytool\1.0.1\tools\netcoreapp2.1\any\mytool.dll")); + } + /// /// Tests that PathUtility.RemoveExtraPathSeparators works correctly with drive references on Windows. /// diff --git a/test/Microsoft.DotNet.Configurer.UnitTests/GivenADotnetFirstTimeUseConfigurer.cs b/test/Microsoft.DotNet.Configurer.UnitTests/GivenADotnetFirstTimeUseConfigurer.cs index 27b3247f4..115acacd7 100644 --- a/test/Microsoft.DotNet.Configurer.UnitTests/GivenADotnetFirstTimeUseConfigurer.cs +++ b/test/Microsoft.DotNet.Configurer.UnitTests/GivenADotnetFirstTimeUseConfigurer.cs @@ -20,9 +20,10 @@ namespace Microsoft.DotNet.Configurer.UnitTests private Mock _firstTimeUseNoticeSentinelMock; private Mock _aspNetCertificateSentinelMock; private Mock _aspNetCoreCertificateGeneratorMock; + private Mock _toolPathSentinelMock; private Mock _environmentProviderMock; private Mock _reporterMock; - private Mock _pathAdder; + private Mock _pathAdderMock; public GivenADotnetFirstTimeUseConfigurer() { @@ -31,9 +32,10 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock = new Mock(); _aspNetCertificateSentinelMock = new Mock(); _aspNetCoreCertificateGeneratorMock = new Mock(); + _toolPathSentinelMock = new Mock(); _environmentProviderMock = new Mock(); _reporterMock = new Mock(); - _pathAdder = new Mock(); + _pathAdderMock = new Mock(); _environmentProviderMock .Setup(e => e.GetEnvironmentVariableAsBool("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", false)) @@ -54,10 +56,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -79,10 +82,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -104,10 +108,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -126,10 +131,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -148,10 +154,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -169,10 +176,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -190,10 +198,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -214,10 +223,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -235,10 +245,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -257,10 +268,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -282,10 +294,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -298,25 +311,49 @@ namespace Microsoft.DotNet.Configurer.UnitTests } [Fact] - public void It_adds_executable_package_path_to_environment_path_when_the_first_notice_sentinel_does_not_exist() + public void It_adds_the_tool_path_to_the_environment_if_the_tool_path_sentinel_does_not_exist() { - _nugetCacheSentinelMock.Setup(n => n.Exists()).Returns(true); - _firstTimeUseNoticeSentinelMock.Setup(n => n.Exists()).Returns(false); + _toolPathSentinelMock.Setup(s => s.Exists()).Returns(false); var dotnetFirstTimeUseConfigurer = new DotnetFirstTimeUseConfigurer( _nugetCachePrimerMock.Object, - new FakeCreateWillExistNuGetCacheSentinel(false, true), - new FakeCreateWillExistFirstTimeUseNoticeSentinel(false), + _nugetCacheSentinelMock.Object, + _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); - _pathAdder.Verify(p => p.AddPackageExecutablePathToUserPath(), Times.AtLeastOnce); + _toolPathSentinelMock.Verify(s => s.Create(), Times.Once); + _pathAdderMock.Verify(p => p.AddPackageExecutablePathToUserPath(), Times.Once); + } + + [Fact] + public void It_does_not_add_the_tool_path_to_the_environment_if_the_tool_path_sentinel_exists() + { + _toolPathSentinelMock.Setup(s => s.Exists()).Returns(true); + + var dotnetFirstTimeUseConfigurer = new DotnetFirstTimeUseConfigurer( + _nugetCachePrimerMock.Object, + _nugetCacheSentinelMock.Object, + _firstTimeUseNoticeSentinelMock.Object, + _aspNetCertificateSentinelMock.Object, + _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, + _environmentProviderMock.Object, + _reporterMock.Object, + CliFallbackFolderPath, + _pathAdderMock.Object); + + dotnetFirstTimeUseConfigurer.Configure(); + + _toolPathSentinelMock.Verify(s => s.Create(), Times.Never); + _pathAdderMock.Verify(p => p.AddPackageExecutablePathToUserPath(), Times.Never); } [Fact] @@ -330,10 +367,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -359,10 +397,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -380,10 +419,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -405,10 +445,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -430,10 +471,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -454,10 +496,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests _firstTimeUseNoticeSentinelMock.Object, _aspNetCertificateSentinelMock.Object, _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, _environmentProviderMock.Object, _reporterMock.Object, CliFallbackFolderPath, - _pathAdder.Object); + _pathAdderMock.Object); dotnetFirstTimeUseConfigurer.Configure(); @@ -467,61 +510,48 @@ namespace Microsoft.DotNet.Configurer.UnitTests _aspNetCoreCertificateGeneratorMock.Verify(s => s.GenerateAspNetCoreDevelopmentCertificate(), Times.Once); } - private class FakeCreateWillExistFirstTimeUseNoticeSentinel : IFirstTimeUseNoticeSentinel + [Fact] + public void It_adds_the_tool_path_to_the_environment_if_the_first_run_experience_is_not_skipped() { - private bool _exists; + var dotnetFirstTimeUseConfigurer = new DotnetFirstTimeUseConfigurer( + _nugetCachePrimerMock.Object, + _nugetCacheSentinelMock.Object, + _firstTimeUseNoticeSentinelMock.Object, + _aspNetCertificateSentinelMock.Object, + _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, + _environmentProviderMock.Object, + _reporterMock.Object, + CliFallbackFolderPath, + _pathAdderMock.Object); - public FakeCreateWillExistFirstTimeUseNoticeSentinel(bool exists) - { - _exists = exists; - } + dotnetFirstTimeUseConfigurer.Configure(); - public void Dispose() - { - } - - public bool Exists() - { - return _exists; - } - - public void CreateIfNotExists() - { - _exists = true; - } + _pathAdderMock.Verify(p => p.AddPackageExecutablePathToUserPath(), Times.Once); } - private class FakeCreateWillExistNuGetCacheSentinel : INuGetCacheSentinel + [Fact] + public void It_does_not_add_the_tool_path_to_the_environment_if_the_first_run_experience_is_skipped() { - private bool _inProgressSentinelAlreadyExists; - private bool _exists; + _environmentProviderMock + .Setup(e => e.GetEnvironmentVariableAsBool("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", false)) + .Returns(true); - public FakeCreateWillExistNuGetCacheSentinel(bool inProgressSentinelAlreadyExists, bool exists) - { - _inProgressSentinelAlreadyExists = inProgressSentinelAlreadyExists; - _exists = exists; - } + var dotnetFirstTimeUseConfigurer = new DotnetFirstTimeUseConfigurer( + _nugetCachePrimerMock.Object, + _nugetCacheSentinelMock.Object, + _firstTimeUseNoticeSentinelMock.Object, + _aspNetCertificateSentinelMock.Object, + _aspNetCoreCertificateGeneratorMock.Object, + _toolPathSentinelMock.Object, + _environmentProviderMock.Object, + _reporterMock.Object, + CliFallbackFolderPath, + _pathAdderMock.Object); - public void Dispose() - { - } + dotnetFirstTimeUseConfigurer.Configure(); - public bool InProgressSentinelAlreadyExists() - { - return _inProgressSentinelAlreadyExists; - } - - public bool Exists() - { - return _exists; - } - - public void CreateIfNotExists() - { - _exists = true; - } - - public bool UnauthorizedAccess { get; set; } + _pathAdderMock.Verify(p => p.AddPackageExecutablePathToUserPath(), Times.Never); } } } diff --git a/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFirstTimeUseNoticeSentinel.cs b/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFirstTimeUseNoticeSentinel.cs index 8db9bc780..fd8887045 100644 --- a/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFirstTimeUseNoticeSentinel.cs +++ b/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFirstTimeUseNoticeSentinel.cs @@ -155,6 +155,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests throw new NotImplementedException(); } + public IEnumerable EnumerateFiles(string path, string searchPattern) + { + throw new NotImplementedException(); + } + public IEnumerable EnumerateFileSystemEntries(string path) { throw new NotImplementedException(); diff --git a/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFunctionReturnStringAndFakeFileSystem.cs b/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFunctionReturnStringAndFakeFileSystem.cs index 8b22e15ca..3844e07c1 100644 --- a/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFunctionReturnStringAndFakeFileSystem.cs +++ b/test/Microsoft.DotNet.Configurer.UnitTests/GivenAFunctionReturnStringAndFakeFileSystem.cs @@ -144,6 +144,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests throw new NotImplementedException(); } + public IEnumerable EnumerateFiles(string path, string searchPattern) + { + throw new NotImplementedException(); + } + public IEnumerable EnumerateFileSystemEntries(string path) { throw new UnauthorizedAccessException(); diff --git a/test/Microsoft.DotNet.Configurer.UnitTests/GivenANuGetCacheSentinel.cs b/test/Microsoft.DotNet.Configurer.UnitTests/GivenANuGetCacheSentinel.cs index ba76fb58b..c224254e0 100644 --- a/test/Microsoft.DotNet.Configurer.UnitTests/GivenANuGetCacheSentinel.cs +++ b/test/Microsoft.DotNet.Configurer.UnitTests/GivenANuGetCacheSentinel.cs @@ -183,6 +183,11 @@ namespace Microsoft.DotNet.Configurer.UnitTests throw new NotImplementedException(); } + public IEnumerable EnumerateFiles(string path, string searchPattern) + { + throw new NotImplementedException(); + } + public IEnumerable EnumerateFileSystemEntries(string path) { throw new NotImplementedException(); diff --git a/test/Microsoft.DotNet.ShellShim.Tests/FakeEnvironmentProvider.cs b/test/Microsoft.DotNet.ShellShim.Tests/FakeEnvironmentProvider.cs deleted file mode 100644 index e33918512..000000000 --- a/test/Microsoft.DotNet.ShellShim.Tests/FakeEnvironmentProvider.cs +++ /dev/null @@ -1,48 +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 Microsoft.DotNet.Cli.Utils; - -namespace Microsoft.DotNet.ShellShim.Tests -{ - internal class FakeEnvironmentProvider : IEnvironmentProvider - { - private readonly Dictionary _environmentVariables; - - public FakeEnvironmentProvider(Dictionary environmentVariables) - { - _environmentVariables = - environmentVariables ?? throw new ArgumentNullException(nameof(environmentVariables)); - } - - public IEnumerable ExecutableExtensions { get; } - - public string GetCommandPath(string commandName, params string[] extensions) - { - throw new NotImplementedException(); - } - - public string GetCommandPathFromRootPath(string rootPath, string commandName, params string[] extensions) - { - throw new NotImplementedException(); - } - - public string GetCommandPathFromRootPath(string rootPath, string commandName, - IEnumerable extensions) - { - throw new NotImplementedException(); - } - - public bool GetEnvironmentVariableAsBool(string name, bool defaultValue) - { - throw new NotImplementedException(); - } - - public string GetEnvironmentVariable(string name) - { - return _environmentVariables.ContainsKey(name) ? _environmentVariables[name] : ""; - } - } -} diff --git a/test/Microsoft.DotNet.ShellShim.Tests/FakeFile.cs b/test/Microsoft.DotNet.ShellShim.Tests/FakeFile.cs deleted file mode 100644 index 9b46dc2f4..000000000 --- a/test/Microsoft.DotNet.ShellShim.Tests/FakeFile.cs +++ /dev/null @@ -1,64 +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 Microsoft.Extensions.EnvironmentAbstractions; - -namespace Microsoft.DotNet.ShellShim.Tests -{ - internal class FakeFile : IFile - { - private Dictionary _files; - - public FakeFile(Dictionary files) - { - _files = files; - } - - public bool Exists(string path) - { - return _files.ContainsKey(path); - } - - public string ReadAllText(string path) - { - throw new NotImplementedException(); - } - - public Stream OpenRead(string path) - { - throw new NotImplementedException(); - } - - public Stream OpenFile(string path, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, - int bufferSize, - FileOptions fileOptions) - { - throw new NotImplementedException(); - } - - public void CreateEmptyFile(string path) - { - _files.Add(path, String.Empty); - } - - public void WriteAllText(string path, string content) - { - _files[path] = content; - } - - public void Move(string source, string destination) - { - throw new NotImplementedException(); - } - - public void Delete(string path) - { - throw new NotImplementedException(); - } - - public static FakeFile Empty => new FakeFile(new Dictionary()); - } -} diff --git a/test/Microsoft.DotNet.ShellShim.Tests/LinuxEnvironmentPathTests.cs b/test/Microsoft.DotNet.ShellShim.Tests/LinuxEnvironmentPathTests.cs index 17b26b38b..b934d2145 100644 --- a/test/Microsoft.DotNet.ShellShim.Tests/LinuxEnvironmentPathTests.cs +++ b/test/Microsoft.DotNet.ShellShim.Tests/LinuxEnvironmentPathTests.cs @@ -2,14 +2,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; using FluentAssertions; +using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Configurer; using Microsoft.DotNet.Tools; using Microsoft.DotNet.Tools.Test.Utilities; using Microsoft.Extensions.DependencyModel.Tests; +using Moq; using Xunit; namespace Microsoft.DotNet.ShellShim.Tests @@ -17,66 +16,138 @@ namespace Microsoft.DotNet.ShellShim.Tests public class LinuxEnvironmentPathTests { [Fact] - public void GivenEnvironmentAndReporterItCanPrintOutInstructionToAddPath() + public void GivenPathNotSetItPrintsManualInstructions() { var reporter = new BufferedReporter(); - var linuxEnvironmentPath = new LinuxEnvironmentPath( - new BashPathUnderHomeDirectory("/myhome", "executable/path"), + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue); + + var environmentPath = new LinuxEnvironmentPath( + toolsPath, reporter, - new FakeEnvironmentProvider( - new Dictionary - { - {"PATH", ""} - }), - FakeFile.Empty); + provider.Object, + FileSystemMockBuilder.Empty.File); - linuxEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); - // similar to https://code.visualstudio.com/docs/setup/mac reporter.Lines.Should().Equal( string.Format( CommonLocalizableStrings.EnvironmentPathLinuxManualInstructions, - "/myhome/executable/path")); + toolsPath.Path)); } [Fact] - public void GivenEnvironmentAndReporterItPrintsNothingWhenenvironmentExists() + public void GivenPathNotSetAndProfileExistsItPrintsLogoutMessage() { var reporter = new BufferedReporter(); - var linuxEnvironmentPath = new LinuxEnvironmentPath( - new BashPathUnderHomeDirectory("/myhome", "executable/path"), - reporter, - new FakeEnvironmentProvider( - new Dictionary - { - {"PATH", @"/myhome/executable/path"} - }), - FakeFile.Empty); + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); - linuxEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue); + + var environmentPath = new LinuxEnvironmentPath( + toolsPath, + reporter, + provider.Object, + new FileSystemMockBuilder() + .AddFile(LinuxEnvironmentPath.DotnetCliToolsProfilePath, "") + .Build() + .File); + + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + + reporter.Lines.Should().Equal(CommonLocalizableStrings.EnvironmentPathLinuxNeedLogout); + } + + [Theory] + [InlineData("/home/user/.dotnet/tools")] + [InlineData("~/.dotnet/tools")] + public void GivenPathSetItPrintsNothing(string toolsDiretoryOnPath) + { + var reporter = new BufferedReporter(); + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue + ":" + toolsDiretoryOnPath); + + var environmentPath = new LinuxEnvironmentPath( + toolsPath, + reporter, + provider.Object, + FileSystemMockBuilder.Empty.File); + + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); reporter.Lines.Should().BeEmpty(); } [Fact] - public void GivenAddPackageExecutablePathToUserPathJustRunItPrintsInstructionToLogout() + public void GivenPathSetItDoesNotAddPathToEnvironment() { var reporter = new BufferedReporter(); - var linuxEnvironmentPath = new LinuxEnvironmentPath( - new BashPathUnderHomeDirectory("/myhome", "executable/path"), + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + var fileSystem = new FileSystemMockBuilder().Build().File; + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue + ":" + toolsPath.Path); + + var environmentPath = new LinuxEnvironmentPath( + toolsPath, reporter, - new FakeEnvironmentProvider( - new Dictionary - { - {"PATH", @""} - }), - FakeFile.Empty); - linuxEnvironmentPath.AddPackageExecutablePathToUserPath(); + provider.Object, + fileSystem); - linuxEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + environmentPath.AddPackageExecutablePathToUserPath(); - reporter.Lines.Should() - .Equal(CommonLocalizableStrings.EnvironmentPathLinuxNeedLogout); + reporter.Lines.Should().BeEmpty(); + + fileSystem + .Exists(LinuxEnvironmentPath.DotnetCliToolsProfilePath) + .Should() + .Be(false); + } + + [Fact] + public void GivenPathNotSetItAddsToEnvironment() + { + var reporter = new BufferedReporter(); + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + var fileSystem = new FileSystemMockBuilder().Build().File; + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue); + + var environmentPath = new LinuxEnvironmentPath( + toolsPath, + reporter, + provider.Object, + fileSystem); + + environmentPath.AddPackageExecutablePathToUserPath(); + + reporter.Lines.Should().BeEmpty(); + + fileSystem + .ReadAllText(LinuxEnvironmentPath.DotnetCliToolsProfilePath) + .Should() + .Be($"export PATH=\"$PATH:{toolsPath.PathWithDollar}\""); } } } diff --git a/test/Microsoft.DotNet.ShellShim.Tests/OsxEnvironmentPathTests.cs b/test/Microsoft.DotNet.ShellShim.Tests/OsxEnvironmentPathTests.cs index dfab68062..3e0522ba0 100644 --- a/test/Microsoft.DotNet.ShellShim.Tests/OsxEnvironmentPathTests.cs +++ b/test/Microsoft.DotNet.ShellShim.Tests/OsxEnvironmentPathTests.cs @@ -2,14 +2,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; using FluentAssertions; +using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Configurer; using Microsoft.DotNet.Tools; using Microsoft.DotNet.Tools.Test.Utilities; using Microsoft.Extensions.DependencyModel.Tests; +using Moq; using Xunit; namespace Microsoft.DotNet.ShellShim.Tests @@ -17,67 +16,138 @@ namespace Microsoft.DotNet.ShellShim.Tests public class OsxEnvironmentPathTests { [Fact] - public void GivenEnvironmentAndReporterItCanPrintOutInstructionToAddPath() + public void GivenPathNotSetItPrintsManualInstructions() { var reporter = new BufferedReporter(); - var osxEnvironmentPath = new OSXEnvironmentPath( - new BashPathUnderHomeDirectory("/myhome", "executable/path"), + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue); + + var environmentPath = new OSXEnvironmentPath( + toolsPath, reporter, - new FakeEnvironmentProvider( - new Dictionary - { - {"PATH", ""} - }), - FakeFile.Empty); + provider.Object, + FileSystemMockBuilder.Empty.File); - osxEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); - // similar to https://code.visualstudio.com/docs/setup/mac reporter.Lines.Should().Equal( string.Format( CommonLocalizableStrings.EnvironmentPathOSXManualInstructions, - "/myhome/executable/path")); + toolsPath.Path)); + } + + [Fact] + public void GivenPathNotSetAndProfileExistsItPrintsReopenMessage() + { + var reporter = new BufferedReporter(); + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue); + + var environmentPath = new OSXEnvironmentPath( + toolsPath, + reporter, + provider.Object, + new FileSystemMockBuilder() + .AddFile(OSXEnvironmentPath.DotnetCliToolsPathsDPath, "") + .Build() + .File); + + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + + reporter.Lines.Should().Equal(CommonLocalizableStrings.EnvironmentPathOSXNeedReopen); } [Theory] - [InlineData("/myhome/executable/path")] - [InlineData("~/executable/path")] - public void GivenEnvironmentAndReporterItPrintsNothingWhenenvironmentExists(string existingPath) + [InlineData("/home/user/.dotnet/tools")] + [InlineData("~/.dotnet/tools")] + public void GivenPathSetItPrintsNothing(string toolsDiretoryOnPath) { var reporter = new BufferedReporter(); - var osxEnvironmentPath = new OSXEnvironmentPath( - new BashPathUnderHomeDirectory("/myhome", "executable/path"), - reporter, - new FakeEnvironmentProvider( - new Dictionary - { - {"PATH", existingPath} - }), - FakeFile.Empty); + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); - osxEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue + ":" + toolsDiretoryOnPath); + + var environmentPath = new OSXEnvironmentPath( + toolsPath, + reporter, + provider.Object, + FileSystemMockBuilder.Empty.File); + + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); reporter.Lines.Should().BeEmpty(); } [Fact] - public void GivenAddPackageExecutablePathToUserPathJustRunItPrintsInstructionToLogout() + public void GivenPathSetItDoesNotAddPathToEnvironment() { var reporter = new BufferedReporter(); - var osxEnvironmentPath = new OSXEnvironmentPath( - new BashPathUnderHomeDirectory("/myhome", "executable/path"), + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + var fileSystem = new FileSystemMockBuilder().Build().File; + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue + ":" + toolsPath.Path); + + var environmentPath = new OSXEnvironmentPath( + toolsPath, reporter, - new FakeEnvironmentProvider( - new Dictionary - { - {"PATH", @""} - }), - FakeFile.Empty); - osxEnvironmentPath.AddPackageExecutablePathToUserPath(); + provider.Object, + fileSystem); - osxEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + environmentPath.AddPackageExecutablePathToUserPath(); - reporter.Lines.Should().Equal(CommonLocalizableStrings.EnvironmentPathOSXNeedReopen); + reporter.Lines.Should().BeEmpty(); + + fileSystem + .Exists(OSXEnvironmentPath.DotnetCliToolsPathsDPath) + .Should() + .Be(false); + } + + [Fact] + public void GivenPathNotSetItAddsToEnvironment() + { + var reporter = new BufferedReporter(); + var toolsPath = new BashPathUnderHomeDirectory("/home/user", ".dotnet/tools"); + var pathValue = @"/usr/bin"; + var provider = new Mock(MockBehavior.Strict); + var fileSystem = new FileSystemMockBuilder().Build().File; + + provider + .Setup(p => p.GetEnvironmentVariable("PATH")) + .Returns(pathValue); + + var environmentPath = new OSXEnvironmentPath( + toolsPath, + reporter, + provider.Object, + fileSystem); + + environmentPath.AddPackageExecutablePathToUserPath(); + + reporter.Lines.Should().BeEmpty(); + + fileSystem + .ReadAllText(OSXEnvironmentPath.DotnetCliToolsPathsDPath) + .Should() + .Be(toolsPath.PathWithTilde); } } } diff --git a/test/Microsoft.DotNet.ShellShim.Tests/ShellShimRepositoryTests.cs b/test/Microsoft.DotNet.ShellShim.Tests/ShellShimRepositoryTests.cs index cf3599b54..15b9d4f7c 100644 --- a/test/Microsoft.DotNet.ShellShim.Tests/ShellShimRepositoryTests.cs +++ b/test/Microsoft.DotNet.ShellShim.Tests/ShellShimRepositoryTests.cs @@ -30,36 +30,12 @@ namespace Microsoft.DotNet.ShellShim.Tests _output = output; } - [WindowsOnlyTheory] - [InlineData("my_native_app.exe", null)] - [InlineData("./my_native_app.js", "nodejs")] - [InlineData(@"C:\tools\my_native_app.dll", "dotnet")] - public void GivenAnRunnerOrEntryPointItCanCreateConfig(string entryPointPath, string runner) - { - var pathToShim = GetNewCleanFolderUnderTempRoot(); - var shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); - var tmpFile = new FilePath(Path.Combine(pathToShim, Path.GetRandomFileName())); - - shellShimRepository.CreateConfigFile(tmpFile, new FilePath(entryPointPath), runner); - - new FileInfo(tmpFile.Value).Should().Exist(); - - var generated = XDocument.Load(tmpFile.Value); - - generated.Descendants("appSettings") - .Descendants("add") - .Should() - .Contain(e => e.Attribute("key").Value == "runner" && e.Attribute("value").Value == (runner ?? string.Empty)) - .And - .Contain(e => e.Attribute("key").Value == "entryPoint" && e.Attribute("value").Value == entryPointPath); - } - [Fact] public void GivenAnExecutablePathItCanGenerateShimFile() { var outputDll = MakeHelloWorldExecutableDll(); var pathToShim = GetNewCleanFolderUnderTempRoot(); - var shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + ShellShimRepository shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName(); shellShimRepository.CreateShim(outputDll, shellCommandName); @@ -69,12 +45,19 @@ namespace Microsoft.DotNet.ShellShim.Tests stdOut.Should().Contain("Hello World"); } + private static ShellShimRepository ConfigBasicTestDependecyShellShimRepository(string pathToShim) + { + string stage2AppHostTemplateDirectory = GetAppHostTemplateFromStage2(); + + return new ShellShimRepository(new DirectoryPath(pathToShim), stage2AppHostTemplateDirectory); + } + [Fact] public void GivenAnExecutablePathItCanGenerateShimFileInTransaction() { var outputDll = MakeHelloWorldExecutableDll(); var pathToShim = GetNewCleanFolderUnderTempRoot(); - var shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + var shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName(); using (var transactionScope = new TransactionScope( @@ -95,7 +78,7 @@ namespace Microsoft.DotNet.ShellShim.Tests { var outputDll = MakeHelloWorldExecutableDll(); var extraNonExistDirectory = Path.GetRandomFileName(); - var shellShimRepository = new ShellShimRepository(new DirectoryPath(Path.Combine(TempRoot.Root, extraNonExistDirectory))); + var shellShimRepository = new ShellShimRepository(new DirectoryPath(Path.Combine(TempRoot.Root, extraNonExistDirectory)), GetAppHostTemplateFromStage2()); var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName(); Action a = () => shellShimRepository.CreateShim(outputDll, shellCommandName); @@ -111,7 +94,7 @@ namespace Microsoft.DotNet.ShellShim.Tests { var outputDll = MakeHelloWorldExecutableDll(); var pathToShim = GetNewCleanFolderUnderTempRoot(); - var shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + var shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName(); shellShimRepository.CreateShim(outputDll, shellCommandName); @@ -140,7 +123,7 @@ namespace Microsoft.DotNet.ShellShim.Tests } else { - shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); } Action a = () => @@ -182,7 +165,7 @@ namespace Microsoft.DotNet.ShellShim.Tests } else { - shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); } Action intendedError = () => throw new ToolPackageException("simulated error"); @@ -219,7 +202,7 @@ namespace Microsoft.DotNet.ShellShim.Tests } else { - shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); } Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty(); @@ -244,7 +227,7 @@ namespace Microsoft.DotNet.ShellShim.Tests } else { - shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); } Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty(); @@ -273,7 +256,7 @@ namespace Microsoft.DotNet.ShellShim.Tests } else { - shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); } Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty(); @@ -309,7 +292,7 @@ namespace Microsoft.DotNet.ShellShim.Tests } else { - shellShimRepository = new ShellShimRepository(new DirectoryPath(pathToShim)); + shellShimRepository = ConfigBasicTestDependecyShellShimRepository(pathToShim); } Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty(); @@ -358,17 +341,28 @@ namespace Microsoft.DotNet.ShellShim.Tests } else { + var file = Path.Combine(cleanFolderUnderTempRoot, shellCommandName); processStartInfo = new ProcessStartInfo { - FileName = "sh", - Arguments = shellCommandName + " " + arguments, + FileName = file, + Arguments = arguments, UseShellExecute = false }; } _output.WriteLine($"Launching '{processStartInfo.FileName} {processStartInfo.Arguments}'"); processStartInfo.WorkingDirectory = cleanFolderUnderTempRoot; - processStartInfo.EnvironmentVariables["PATH"] = Path.GetDirectoryName(new Muxer().MuxerPath); + + var environmentProvider = new EnvironmentProvider(); + processStartInfo.EnvironmentVariables["PATH"] = environmentProvider.GetEnvironmentVariable("PATH"); + if (Environment.Is64BitProcess) + { + processStartInfo.EnvironmentVariables["DOTNET_ROOT"] = new RepoDirectoriesProvider().DotnetRoot; + } + else + { + processStartInfo.EnvironmentVariables["DOTNET_ROOT(x86)"] = new RepoDirectoriesProvider().DotnetRoot; + } processStartInfo.ExecuteAndCaptureOutput(out var stdOut, out var stdErr); @@ -377,6 +371,47 @@ namespace Microsoft.DotNet.ShellShim.Tests return stdOut ?? ""; } + private static FileInfo GetStage2DotnetPath() + { + string stage2DotnetPath; + + var environmentProvider = new EnvironmentProvider(); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + stage2DotnetPath = environmentProvider.GetCommandPath("dotnet", ".exe"); + } + else + { + stage2DotnetPath = environmentProvider.GetCommandPath("dotnet"); + } + + var stage2Dotnet = new FileInfo(stage2DotnetPath); + return stage2Dotnet; + } + + private static string GetAppHostTemplateFromStage2() + { + var environmentProvider = new EnvironmentProvider(); + string stage2DotnetPath; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + stage2DotnetPath = environmentProvider.GetCommandPath("dotnet", ".exe"); + } + else + { + stage2DotnetPath = environmentProvider.GetCommandPath("dotnet"); + } + + var stage2Dotnet = GetStage2DotnetPath(); + + var stage2AppHostTemplateDirectory = + new DirectoryInfo(new RepoDirectoriesProvider().Stage2Sdk) + .GetDirectory("AppHostTemplate").FullName; + return stage2AppHostTemplateDirectory; + } + private static FilePath MakeHelloWorldExecutableDll() { const string testAppName = "TestAppSimple"; diff --git a/test/Microsoft.DotNet.ShellShim.Tests/WindowsEnvironmentPathTests.cs b/test/Microsoft.DotNet.ShellShim.Tests/WindowsEnvironmentPathTests.cs new file mode 100644 index 000000000..b6424c127 --- /dev/null +++ b/test/Microsoft.DotNet.ShellShim.Tests/WindowsEnvironmentPathTests.cs @@ -0,0 +1,175 @@ +// 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 FluentAssertions; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Configurer; +using Microsoft.DotNet.Tools; +using Microsoft.DotNet.Tools.Test.Utilities; +using Moq; +using Xunit; + +namespace Microsoft.DotNet.ShellShim.Tests +{ + public class WindowsEnvironmentPathTests + { + [Fact] + public void GivenPathNotSetItPrintsManualInstructions() + { + var reporter = new BufferedReporter(); + var toolsPath = @"C:\Tools"; + var pathValue = @"C:\Other"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable( + "PATH", + It.Is(t => + t == EnvironmentVariableTarget.Process || + t == EnvironmentVariableTarget.User || + t == EnvironmentVariableTarget.Machine))) + .Returns(pathValue); + + var environmentPath = new WindowsEnvironmentPath(toolsPath, reporter, provider.Object); + + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + + reporter.Lines.Should().Equal( + string.Format( + CommonLocalizableStrings.EnvironmentPathWindowsManualInstructions, + toolsPath)); + } + + [Fact] + public void GivenPathNotSetInProcessItPrintsReopenNotice() + { + var reporter = new BufferedReporter(); + var toolsPath = @"C:\Tools"; + var pathValue = @"C:\Other"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process)) + .Returns(pathValue); + + provider + .Setup(p => p.GetEnvironmentVariable( + "PATH", + It.Is(t => + t == EnvironmentVariableTarget.User || + t == EnvironmentVariableTarget.Machine))) + .Returns(pathValue + ";" + toolsPath); + + var environmentPath = new WindowsEnvironmentPath(toolsPath, reporter, provider.Object); + + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + + reporter.Lines.Should().Equal(CommonLocalizableStrings.EnvironmentPathWindowsNeedReopen); + } + + [Fact] + public void GivenPathSetInProcessAndEnvironmentItPrintsNothing() + { + var reporter = new BufferedReporter(); + var toolsPath = @"C:\Tools"; + var pathValue = @"C:\Other"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable( + "PATH", + It.Is(t => + t == EnvironmentVariableTarget.Process || + t == EnvironmentVariableTarget.User || + t == EnvironmentVariableTarget.Machine))) + .Returns(pathValue + ";" + toolsPath); + + var environmentPath = new WindowsEnvironmentPath(toolsPath, reporter, provider.Object); + + environmentPath.PrintAddPathInstructionIfPathDoesNotExist(); + + reporter.Lines.Should().BeEmpty(); + } + + [Fact] + public void GivenPathSetItDoesNotAddPathToEnvironment() + { + var reporter = new BufferedReporter(); + var toolsPath = @"C:\Tools"; + var pathValue = @"C:\Other"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable( + "PATH", + It.Is(t => + t == EnvironmentVariableTarget.Process || + t == EnvironmentVariableTarget.User || + t == EnvironmentVariableTarget.Machine))) + .Returns(pathValue + ";" + toolsPath); + + var environmentPath = new WindowsEnvironmentPath(toolsPath, reporter, provider.Object); + + environmentPath.AddPackageExecutablePathToUserPath(); + + reporter.Lines.Should().BeEmpty(); + } + + [Fact] + public void GivenPathNotSetItAddsToEnvironment() + { + var reporter = new BufferedReporter(); + var toolsPath = @"C:\Tools"; + var pathValue = @"C:\Other"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable( + "PATH", + It.Is(t => + t == EnvironmentVariableTarget.Process || + t == EnvironmentVariableTarget.User || + t == EnvironmentVariableTarget.Machine))) + .Returns(pathValue); + provider + .Setup(p => p.SetEnvironmentVariable("PATH", pathValue + ";" + toolsPath, EnvironmentVariableTarget.User)); + + var environmentPath = new WindowsEnvironmentPath(toolsPath, reporter, provider.Object); + + environmentPath.AddPackageExecutablePathToUserPath(); + + reporter.Lines.Should().BeEmpty(); + } + + [Fact] + public void GivenSecurityExceptionItPrintsWarning() + { + var reporter = new BufferedReporter(); + var toolsPath = @"C:\Tools"; + var pathValue = @"C:\Other"; + var provider = new Mock(MockBehavior.Strict); + + provider + .Setup(p => p.GetEnvironmentVariable( + "PATH", + It.Is(t => + t == EnvironmentVariableTarget.Process || + t == EnvironmentVariableTarget.User || + t == EnvironmentVariableTarget.Machine))) + .Returns(pathValue); + provider + .Setup(p => p.SetEnvironmentVariable("PATH", pathValue + ";" + toolsPath, EnvironmentVariableTarget.User)) + .Throws(new System.Security.SecurityException()); + + var environmentPath = new WindowsEnvironmentPath(toolsPath, reporter, provider.Object); + + environmentPath.AddPackageExecutablePathToUserPath(); + + reporter.Lines.Should().Equal( + string.Format( + CommonLocalizableStrings.FailedToSetToolsPathEnvironmentVariable, + toolsPath).Yellow()); + } + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs index 83043dec9..6adce5ca9 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs @@ -150,6 +150,11 @@ namespace Microsoft.Extensions.DependencyModel.Tests return _temporaryDirectory; } + public IEnumerable EnumerateFiles(string path, string searchPattern) + { + throw new NotImplementedException(); + } + public IEnumerable EnumerateFileSystemEntries(string path) { foreach (var entry in _files.Keys.Where(k => Path.GetDirectoryName(k) == path)) diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs index 056b1c197..7de277852 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs @@ -15,6 +15,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities private static string s_buildRid; private string _artifacts; + private string _dotnetRoot; private string _builtDotnet; private string _nugetPackages; private string _stage2Sdk; @@ -85,6 +86,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities public string Artifacts => _artifacts; public string BuiltDotnet => _builtDotnet; + public string DotnetRoot => _dotnetRoot; public string NugetPackages => _nugetPackages; public string Stage2Sdk => _stage2Sdk; public string Stage2WithBackwardsCompatibleRuntimesDirectory => _stage2WithBackwardsCompatibleRuntimesDirectory; @@ -106,6 +108,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities previousStage.ToString(), BuildRid); _builtDotnet = builtDotnet ?? Path.Combine(_artifacts, "intermediate", "sharedFrameworkPublish"); + _dotnetRoot = Path.Combine(_artifacts, "dotnet"); _nugetPackages = nugetPackages ?? Path.Combine(RepoRoot, ".nuget", "packages"); _stage2Sdk = Directory .EnumerateDirectories(Path.Combine(_artifacts, "dotnet", "sdk")) @@ -117,7 +120,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities _testPackages = Environment.GetEnvironmentVariable("TEST_PACKAGES"); if (string.IsNullOrEmpty(_testPackages)) { - throw new InvalidOperationException("TEST_PACKAGES environment variable not set"); + _testPackages = Path.Combine(_artifacts, "test", "packages"); } _testWorkingFolder = Path.Combine(RepoRoot, diff --git a/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs b/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs index ff48ed8d2..36459d50d 100644 --- a/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs +++ b/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs @@ -40,6 +40,7 @@ SDK commands: vstest Runs Microsoft Test Execution Command Line Tool. store Stores the specified assemblies in the runtime store. tool Modify tools. + buildserver Interact with servers started by a build. help Show help. Common options: diff --git a/test/dotnet.Tests/BuildServerTests/RazorServerManagerTests.cs b/test/dotnet.Tests/BuildServerTests/RazorServerManagerTests.cs new file mode 100644 index 000000000..925f21179 --- /dev/null +++ b/test/dotnet.Tests/BuildServerTests/RazorServerManagerTests.cs @@ -0,0 +1,123 @@ +// 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 System.Threading.Tasks; +using FluentAssertions; +using Microsoft.Build.Exceptions; +using Microsoft.DotNet.BuildServer; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools; +using Microsoft.DotNet.Tools.Test.Utilities; +using Microsoft.Extensions.EnvironmentAbstractions; +using Moq; +using NuGet.Frameworks; +using Xunit; +using LocalizableStrings = Microsoft.DotNet.BuildServer.LocalizableStrings; + +namespace Microsoft.DotNet.Tests.BuildServerTests +{ + public class RazorServerManagerTests + { + [Fact] + public async Task GivenNoRazorAssemblyShutdownIsSkipped() + { + var resolverMock = new Mock(MockBehavior.Strict); + resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Returns(new FilePath[] {}); + + var commandFactoryMock = new Mock(MockBehavior.Strict); + + var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object); + + var result = await manager.ShutdownServerAsync(); + result.Kind.Should().Be(ResultKind.Skipped); + result.Message.Should().Be(LocalizableStrings.NoRazorProjectFound); + result.Exception.Should().BeNull(); + } + + [Fact] + public async Task GivenARazorAssemblyShutdownSucceeds() + { + const string FakeRazorAssemblyPath = "/path/to/razor.dll"; + + var resolverMock = new Mock(MockBehavior.Strict); + resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Returns(new FilePath[] { new FilePath(FakeRazorAssemblyPath) }); + + var commandMock = new Mock(MockBehavior.Strict); + commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object); + commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object); + commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 0, "", "")); + + var commandFactoryMock = new Mock(MockBehavior.Strict); + commandFactoryMock + .Setup( + f => f.Create( + "exec", + new string[] { FakeRazorAssemblyPath, "shutdown" }, + It.IsAny(), + Constants.DefaultConfiguration)) + .Returns(commandMock.Object); + + var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object); + + var result = await manager.ShutdownServerAsync(); + result.Kind.Should().Be(ResultKind.Success); + result.Message.Should().BeNull(); + result.Exception.Should().BeNull(); + } + + [Fact] + public async Task GivenAnInvalidProjectFileShutdownFails() + { + var exception = new InvalidProjectFileException("invalid project!"); + + var resolverMock = new Mock(MockBehavior.Strict); + resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Throws(exception); + + var commandFactoryMock = new Mock(MockBehavior.Strict); + + var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object); + + var result = await manager.ShutdownServerAsync(); + result.Kind.Should().Be(ResultKind.Failure); + result.Message.Should().Be(exception.Message); + result.Exception.Should().Be(exception); + } + + [Fact] + public async Task GivenANonZeroExitCodeShutdownFails() + { + const string FakeRazorAssemblyPath = "/path/to/razor.dll"; + const string ErrorMessage = "failed!"; + + var resolverMock = new Mock(MockBehavior.Strict); + resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Returns(new FilePath[] { new FilePath(FakeRazorAssemblyPath) }); + + var commandMock = new Mock(MockBehavior.Strict); + commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object); + commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object); + commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 1, "", ErrorMessage)); + + var commandFactoryMock = new Mock(MockBehavior.Strict); + commandFactoryMock + .Setup( + f => f.Create( + "exec", + new string[] { FakeRazorAssemblyPath, "shutdown" }, + It.IsAny(), + Constants.DefaultConfiguration)) + .Returns(commandMock.Object); + + var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object); + + var result = await manager.ShutdownServerAsync(); + result.Kind.Should().Be(ResultKind.Failure); + result.Message.Should().Be(ErrorMessage); + result.Exception.Should().BeNull(); + } + } +} diff --git a/test/dotnet.Tests/BuildServerTests/VBCSCompilerServerManagerTests.cs b/test/dotnet.Tests/BuildServerTests/VBCSCompilerServerManagerTests.cs new file mode 100644 index 000000000..01e156483 --- /dev/null +++ b/test/dotnet.Tests/BuildServerTests/VBCSCompilerServerManagerTests.cs @@ -0,0 +1,75 @@ +// 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.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.BuildServer; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools; +using Microsoft.Extensions.EnvironmentAbstractions; +using Moq; +using NuGet.Frameworks; +using Xunit; + +namespace Microsoft.DotNet.Tests.BuildServerTests +{ + public class VBCSCompilerServerManagerTests + { + [Fact] + public async Task GivenAZeroExit() + { + var commandMock = new Mock(MockBehavior.Strict); + commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object); + commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object); + commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 0, "", "")); + + var commandFactoryMock = new Mock(MockBehavior.Strict); + commandFactoryMock + .Setup( + f => f.Create( + "exec", + new string[] { VBCSCompilerServerManager.VBCSCompilerPath, "-shutdown" }, + It.IsAny(), + Constants.DefaultConfiguration)) + .Returns(commandMock.Object); + + var manager = new VBCSCompilerServerManager(commandFactoryMock.Object); + + var result = await manager.ShutdownServerAsync(); + result.Kind.Should().Be(ResultKind.Success); + result.Message.Should().BeNull(); + result.Exception.Should().BeNull(); + } + + [Fact] + public async Task GivenANonZeroExitCodeShutdownFails() + { + const string ErrorMessage = "failed!"; + + var commandMock = new Mock(MockBehavior.Strict); + commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object); + commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object); + commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 1, "", ErrorMessage)); + + var commandFactoryMock = new Mock(MockBehavior.Strict); + commandFactoryMock + .Setup( + f => f.Create( + "exec", + new string[] { VBCSCompilerServerManager.VBCSCompilerPath, "-shutdown" }, + It.IsAny(), + Constants.DefaultConfiguration)) + .Returns(commandMock.Object); + + var manager = new VBCSCompilerServerManager(commandFactoryMock.Object); + + var result = await manager.ShutdownServerAsync(); + result.Kind.Should().Be(ResultKind.Failure); + result.Message.Should().Be(ErrorMessage); + result.Exception.Should().BeNull(); + } + } +} diff --git a/test/dotnet.Tests/CommandTests/BuildServerShutdownCommandTests.cs b/test/dotnet.Tests/CommandTests/BuildServerShutdownCommandTests.cs new file mode 100644 index 000000000..795fe57d9 --- /dev/null +++ b/test/dotnet.Tests/CommandTests/BuildServerShutdownCommandTests.cs @@ -0,0 +1,222 @@ +// 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 System.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.BuildServer; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools.BuildServer; +using Microsoft.DotNet.Tools.BuildServer.Shutdown; +using Microsoft.DotNet.Tools.Test.Utilities; +using Moq; +using Xunit; +using Parser = Microsoft.DotNet.Cli.Parser; +using LocalizableStrings = Microsoft.DotNet.Tools.BuildServer.Shutdown.LocalizableStrings; + +namespace Microsoft.DotNet.Tests.Commands +{ + public class BuildServerShutdownCommandTests + { + private readonly BufferedReporter _reporter = new BufferedReporter(); + + [Fact] + public void GivenNoOptionsAllManagersArePresent() + { + var command = CreateCommand(); + + command.Managers.Select(m => m.ServerName).Should().Equal( + DotNet.BuildServer.LocalizableStrings.MSBuildServer, + DotNet.BuildServer.LocalizableStrings.VBCSCompilerServer, + DotNet.BuildServer.LocalizableStrings.RazorServer + ); + } + + [Fact] + public void GivenMSBuildOptionOnlyItIsTheOnlyManager() + { + var command = CreateCommand("--msbuild"); + + command.Managers.Select(m => m.ServerName).Should().Equal( + DotNet.BuildServer.LocalizableStrings.MSBuildServer + ); + } + + [Fact] + public void GivenVBCSCompilerOptionOnlyItIsTheOnlyManager() + { + var command = CreateCommand("--vbcscompiler"); + + command.Managers.Select(m => m.ServerName).Should().Equal( + DotNet.BuildServer.LocalizableStrings.VBCSCompilerServer + ); + } + + [Fact] + public void GivenRazorOptionOnlyItIsTheOnlyManager() + { + var command = CreateCommand("--razor"); + + command.Managers.Select(m => m.ServerName).Should().Equal( + DotNet.BuildServer.LocalizableStrings.RazorServer + ); + } + + [Fact] + public void GivenSuccessfulShutdownsItPrintsSuccess() + { + var mocks = new[] { + CreateManagerMock("first", new Result(ResultKind.Success)), + CreateManagerMock("second", new Result(ResultKind.Success)), + CreateManagerMock("third", new Result(ResultKind.Success)) + }; + + var command = CreateCommand(managers: mocks.Select(m => m.Object)); + + command.Execute().Should().Be(0); + + _reporter.Lines.Should().Equal( + FormatShuttingDownMessage(mocks[0].Object), + FormatShuttingDownMessage(mocks[1].Object), + FormatShuttingDownMessage(mocks[2].Object), + FormatSuccessMessage(mocks[0].Object), + FormatSuccessMessage(mocks[1].Object), + FormatSuccessMessage(mocks[2].Object)); + + VerifyShutdownCalls(mocks); + } + + [Fact] + public void GivenAFailingShutdownItPrintsFailureMessage() + { + const string FailureMessage = "failed!"; + + var mocks = new[] { + CreateManagerMock("first", new Result(ResultKind.Success)), + CreateManagerMock("second", new Result(ResultKind.Failure, FailureMessage)), + CreateManagerMock("third", new Result(ResultKind.Success)) + }; + + var command = CreateCommand(managers: mocks.Select(m => m.Object)); + + command.Execute().Should().Be(1); + + _reporter.Lines.Should().Equal( + FormatShuttingDownMessage(mocks[0].Object), + FormatShuttingDownMessage(mocks[1].Object), + FormatShuttingDownMessage(mocks[2].Object), + FormatSuccessMessage(mocks[0].Object), + FormatFailureMessage(mocks[1].Object, FailureMessage), + FormatSuccessMessage(mocks[2].Object)); + + VerifyShutdownCalls(mocks); + } + + [Fact] + public void GivenASkippedShutdownItPrintsSkipMessage() + { + const string SkipMessage = "skipped!"; + + var mocks = new[] { + CreateManagerMock("first", new Result(ResultKind.Success)), + CreateManagerMock("second", new Result(ResultKind.Success)), + CreateManagerMock("third", new Result(ResultKind.Skipped, SkipMessage)) + }; + + var command = CreateCommand(managers: mocks.Select(m => m.Object)); + + command.Execute().Should().Be(0); + + _reporter.Lines.Should().Equal( + FormatShuttingDownMessage(mocks[0].Object), + FormatShuttingDownMessage(mocks[1].Object), + FormatShuttingDownMessage(mocks[2].Object), + FormatSuccessMessage(mocks[0].Object), + FormatSuccessMessage(mocks[1].Object), + FormatSkippedMessage(mocks[2].Object, SkipMessage)); + + VerifyShutdownCalls(mocks); + } + + [Fact] + public void GivenSuccessFailureAndSkippedItPrintsAllThree() + { + const string FailureMessage = "failed!"; + const string SkipMessage = "skipped!"; + + var mocks = new[] { + CreateManagerMock("first", new Result(ResultKind.Success)), + CreateManagerMock("second", new Result(ResultKind.Failure, FailureMessage)), + CreateManagerMock("third", new Result(ResultKind.Skipped, SkipMessage)) + }; + + var command = CreateCommand(managers: mocks.Select(m => m.Object)); + + command.Execute().Should().Be(1); + + _reporter.Lines.Should().Equal( + FormatShuttingDownMessage(mocks[0].Object), + FormatShuttingDownMessage(mocks[1].Object), + FormatShuttingDownMessage(mocks[2].Object), + FormatSuccessMessage(mocks[0].Object), + FormatFailureMessage(mocks[1].Object, FailureMessage), + FormatSkippedMessage(mocks[2].Object, SkipMessage)); + + VerifyShutdownCalls(mocks); + } + + private BuildServerShutdownCommand CreateCommand(string options = "", IEnumerable managers = null) + { + ParseResult result = Parser.Instance.Parse("dotnet buildserver shutdown " + options); + return new BuildServerShutdownCommand( + options: result["dotnet"]["buildserver"]["shutdown"], + result: result, + managers: managers, + useOrderedWait: true, + reporter: _reporter); + } + + private Mock CreateManagerMock(string serverName, Result result) + { + var mock = new Mock(MockBehavior.Strict); + + mock.SetupGet(m => m.ServerName).Returns(serverName); + mock.Setup(m => m.ShutdownServerAsync()).Returns(Task.FromResult(result)); + + return mock; + } + + private void VerifyShutdownCalls(IEnumerable> mocks) + { + foreach (var mock in mocks) + { + mock.Verify(m => m.ShutdownServerAsync(), Times.Once()); + } + } + + private static string FormatShuttingDownMessage(IBuildServerManager manager) + { + return string.Format(LocalizableStrings.ShuttingDownServer, manager.ServerName); + } + + private static string FormatSuccessMessage(IBuildServerManager manager) + { + return string.Format(LocalizableStrings.ShutDownSucceeded, manager.ServerName).Green(); + } + + private static string FormatFailureMessage(IBuildServerManager manager, string message) + { + return string.Format(LocalizableStrings.ShutDownFailed, manager.ServerName, message).Red(); + } + + private static string FormatSkippedMessage(IBuildServerManager manager, string message) + { + return string.Format(LocalizableStrings.ShutDownSkipped, manager.ServerName, message).Cyan(); + } + } +} diff --git a/test/dotnet.Tests/CommandTests/ToolInstallCommandTests.cs b/test/dotnet.Tests/CommandTests/ToolInstallCommandTests.cs index 65ea11d13..05cca5f33 100644 --- a/test/dotnet.Tests/CommandTests/ToolInstallCommandTests.cs +++ b/test/dotnet.Tests/CommandTests/ToolInstallCommandTests.cs @@ -360,7 +360,7 @@ namespace Microsoft.DotNet.Tests.Commands a.ShouldThrow().And.Message .Should().Contain( LocalizableStrings.ToolInstallationRestoreFailed + - Environment.NewLine + string.Format(LocalizableStrings.ToolInstallationFailed, PackageId)); + Environment.NewLine + string.Format(LocalizableStrings.ToolInstallationFailedWithExplicitVersionGuide, PackageId)); _fileSystem.Directory.Exists(Path.Combine(PathToPlacePackages, PackageId)).Should().BeFalse(); } diff --git a/test/dotnet.Tests/ParserTests/BuildServerShutdownParserTests.cs b/test/dotnet.Tests/ParserTests/BuildServerShutdownParserTests.cs new file mode 100644 index 000000000..fb6e66bc1 --- /dev/null +++ b/test/dotnet.Tests/ParserTests/BuildServerShutdownParserTests.cs @@ -0,0 +1,78 @@ +// 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.Linq; +using FluentAssertions; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.CommandLine; +using Xunit; +using Xunit.Abstractions; +using Parser = Microsoft.DotNet.Cli.Parser; + +namespace Microsoft.DotNet.Tests.ParserTests +{ + public class BuildServerShutdownParserTests + { + private readonly ITestOutputHelper output; + + public BuildServerShutdownParserTests(ITestOutputHelper output) + { + this.output = output; + } + + [Fact] + public void GivenNoOptionsAllFlagsAreFalse() + { + var result = Parser.Instance.Parse("dotnet buildserver shutdown"); + + var options = result["dotnet"]["buildserver"]["shutdown"]; + options.ValueOrDefault("msbuild").Should().Be(false); + options.ValueOrDefault("vbcscompiler").Should().Be(false); + options.ValueOrDefault("razor").Should().Be(false); + } + + [Fact] + public void GivenMSBuildOptionIsItTrue() + { + var result = Parser.Instance.Parse("dotnet buildserver shutdown --msbuild"); + + var options = result["dotnet"]["buildserver"]["shutdown"]; + options.ValueOrDefault("msbuild").Should().Be(true); + options.ValueOrDefault("vbcscompiler").Should().Be(false); + options.ValueOrDefault("razor").Should().Be(false); + } + + [Fact] + public void GivenVBCSCompilerOptionIsItTrue() + { + var result = Parser.Instance.Parse("dotnet buildserver shutdown --vbcscompiler"); + + var options = result["dotnet"]["buildserver"]["shutdown"]; + options.ValueOrDefault("msbuild").Should().Be(false); + options.ValueOrDefault("vbcscompiler").Should().Be(true); + options.ValueOrDefault("razor").Should().Be(false); + } + + [Fact] + public void GivenRazorOptionIsItTrue() + { + var result = Parser.Instance.Parse("dotnet buildserver shutdown --razor"); + + var options = result["dotnet"]["buildserver"]["shutdown"]; + options.ValueOrDefault("msbuild").Should().Be(false); + options.ValueOrDefault("vbcscompiler").Should().Be(false); + options.ValueOrDefault("razor").Should().Be(true); + } + + [Fact] + public void GivenMultipleOptionsThoseAreTrue() + { + var result = Parser.Instance.Parse("dotnet buildserver shutdown --razor --msbuild"); + + var options = result["dotnet"]["buildserver"]["shutdown"]; + options.ValueOrDefault("msbuild").Should().Be(true); + options.ValueOrDefault("vbcscompiler").Should().Be(false); + options.ValueOrDefault("razor").Should().Be(true); + } + } +} diff --git a/testAsset.props b/testAsset.props index b130414b8..8d003d8ab 100644 --- a/testAsset.props +++ b/testAsset.props @@ -1,4 +1,8 @@ + + $(MSBuildThisFileDirectory) + + $(TEST_PACKAGES)