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.
This commit is contained in:
William Li 2018-06-24 11:32:44 -07:00 committed by GitHub
parent dc2443ca74
commit 5218c4bcf5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 52 additions and 16 deletions

View file

@ -9,7 +9,6 @@ namespace Microsoft.DotNet.ToolPackage
internal interface IProjectRestorer
{
void Restore(FilePath project,
DirectoryPath assetJsonOutput,
FilePath? nugetConfig = null,
string verbosity = null);
}

View file

@ -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;

View file

@ -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<string>
{
"--runtime",
AnyRid,
$"-property:BaseIntermediateOutputPath={assetJsonOutput.ToXmlEncodeString()}"
AnyRid
});
argsToPassToRestore.Add($"-verbosity:{verbosity ?? "quiet"}");

View file

@ -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,

View file

@ -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)
{

View file

@ -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);