diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 4b341ed9a..0988307b9 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -22,12 +22,15 @@ 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 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 2e8ac9665..f8f05d130 100644 --- a/build/DependencyVersions.props +++ b/build/DependencyVersions.props @@ -14,7 +14,7 @@ $(MicrosoftCodeAnalysisCSharpPackageVersion) $(MicrosoftCodeAnalysisCSharpPackageVersion) $(MicrosoftCodeAnalysisCSharpPackageVersion) - 2.1.300-preview2-62730-09 + 2.1.300-preview2-62731-04 $(MicrosoftNETSdkPackageVersion) $(MicrosoftAspNetCoreAppPackageVersion) 2.1.300-preview2-20180330-1538569 diff --git a/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHost.cs b/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHost.cs new file mode 100644 index 000000000..7a91b6f2f --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/EmbedAppNameInHost.cs @@ -0,0 +1,145 @@ +// 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); + public static void EmbedAndReturnModifiedAppHostPath( + string appHostSourceFilePath, + string appHostDestinationFilePath, + string appBinaryName) + { + var hostExtension = Path.GetExtension(appHostSourceFilePath); + var appbaseName = Path.GetFileNameWithoutExtension(appBinaryName); + var bytesToWrite = Encoding.UTF8.GetBytes(appBinaryName); + 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, appBinaryName)); + } + + 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 de2a584df..f0a9fefbe 100644 --- a/src/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs +++ b/src/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs @@ -142,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 004d7a214..435a26de9 100644 --- a/src/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx +++ b/src/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx @@ -265,4 +265,10 @@ MSBuild arguments: {0} - \ No newline at end of file + + 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 015c486f0..e344ea524 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf @@ -249,6 +249,16 @@ 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 7af64fb1b..61e4513d5 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf @@ -249,6 +249,16 @@ 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 96ea5c325..6c204f324 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf @@ -249,6 +249,16 @@ 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 49dee1f7d..88aad3035 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf @@ -249,6 +249,16 @@ 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 662b786dc..ca4052e06 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf @@ -249,6 +249,16 @@ 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 b21a43542..b4a5d5c52 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf @@ -249,6 +249,16 @@ 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 7cb60bcbc..9dfca8978 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf @@ -249,6 +249,16 @@ 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 6aaade6a0..ef52ffcc3 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf @@ -249,6 +249,16 @@ 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 fc793c1b6..fd20f0ffa 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf @@ -249,6 +249,16 @@ 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 7b1978f56..35d41a676 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf @@ -249,6 +249,16 @@ 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 a3787c97a..b1afa5763 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf @@ -249,6 +249,16 @@ 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 83a234d5a..c30d33e41 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf @@ -249,6 +249,16 @@ 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 a6241b6d0..d56372b1f 100644 --- a/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf @@ -249,6 +249,16 @@ 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/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/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..6fcdf9c11 100644 --- a/src/dotnet/ShellShim/ShellShimRepository.cs +++ b/src/dotnet/ShellShim/ShellShimRepository.cs @@ -6,25 +6,27 @@ 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.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 +49,8 @@ namespace Microsoft.DotNet.ShellShim } TransactionalAction.Run( - action: () => { + action: () => + { try { if (!Directory.Exists(_shimsDirectory.Value)) @@ -55,29 +58,13 @@ namespace Microsoft.DotNet.ShellShim Directory.CreateDirectory(_shimsDirectory.Value); } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + CreateApphostShimAndConfigFile( + 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 +125,43 @@ namespace Microsoft.DotNet.ShellShim }); } - internal void CreateConfigFile(FilePath outputPath, FilePath entryPoint, string runner) + private void CreateApphostShimAndConfigFile(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); + EmbedAppNameInHost.EmbedAndReturnModifiedAppHostPath( + appHostSourceFilePath: appHostSourcePath, + appHostDestinationFilePath: GetShimPath(commandName).Value, + appBinaryName: Path.GetFileName(entryPoint.Value)); + + var config = JsonConvert.SerializeObject( + new RootObject + { + startupOptions = new StartupOptions + { + appRoot = entryPoint.GetDirectoryPath().Value + } + }); + + File.WriteAllText(GetConfigPath(commandName).Value, config); + } + + private class StartupOptions + { + public string appRoot { get; set; } + } + + private class RootObject + { + public StartupOptions startupOptions { get; set; } } private bool ShimExists(string commandName) @@ -164,30 +176,25 @@ namespace Microsoft.DotNet.ShellShim yield break; } + yield return GetShimPath(commandName); + yield return GetConfigPath(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) + private FilePath GetConfigPath(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"); + return _shimsDirectory.WithFile(commandName + ".startupconfig.json"); } private static void SetUserExecutionPermission(FilePath path) diff --git a/src/dotnet/ShellShim/WindowsEnvironmentPath.cs b/src/dotnet/ShellShim/WindowsEnvironmentPath.cs index da16b02c7..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,17 +30,37 @@ namespace Microsoft.DotNet.ShellShim return; } - var existingUserEnvPath = Environment.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.User); + var existingUserEnvPath = _environmentProvider.GetEnvironmentVariable(PathName, EnvironmentVariableTarget.User); - if (existingUserEnvPath.EndsWith(';')) + try { - existingUserEnvPath = existingUserEnvPath.Substring(0, (existingUserEnvPath.Length - 1)); - } + if (existingUserEnvPath == null) + { + _environmentProvider.SetEnvironmentVariable( + PathName, + _packageExecutablePath, + EnvironmentVariableTarget.User); + } + else + { + if (existingUserEnvPath.EndsWith(';')) + { + existingUserEnvPath = existingUserEnvPath.Substring(0, (existingUserEnvPath.Length - 1)); + } - Environment.SetEnvironmentVariable( - PathName, - $"{existingUserEnvPath};{_packageExecutablePath}", - EnvironmentVariableTarget.User); + _environmentProvider.SetEnvironmentVariable( + PathName, + $"{existingUserEnvPath};{_packageExecutablePath}", + EnvironmentVariableTarget.User); + } + } + catch (System.Security.SecurityException) + { + _reporter.WriteLine( + string.Format( + CommonLocalizableStrings.FailedToSetToolsPathEnvironmentVariable, + _packageExecutablePath).Yellow()); + } } private bool PackageExecutablePathExists() @@ -51,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) @@ -67,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-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 ecbfee407..b7d26a073 100644 --- a/src/dotnet/dotnet.csproj +++ b/src/dotnet/dotnet.csproj @@ -79,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 65bd1e2a9..bc22fcf3f 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/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.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/RepoDirectoriesProvider.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs index b68df6b4f..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")) 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/testAsset.props b/testAsset.props index b130414b8..8d003d8ab 100644 --- a/testAsset.props +++ b/testAsset.props @@ -1,4 +1,8 @@ + + $(MSBuildThisFileDirectory) + + $(TEST_PACKAGES)