From de5da5870f5722e2f69815535e6b6ed9458a8456 Mon Sep 17 00:00:00 2001 From: Livar Date: Thu, 3 Nov 2016 10:27:51 -0700 Subject: [PATCH] Marking hoisted P2P projects with a FromP2P attribute. (#4598) --- .../ProjectDependency.cs | 16 +++++++- .../ProjectDependencyFinder.cs | 34 +++++++++++----- .../Rules/MigrateProjectDependenciesRule.cs | 37 +++++++++++------- ...enThatIWantToMigrateProjectDependencies.cs | 39 +++++++++++++++++++ 4 files changed, 103 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs index 2315deabb..afea501a7 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependency.cs @@ -7,11 +7,25 @@ namespace Microsoft.DotNet.ProjectJsonMigration { public string Name { get; } public string ProjectFilePath { get; } + public bool Hoisted { get; } - public ProjectDependency(string name, string projectFilePath) + public ProjectDependency(string name, string projectFilePath, bool hoisted) { Name = name; ProjectFilePath = System.IO.Path.GetFullPath(projectFilePath); + Hoisted = hoisted; + } + + public override bool Equals(object obj) + { + var other = obj as ProjectDependency; + + return other != null && other.ProjectFilePath == ProjectFilePath; + } + + public override int GetHashCode() + { + return ProjectFilePath.GetHashCode(); } } } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs index ab69f6cc0..fbfa76838 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs @@ -50,7 +50,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration IEnumerable preResolvedProjects=null) { var projects = new List { projectToResolve }; - var allDependencies = new List(); + var allDependencies = new HashSet(); while (projects.Count > 0) { var project = projects.First(); @@ -65,24 +65,33 @@ namespace Microsoft.DotNet.ProjectJsonMigration var dependencies = ResolveDirectProjectDependenciesForFramework( projectContext.ProjectFile, framework, - preResolvedProjects + preResolvedProjects, + HoistDependenciesThatAreNotDirectDependencies(projectToResolve, project) ); projects.AddRange(dependencies); - allDependencies.AddRange(dependencies); + allDependencies.UnionWith(dependencies); } return allDependencies; } + private bool HoistDependenciesThatAreNotDirectDependencies( + ProjectDependency originalProject, + ProjectDependency dependenciesOwner) + { + return originalProject != dependenciesOwner; + } + public IEnumerable ResolveDirectProjectDependenciesForFramework( Project project, NuGetFramework framework, - IEnumerable preResolvedProjects=null) + IEnumerable preResolvedProjects=null, + bool hoistedDependencies = false) { preResolvedProjects = preResolvedProjects ?? new HashSet(); var possibleProjectDependencies = - FindPossibleProjectDependencies(project.ProjectFilePath); + FindPossibleProjectDependencies(project.ProjectFilePath, hoistedDependencies); var projectDependencies = new List(); @@ -205,7 +214,9 @@ namespace Microsoft.DotNet.ProjectJsonMigration PathUtility.GetPathWithDirectorySeparator(p)))); } - private Dictionary FindPossibleProjectDependencies(string projectJsonFilePath) + private Dictionary FindPossibleProjectDependencies( + string projectJsonFilePath, + bool hoistedDependencies = false) { var projectRootDirectory = GetRootFromProjectJson(projectJsonFilePath); @@ -217,7 +228,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration var projects = new Dictionary(StringComparer.Ordinal); - foreach (var project in GetPotentialProjects(projectSearchPaths)) + foreach (var project in GetPotentialProjects(projectSearchPaths, hoistedDependencies)) { if (projects.ContainsKey(project.Name)) { @@ -278,7 +289,9 @@ namespace Microsoft.DotNet.ProjectJsonMigration /// /// Create the list of potential projects from the search paths. /// - private static List GetPotentialProjects(IEnumerable searchPaths) + private static List GetPotentialProjects( + IEnumerable searchPaths, + bool hoistedDependencies = false) { var projects = new List(); @@ -301,7 +314,10 @@ namespace Microsoft.DotNet.ProjectJsonMigration // Instead, we'll do an exists check when we try to resolve // Check if we've already added this, just in case it was pre-loaded into the cache - var project = new ProjectDependency(projectDirectory.Name, projectFilePath); + var project = new ProjectDependency( + projectDirectory.Name, + projectFilePath, + hoistedDependencies); projects.Add(project); } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs index e40c54c5a..a0db963e8 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Rules/MigrateProjectDependenciesRule.cs @@ -106,12 +106,15 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules ProjectRootElement outputMSBuildProject) { var projectDependencies = _projectDependencyFinder.ResolveAllProjectDependenciesForFramework( - new ProjectDependency(project.Name, project.ProjectFilePath), + new ProjectDependency(project.Name, project.ProjectFilePath, false), framework, migratedXProjDependencyNames); var projectDependencyTransformResults = - projectDependencies.Select(p => ProjectDependencyTransform.Transform(p)); + projectDependencies.Select(p => + p.Hoisted ? + HoistedDependencyTransform.Transform(p) : + ProjectDependencyTransform.Transform(p)); if (projectDependencyTransformResults.Any()) { @@ -138,18 +141,26 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules } } - private AddItemTransform ProjectDependencyTransform => new AddItemTransform( - "ProjectReference", - dep => - { - var projectDir = Path.GetDirectoryName(dep.ProjectFilePath); - var migratedProjectFileName = Path.GetFileName(projectDir) + ".csproj"; - var relativeProjectDir = PathUtility.GetRelativePath(_projectDirectory + "/", projectDir); + private AddItemTransform ProjectDependencyTransform => + GetProjectDependencyTransfrom(); - return Path.Combine(relativeProjectDir, migratedProjectFileName); - }, - dep => "", - dep => true); + private AddItemTransform HoistedDependencyTransform => + GetProjectDependencyTransfrom() + .WithMetadata("FromP2P", "true"); + + private Func> GetProjectDependencyTransfrom => + () => new AddItemTransform( + "ProjectReference", + dep => + { + var projectDir = Path.GetDirectoryName(dep.ProjectFilePath); + var migratedProjectFileName = Path.GetFileName(projectDir) + ".csproj"; + var relativeProjectDir = PathUtility.GetRelativePath(_projectDirectory + "/", projectDir); + + return Path.Combine(relativeProjectDir, migratedProjectFileName); + }, + dep => "", + dep => true); private AddItemTransform ProjectDependencyStringTransform => new AddItemTransform( "ProjectReference", diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs index b6aa8915a..049615fd0 100644 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/Rules/GivenThatIWantToMigrateProjectDependencies.cs @@ -249,6 +249,45 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests projectReferences.Count().Should().Be(7); } + [Fact] + public void All_promoted_P2P_references_are_marked_with_a_FromP2P_attribute() + { + var expectedHoistedProjectReferences = new [] { + Path.Combine("..", "ProjectD", "ProjectD.csproj"), + Path.Combine("..", "ProjectE", "ProjectE.csproj"), + Path.Combine("..", "CsprojLibrary1", "CsprojLibrary1.csproj"), + Path.Combine("..", "CsprojLibrary2", "CsprojLibrary2.csproj"), + Path.Combine("..", "CsprojLibrary3", "CsprojLibrary3.csproj") + }; + + var mockProj = MigrateProject("TestAppDependencyGraph", "ProjectA"); + + var projectReferences = mockProj.Items + .Where(item => + item.ItemType == "ProjectReference" && item.GetMetadataWithName("FromP2P") != null) + .Select(i => i.Include); + + projectReferences.Should().BeEquivalentTo(expectedHoistedProjectReferences); + } + + [Fact] + public void All_non_promoted_P2P_references_are_not_marked_with_a_FromP2P_attribute() + { + var expectedNonHoistedProjectReferences = new [] { + Path.Combine("..", "ProjectB", "ProjectB.csproj"), + Path.Combine("..", "ProjectC", "ProjectC.csproj") + }; + + var mockProj = MigrateProject("TestAppDependencyGraph", "ProjectA"); + + var projectReferences = mockProj.Items + .Where(item => + item.ItemType == "ProjectReference" && item.GetMetadataWithName("FromP2P") == null) + .Select(i => i.Include); + + projectReferences.Should().BeEquivalentTo(expectedNonHoistedProjectReferences); + } + [Fact] public void It_migrates_unqualified_dependencies_as_ProjectReference_when_a_matching_project_is_found() {