Fix P2P migration

Fixes #4269 by deep cloning the MsbuildTemplateProject for each P2P reference. Add test which migrates and builds P2P references.
This commit is contained in:
Sridhar Periyasamy 2016-10-03 10:58:32 -07:00
parent 09e8877bd4
commit a396630576
27 changed files with 201 additions and 54 deletions

View file

@ -0,0 +1,17 @@
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworkIdentifier>.NETStandard</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v1.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="$(GlobalExclude)" />
<EmbeddedResource Include="**\*.resx" Exclude="$(GlobalExclude)" />
<None Include="project.json" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -5,11 +5,11 @@ using System;
namespace TestLibrary namespace TestLibrary
{ {
public static class ProjectE public static class ProjectC
{ {
public static string GetMessage() public static string GetMessage()
{ {
return "This string came from ProjectF"; return "This string came from CsprojLibrary1";
} }
} }
} }

View file

@ -0,0 +1,11 @@
{
"dependencies": {},
"frameworks": {
"netstandard1.5": {
"dependencies": {
"Microsoft.NETCore.Sdk": "1.0.0-alpha-20160923-4",
"NETStandard.Library": "1.6.0"
}
}
}
}

View file

@ -0,0 +1,17 @@
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworkIdentifier>.NETStandard</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v1.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="$(GlobalExclude)" />
<EmbeddedResource Include="**\*.resx" Exclude="$(GlobalExclude)" />
<None Include="project.json" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace TestLibrary
{
public static class ProjectC
{
public static string GetMessage()
{
return "This string came from CsprojLibrary2";
}
}
}

View file

@ -0,0 +1,11 @@
{
"dependencies": {},
"frameworks": {
"netstandard1.5": {
"dependencies": {
"Microsoft.NETCore.Sdk": "1.0.0-alpha-20160923-4",
"NETStandard.Library": "1.6.0"
}
}
}
}

View file

@ -0,0 +1,17 @@
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworkIdentifier>.NETStandard</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v1.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="$(GlobalExclude)" />
<EmbeddedResource Include="**\*.resx" Exclude="$(GlobalExclude)" />
<None Include="project.json" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace TestLibrary
{
public static class ProjectC
{
public static string GetMessage()
{
return "This string came from CsprojLibrary3";
}
}
}

View file

@ -0,0 +1,11 @@
{
"dependencies": {},
"frameworks": {
"netstandard1.5": {
"dependencies": {
"Microsoft.NETCore.Sdk": "1.0.0-alpha-20160923-4",
"NETStandard.Library": "1.6.0"
}
}
}
}

View file

@ -11,7 +11,7 @@ namespace TestApp
public static int Main(string[] args) public static int Main(string[] args)
{ {
Console.WriteLine("This string came from ProjectA"); Console.WriteLine("This string came from ProjectA");
return 100; return 0;
} }
} }
} }

View file

@ -16,8 +16,8 @@
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\ClassLibrary1\ClassLibrary1.csproj" /> <ProjectReference Include="..\CsprojLibrary1\CsprojLibrary1.csproj" />
<ProjectReference Include="..\..\ClassLibrary2\ClassLibrary2.csproj" /> <ProjectReference Include="..\CsprojLibrary2\CsprojLibrary2.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View file

@ -18,10 +18,10 @@
"target": "project", "target": "project",
"version": "1.0.0-*" "version": "1.0.0-*"
}, },
"ClassLibrary1": { "CsprojLibrary1": {
"target": "project" "target": "project"
}, },
"ClassLibrary2": { "CsprojLibrary2": {
"target": "project" "target": "project"
}, },
"NETStandard.Library": "1.6.0" "NETStandard.Library": "1.6.0"

View file

@ -16,8 +16,8 @@
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\ClassLibrary2\ClassLibrary2.csproj" /> <ProjectReference Include="..\CsprojLibrary2\CsprojLibrary2.csproj" />
<ProjectReference Include="..\..\ClassLibrary3\ClassLibrary3.csproj" /> <ProjectReference Include="..\CsprojLibrary3\CsprojLibrary3.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View file

