From ef906673758f51b8b8c9468b27eef970144afe5c Mon Sep 17 00:00:00 2001 From: Livar Cunha Date: Thu, 3 Nov 2016 16:54:15 -0700 Subject: [PATCH] Hoisting FrameworkAssemblies for desktop frameworks during migration. --- .../ProjectA/.noautobuild | 0 .../ProjectA/Program.cs | 19 ++++++ .../ProjectA/project.json | 31 ++++++++++ .../ProjectB/.noautobuild | 0 .../ProjectB/Helper.cs | 15 +++++ .../ProjectB/project.json | 23 ++++++++ .../Rules/MigrateProjectDependenciesRule.cs | 59 +++++++++++++++++++ ...enThatIWantToMigrateProjectDependencies.cs | 33 ++++++++++- 8 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/.noautobuild create mode 100644 TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/Program.cs create mode 100644 TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/project.json create mode 100644 TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/.noautobuild create mode 100644 TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/Helper.cs create mode 100644 TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/project.json diff --git a/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/.noautobuild b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/Program.cs b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/Program.cs new file mode 100644 index 000000000..1d1f78b84 --- /dev/null +++ b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/Program.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; +using System.Diagnostics; +using TestLibrary; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("This string came from ProjectA"); + Console.WriteLine($"{ProjectD.GetMessage()}"); + return 0; + } + } +} diff --git a/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/project.json b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/project.json new file mode 100644 index 000000000..3c9535c54 --- /dev/null +++ b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectA/project.json @@ -0,0 +1,31 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectB": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": "1.0.1" + }, + "frameworks": { + "netcoreapp1.0": {}, + "net451": {} + }, + "runtimes": { + "win7-x64": {}, + "win7-x86": {}, + "osx.10.10-x64": {}, + "osx.10.11-x64": {}, + "ubuntu.14.04-x64": {}, + "ubuntu.16.04-x64": {}, + "centos.7-x64": {}, + "rhel.7.2-x64": {}, + "debian.8-x64": {}, + "fedora.23-x64": {}, + "opensuse.13.2-x64": {} + } +} diff --git a/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/.noautobuild b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/Helper.cs b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/Helper.cs new file mode 100644 index 000000000..5a986d891 --- /dev/null +++ b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/Helper.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace TestLibrary +{ + public static class ProjectB + { + public static string GetMessage() + { + return "This string came from ProjectB"; + } + } +} diff --git a/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/project.json b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/project.json new file mode 100644 index 000000000..0e9d0db62 --- /dev/null +++ b/TestAssets/DesktopTestProjects/TestAppWithFrameworkAssemblies/ProjectB/project.json @@ -0,0 +1,23 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "nowarn": [ + "CS1591" + ], + "xmlDoc": true, + "additionalArguments": [ + "-highentropyva+" + ] + }, + "dependencies": { + "NETStandard.Library": "1.6.0" + }, + "frameworks": { + "netstandard1.5": {}, + "net451": { + "frameworkAssemblies": { + "System.ComponentModel.DataAnnotations": "" + } + } + } +} diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs index a0db963e8..1ac8aaa9e 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs @@ -10,6 +10,7 @@ using Microsoft.DotNet.ProjectJsonMigration.Transforms; using Microsoft.DotNet.Internal.ProjectModel; using Microsoft.DotNet.Tools.Common; using NuGet.Frameworks; +using NuGet.LibraryModel; namespace Microsoft.DotNet.ProjectJsonMigration.Rules { @@ -123,6 +124,56 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules projectDependencyTransformResults, framework); } + + HoistFrameworkAssembliesForProjectDependencies(projectDependencies, outputMSBuildProject); + } + + private void HoistFrameworkAssembliesForProjectDependencies( + IEnumerable projectDependencies, + ProjectRootElement outputMSBuildProject) + { + foreach (var projectDependency in projectDependencies) + { + HoistFrameworkAssembliesForDesktopFrameworks(projectDependency, outputMSBuildProject); + } + } + + private void HoistFrameworkAssembliesForDesktopFrameworks( + ProjectDependency projectDependency, + ProjectRootElement outputMSBuildProject) + { + var targetFrameworks = ProjectReader + .GetProject(projectDependency.ProjectFilePath) + .GetTargetFrameworks().Where(p => !p.FrameworkName.IsPackageBased); + + foreach (var targetFramework in targetFrameworks) + { + HoistFrameworkAssemblies(targetFramework, outputMSBuildProject); + } + } + + private void HoistFrameworkAssemblies( + TargetFrameworkInformation targetFramework, + ProjectRootElement outputMSBuildProject) + { + var frameworkAssemblies = targetFramework.Dependencies.Where(d => + d.LibraryRange.TypeConstraint == LibraryDependencyTarget.Reference); + if(frameworkAssemblies.Any()) + { + var condition = targetFramework.FrameworkName.GetMSBuildCondition(); + var itemGroup = + outputMSBuildProject.ItemGroups.FirstOrDefault(i => i.Condition == condition) ?? + outputMSBuildProject.AddItemGroup(); + itemGroup.Condition = condition; + + foreach (var frameworkAssembly in frameworkAssemblies) + { + _transformApplicator.Execute( + FrameworkDependencyTransform.Transform(frameworkAssembly), + itemGroup, + mergeExisting: true); + } + } } private void AddProjectDependenciesToNewItemGroup( @@ -167,5 +218,13 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules path => path, path => "", path => true); + + private AddItemTransform FrameworkDependencyTransform => + new AddItemTransform( + "Reference", + dep => dep.Name, + dep => "", + dep => true) + .WithMetadata("FromP2P", "true"); } } diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs index 049615fd0..56f104de7 100644 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs @@ -249,6 +249,29 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests projectReferences.Count().Should().Be(7); } + [Fact] + public void It_promotes_FrameworkAssemblies_from_P2P_references_up_in_the_dependency_chain() + { + var solutionDirectory = TestAssets.Get(TestAssetKinds.DesktopTestProjects, "TestAppWithFrameworkAssemblies") + .CreateInstance() + .WithSourceFiles().Root; + + var appDirectory = Path.Combine(solutionDirectory.FullName, "ProjectA"); + + var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.Net451); + var mockProj = ProjectRootElement.Create(); + var testSettings = new MigrationSettings(appDirectory, appDirectory, "1.0.0", mockProj, null); + var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(), + mockProj.AddPropertyGroup()); + new MigrateProjectDependenciesRule().Apply(testSettings, testInputs); + + var frameworkAssemblyReferences = mockProj.Items.Where( + item => item.ItemType == "Reference" && + item.Include == "System.ComponentModel.DataAnnotations" && + item.Parent.Condition == " '$(TargetFramework)' == 'net451' "); + frameworkAssemblyReferences.Count().Should().Be(1); + } + [Fact] public void All_promoted_P2P_references_are_marked_with_a_FromP2P_attribute() { @@ -299,13 +322,21 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests } private ProjectRootElement MigrateProject(string solution, string project) + { + return MigrateProject(solution, project, FrameworkConstants.CommonFrameworks.NetCoreApp10); + } + + private ProjectRootElement MigrateProject( + string solution, + string project, + NuGetFramework targetFramework) { var solutionDirectory = TestAssetsManager.CreateTestInstance(solution, callingMethod: "p").Path; var appDirectory = Path.Combine(solutionDirectory, project); - var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10); + var projectContext = ProjectContext.Create(appDirectory, targetFramework); var mockProj = ProjectRootElement.Create(); var testSettings = new MigrationSettings(appDirectory, appDirectory, "1.0.0", mockProj, null); var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),