From 5218c4bcf52441075ca4d5b8fa7ed860c99ea454 Mon Sep 17 00:00:00 2001 From: William Li Date: Sun, 24 Jun 2018 11:32:44 -0700 Subject: [PATCH] Pass BaseIntermediateOutputPath via xml (#9509) Instead of command line to avoid escaping problem. It can support most of the character including surrogate char. It cannot support semicolon. However, semicolon is not allow to be part of the user name. Port 2.1.4xx fix 0251f677ede571b61a47ca24f38df8e09038277d while keep BaseIntermediateOutputPath instead of MsBuildProjectExtensionsPath to minimize the change. --- src/dotnet/ToolPackage/IProjectRestorer.cs | 1 - .../ToolPackage/ToolPackageInstaller.cs | 17 +++++++--- .../dotnet-tool/install/ProjectRestorer.cs | 4 +-- .../ToolPackageInstallerTests.cs | 34 ++++++++++++++++++- .../ProjectRestorerMock.cs | 9 ++--- .../ToolPackageInstallerMock.cs | 3 +- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/dotnet/ToolPackage/IProjectRestorer.cs b/src/dotnet/ToolPackage/IProjectRestorer.cs index 0546c399a..343681f8d 100644 --- a/src/dotnet/ToolPackage/IProjectRestorer.cs +++ b/src/dotnet/ToolPackage/IProjectRestorer.cs @@ -9,7 +9,6 @@ namespace Microsoft.DotNet.ToolPackage internal interface IProjectRestorer { void Restore(FilePath project, - DirectoryPath assetJsonOutput, FilePath? nugetConfig = null, string verbosity = null); } diff --git a/src/dotnet/ToolPackage/ToolPackageInstaller.cs b/src/dotnet/ToolPackage/ToolPackageInstaller.cs index 14ea51d25..0814bc601 100644 --- a/src/dotnet/ToolPackage/ToolPackageInstaller.cs +++ b/src/dotnet/ToolPackage/ToolPackageInstaller.cs @@ -55,6 +55,7 @@ namespace Microsoft.DotNet.ToolPackage versionRange: versionRange, targetFramework: targetFramework ?? BundledTargetFramework.GetTargetFrameworkMoniker(), restoreDirectory: stageDirectory, + assetJsonOutputDirectory: stageDirectory, rootConfigDirectory: rootConfigDirectory, additionalFeeds: additionalFeeds); @@ -62,7 +63,6 @@ namespace Microsoft.DotNet.ToolPackage { _projectRestorer.Restore( tempProject, - stageDirectory, nugetConfig, verbosity: verbosity); } @@ -117,6 +117,7 @@ namespace Microsoft.DotNet.ToolPackage VersionRange versionRange, string targetFramework, DirectoryPath restoreDirectory, + DirectoryPath assetJsonOutputDirectory, DirectoryPath? rootConfigDirectory, string[] additionalFeeds) { @@ -133,7 +134,12 @@ namespace Microsoft.DotNet.ToolPackage var tempProjectContent = new XDocument( new XElement("Project", - new XAttribute("Sdk", "Microsoft.NET.Sdk"), + new XElement("PropertyGroup", + new XElement("BaseIntermediateOutputPath", assetJsonOutputDirectory.Value)), // change the output directory of asset.json + // due to https://github.com/Microsoft/msbuild/issues/1603 -- import SDK after setting BaseIntermediateOutputPath + new XElement(("Import"), + new XAttribute("Project", "Sdk.props"), + new XAttribute("Sdk", "Microsoft.NET.Sdk")), new XElement("PropertyGroup", new XElement("TargetFramework", targetFramework), new XElement("RestorePackagesPath", restoreDirectory.Value), @@ -149,9 +155,10 @@ namespace Microsoft.DotNet.ToolPackage new XElement("PackageReference", new XAttribute("Include", packageId.ToString()), new XAttribute("Version", - versionRange?.ToString("S", new VersionRangeFormatter()) ?? "*") // nuget will restore latest stable for * - )) - )); + versionRange?.ToString("S", new VersionRangeFormatter()) ?? "*"))), // nuget will restore latest stable for * + new XElement(("Import"), + new XAttribute("Project", "Sdk.targets"), + new XAttribute("Sdk", "Microsoft.NET.Sdk")))); File.WriteAllText(tempProject.Value, tempProjectContent.ToString()); return tempProject; diff --git a/src/dotnet/commands/dotnet-tool/install/ProjectRestorer.cs b/src/dotnet/commands/dotnet-tool/install/ProjectRestorer.cs index 7d0096b57..83ccd6f34 100644 --- a/src/dotnet/commands/dotnet-tool/install/ProjectRestorer.cs +++ b/src/dotnet/commands/dotnet-tool/install/ProjectRestorer.cs @@ -27,7 +27,6 @@ namespace Microsoft.DotNet.Tools.Tool.Install } public void Restore(FilePath project, - DirectoryPath assetJsonOutput, FilePath? nugetConfig = null, string verbosity = null) { @@ -43,8 +42,7 @@ namespace Microsoft.DotNet.Tools.Tool.Install argsToPassToRestore.AddRange(new List { "--runtime", - AnyRid, - $"-property:BaseIntermediateOutputPath={assetJsonOutput.ToXmlEncodeString()}" + AnyRid }); argsToPassToRestore.Add($"-verbosity:{verbosity ?? "quiet"}"); diff --git a/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageInstallerTests.cs b/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageInstallerTests.cs index 1b4dcadbd..e40c98c68 100644 --- a/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageInstallerTests.cs +++ b/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageInstallerTests.cs @@ -1,8 +1,9 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// 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.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -16,8 +17,10 @@ using Microsoft.DotNet.Tools.Tool.Install; using Microsoft.DotNet.Tools.Tests.ComponentMocks; using Microsoft.Extensions.DependencyModel.Tests; using Microsoft.Extensions.EnvironmentAbstractions; +using Microsoft.TemplateEngine.Cli; using NuGet.Versioning; using Xunit; +using LocalizableStrings = Microsoft.DotNet.Tools.Tool.Install.LocalizableStrings; namespace Microsoft.DotNet.ToolPackage.Tests { @@ -612,6 +615,35 @@ namespace Microsoft.DotNet.ToolPackage.Tests package.Uninstall(); } + [Fact] + public void GivenARootWithNonAsciiCharactorInstallSucceeds() + { + var nugetConfigPath = WriteNugetConfigFileToPointToTheFeed(); + + var surrogate = char.ConvertFromUtf32(int.Parse("2A601", NumberStyles.HexNumber)); + string nonAscii = "ab Ṱ̺̺̕o 田中さん åä," + surrogate; + + var root = new DirectoryPath(Path.Combine(TempRoot.Root, nonAscii, Path.GetRandomFileName())); + var reporter = new BufferedReporter(); + var fileSystem = new FileSystemWrapper(); + var store = new ToolPackageStore(root); + var installer = new ToolPackageInstaller( + store: store, + projectRestorer: new ProjectRestorer(reporter), + tempProject: GetUniqueTempProjectPathEachTest(), + offlineFeed: new DirectoryPath("does not exist")); + + var package = installer.InstallPackage( + packageId: TestPackageId, + versionRange: VersionRange.Parse(TestPackageVersion), + targetFramework: _testTargetframework, + nugetConfig: nugetConfigPath); + + AssertPackageInstall(reporter, fileSystem, package, store); + + package.Uninstall(); + } + private static void AssertPackageInstall( BufferedReporter reporter, IFileSystem fileSystem, diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ProjectRestorerMock.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ProjectRestorerMock.cs index 7d7f34849..a7548a484 100644 --- a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ProjectRestorerMock.cs +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ProjectRestorerMock.cs @@ -57,19 +57,19 @@ namespace Microsoft.DotNet.Tools.Tests.ComponentMocks } public void Restore(FilePath project, - DirectoryPath assetJsonOutput, FilePath? nugetConfig = null, string verbosity = null) { string packageId; VersionRange versionRange; string targetFramework; + DirectoryPath assetJsonOutput; try { - // The mock installer wrote a mock project file containing id:version:framework + // The mock installer wrote a mock project file containing id;version;framework;stageDirectory var contents = _fileSystem.File.ReadAllText(project.Value); - var tokens = contents.Split(':'); - if (tokens.Length != 3) + var tokens = contents.Split(';'); + if (tokens.Length != 4) { throw new ToolPackageException(LocalizableStrings.ToolInstallationRestoreFailed); } @@ -77,6 +77,7 @@ namespace Microsoft.DotNet.Tools.Tests.ComponentMocks packageId = tokens[0]; versionRange = VersionRange.Parse(tokens[1]); targetFramework = tokens[2]; + assetJsonOutput = new DirectoryPath(tokens[3]); } catch (IOException) { diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageInstallerMock.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageInstallerMock.cs index 9737ff858..6b28de63b 100644 --- a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageInstallerMock.cs +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageInstallerMock.cs @@ -63,12 +63,11 @@ namespace Microsoft.DotNet.Tools.Tests.ComponentMocks // Write a fake project with the requested package id, version, and framework _fileSystem.File.WriteAllText( tempProject.Value, - $"{packageId}:{versionRange?.ToString("S", new VersionRangeFormatter()) ?? "*"}:{targetFramework}"); + $"{packageId};{versionRange?.ToString("S", new VersionRangeFormatter()) ?? "*"};{targetFramework};{stageDirectory.Value}"); // Perform a restore on the fake project _projectRestorer.Restore( tempProject, - stageDirectory, nugetConfig, verbosity);