@ -10,10 +10,10 @@
] ]
}, },
"dependencies": { "dependencies": {
"ClassLibrary2": { "CsprojLibrary2": {
"target": "project" "target": "project"
}, },
"ClassLibrary3": { "CsprojLibrary3": {
"target": "project" "target": "project"
}, },
"NETStandard.Library": "1.6.0" "NETStandard.Library": "1.6.0"

View file

@ -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;
using System.Diagnostics;
namespace TestApp
{
public class Program
{
public static int Main(string[] args)
{
Console.WriteLine("This string came from ProjectF");
string helperStr = TestLibrary.ProjectG.GetMessage();
Console.WriteLine(helperStr);
return 0;
}
}
}

View file

@ -1,22 +1,20 @@
{ {
"version": "1.0.0-*", "version": "1.0.0-*",
"buildOptions": { "buildOptions": {
"nowarn": [ "emitEntryPoint": true,
"CS1591" "preserveCompilationContext": true
],
"xmlDoc": true,
"additionalArguments": [
"-highentropyva+"
]
}, },
"dependencies": { "dependencies": {
"ProjectG": { "ProjectG": {
"target": "project", "target": "project",
"version": "1.0.0-*" "version": "1.0.0-*"
}, },
"NETStandard.Library": "1.6.0" "Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.1"
}
}, },
"frameworks": { "frameworks": {
"netstandard1.5": {} "netcoreapp1.0": {}
} }
} }

View file

@ -5,7 +5,7 @@ using System;
namespace TestLibrary namespace TestLibrary
{ {
public static class ProjectE public static class ProjectG
{ {
public static string GetMessage() public static string GetMessage()
{ {

View file

@ -15,7 +15,7 @@ using NuGet.LibraryModel;
namespace Microsoft.DotNet.ProjectJsonMigration namespace Microsoft.DotNet.ProjectJsonMigration
{ {
internal class ProjectDependencyFinder public class ProjectDependencyFinder
{ {
public IEnumerable<ProjectDependency> ResolveProjectDependencies(string projectDir, string xprojFile = null) public IEnumerable<ProjectDependency> ResolveProjectDependencies(string projectDir, string xprojFile = null)
{ {
@ -43,6 +43,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
} }
} }
} }
public IEnumerable<ProjectDependency> ResolveProjectDependenciesForFramework( public IEnumerable<ProjectDependency> ResolveProjectDependenciesForFramework(
Project project, Project project,
NuGetFramework framework, NuGetFramework framework,
@ -104,10 +105,14 @@ namespace Microsoft.DotNet.ProjectJsonMigration
var projectExportName = projectExport.Library.Identity.Name; var projectExportName = projectExport.Library.Identity.Name;
ProjectDependency projectDependency; ProjectDependency projectDependency;
if (preResolvedProjects.Contains(projectExportName))
{
continue;
}
if (!possibleProjectDependencies.TryGetValue(projectExportName, out projectDependency)) if (!possibleProjectDependencies.TryGetValue(projectExportName, out projectDependency))
{ {
if (projectExport.Library.Identity.Type.Equals(LibraryType.Project) if (projectExport.Library.Identity.Type.Equals(LibraryType.Project))
&& !preResolvedProjects.Contains(projectExportName))
{ {
MigrationErrorCodes MigrationErrorCodes
.MIGRATE1014($"Unresolved project dependency ({projectExportName})").Throw(); .MIGRATE1014($"Unresolved project dependency ({projectExportName})").Throw();

View file

@ -35,6 +35,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration
Exception exc = null; Exception exc = null;
IEnumerable<ProjectDependency> projectDependencies = null; IEnumerable<ProjectDependency> projectDependencies = null;
var tempMSBuildProjectTemplate = rootSettings.MSBuildProjectTemplate.DeepClone();
try try
{ {
projectDependencies = ResolveTransitiveClosureProjectDependencies( projectDependencies = ResolveTransitiveClosureProjectDependencies(
@ -66,7 +68,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
var settings = new MigrationSettings(projectDir, var settings = new MigrationSettings(projectDir,
projectDir, projectDir,
rootSettings.SdkPackageVersion, rootSettings.SdkPackageVersion,
rootSettings.MSBuildProjectTemplate); tempMSBuildProjectTemplate.DeepClone());
MigrateProject(settings); MigrateProject(settings);
} }
} }

View file

@ -153,8 +153,6 @@ namespace Microsoft.DotNet.Migration.Tests
var projectDirectory = var projectDirectory =
TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.RefsTest").Path; TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.RefsTest").Path;
FixUpProjectJsons(projectDirectory);
MigrateProject(Path.Combine(projectDirectory, projectName)); MigrateProject(Path.Combine(projectDirectory, projectName));
string[] migratedProjects = expectedProjects.Split(new char[] { ',' }); string[] migratedProjects = expectedProjects.Split(new char[] { ',' });
@ -172,8 +170,6 @@ namespace Microsoft.DotNet.Migration.Tests
var projectDirectory = var projectDirectory =
TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.SkipRefsTest").Path; TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.SkipRefsTest").Path;
FixUpProjectJsons(projectDirectory);
MigrateCommand.Run(new [] { Path.Combine(projectDirectory, projectName), "--skip-project-references" }).Should().Be(0); MigrateCommand.Run(new [] { Path.Combine(projectDirectory, projectName), "--skip-project-references" }).Should().Be(0);
VerifyMigration(Enumerable.Repeat(projectName, 1), projectDirectory); VerifyMigration(Enumerable.Repeat(projectName, 1), projectDirectory);
@ -186,8 +182,6 @@ namespace Microsoft.DotNet.Migration.Tests
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}").Path; var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}").Path;
FixUpProjectJsons(projectDirectory);
if (skipRefs) if (skipRefs)
{ {
MigrateCommand.Run(new [] { projectDirectory, "--skip-project-references" }).Should().Be(0); MigrateCommand.Run(new [] { projectDirectory, "--skip-project-references" }).Should().Be(0);
@ -206,8 +200,6 @@ namespace Microsoft.DotNet.Migration.Tests
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path;
FixUpProjectJsons(projectDirectory);
var project = Path.Combine(projectDirectory, "ProjectA", "project.json"); var project = Path.Combine(projectDirectory, "ProjectA", "project.json");
MigrateCommand.Run(new [] { project }).Should().Be(0); MigrateCommand.Run(new [] { project }).Should().Be(0);
@ -215,21 +207,31 @@ namespace Microsoft.DotNet.Migration.Tests
VerifyMigration(migratedProjects, projectDirectory); VerifyMigration(migratedProjects, projectDirectory);
} }
private void FixUpProjectJsons(string projectDirectory) [Fact]
// regression test for https://github.com/dotnet/cli/issues/4269
public void It_migrates_and_builds_P2P_references()
{ {
var pjs = Directory.EnumerateFiles(projectDirectory, "project.json.1", SearchOption.AllDirectories); var assetsDir = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").WithLockFiles().Path;
var projectDirectory = Path.Combine(assetsDir, "ProjectF");
var depProjects = new List<string>() { Path.Combine(assetsDir, "ProjectG") };
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, "ProjectF", depProjects);
foreach(var pj in pjs) var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs
.SetEquals(outputComparisonData.MSBuildBuildOutputs);
if (!outputsIdentical)
{ {
var newPj = pj.Replace("project.json.1", "project.json"); OutputDiagnostics(outputComparisonData);
File.Move(pj, newPj);
} }
outputsIdentical.Should().BeTrue();
VerifyAllMSBuildOutputsRunnable(projectDirectory);
} }
private void VerifyMigration(IEnumerable<string> expectedProjects, string rootDir) private void VerifyMigration(IEnumerable<string> expectedProjects, string rootDir)
{ {
var migratedProjects = Directory.EnumerateFiles(rootDir, "*.csproj", SearchOption.AllDirectories) var migratedProjects = Directory.EnumerateFiles(rootDir, "project.migrated.json", SearchOption.AllDirectories)
.Select(s => Path.GetFileNameWithoutExtension(s)); .Select(s => Path.GetFileName(Path.GetDirectoryName(s)));
migratedProjects.Should().BeEquivalentTo(expectedProjects); migratedProjects.Should().BeEquivalentTo(expectedProjects);
} }
@ -272,7 +274,7 @@ namespace Microsoft.DotNet.Migration.Tests
} }
} }
private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, string projectName=null) private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, string projectName, List<string> additonalRestoreDirectories = null)
{ {
BuildProjectJson(projectDirectory); BuildProjectJson(projectDirectory);
var projectJsonBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory)); var projectJsonBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));
@ -285,6 +287,13 @@ namespace Microsoft.DotNet.Migration.Tests
DeleteXproj(projectDirectory); DeleteXproj(projectDirectory);
Restore3(projectDirectory, projectName); Restore3(projectDirectory, projectName);
additonalRestoreDirectories = additonalRestoreDirectories ?? new List<string>();
foreach(var dir in additonalRestoreDirectories)
{
Restore3(dir);
}
BuildMSBuild(projectDirectory, projectName); BuildMSBuild(projectDirectory, projectName);
var msbuildBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory)); var msbuildBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));