diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/.noautobuild b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/CsprojLibrary1.csproj b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/CsprojLibrary1.csproj new file mode 100644 index 000000000..5c4334277 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/CsprojLibrary1.csproj @@ -0,0 +1,17 @@ + + + + + Library + .NETStandard + v1.5 + + + + + + + + + + diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/Helper.cs b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/Helper.cs new file mode 100644 index 000000000..a9734c078 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/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 ProjectC + { + public static string GetMessage() + { + return "This string came from CsprojLibrary1"; + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/project.json b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/project.json new file mode 100644 index 000000000..f09b9f4d3 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary1/project.json @@ -0,0 +1,11 @@ +{ + "dependencies": {}, + "frameworks": { + "netstandard1.5": { + "dependencies": { + "Microsoft.NETCore.Sdk": "1.0.0-alpha-20160923-4", + "NETStandard.Library": "1.6.0" + } + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/.noautobuild b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/CsprojLibrary2.csproj b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/CsprojLibrary2.csproj new file mode 100644 index 000000000..5c4334277 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/CsprojLibrary2.csproj @@ -0,0 +1,17 @@ + + + + + Library + .NETStandard + v1.5 + + + + + + + + + + diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/Helper.cs b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/Helper.cs new file mode 100644 index 000000000..d32ed6e6b --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/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 ProjectC + { + public static string GetMessage() + { + return "This string came from CsprojLibrary2"; + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/project.json b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/project.json new file mode 100644 index 000000000..f09b9f4d3 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary2/project.json @@ -0,0 +1,11 @@ +{ + "dependencies": {}, + "frameworks": { + "netstandard1.5": { + "dependencies": { + "Microsoft.NETCore.Sdk": "1.0.0-alpha-20160923-4", + "NETStandard.Library": "1.6.0" + } + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/.noautobuild b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/CsprojLibrary3.csproj b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/CsprojLibrary3.csproj new file mode 100644 index 000000000..5c4334277 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/CsprojLibrary3.csproj @@ -0,0 +1,17 @@ + + + + + Library + .NETStandard + v1.5 + + + + + + + + + + diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/Helper.cs b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/Helper.cs new file mode 100644 index 000000000..d7784a65d --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/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 ProjectC + { + public static string GetMessage() + { + return "This string came from CsprojLibrary3"; + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/project.json b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/project.json new file mode 100644 index 000000000..f09b9f4d3 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/CsprojLibrary3/project.json @@ -0,0 +1,11 @@ +{ + "dependencies": {}, + "frameworks": { + "netstandard1.5": { + "dependencies": { + "Microsoft.NETCore.Sdk": "1.0.0-alpha-20160923-4", + "NETStandard.Library": "1.6.0" + } + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/Program.cs b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/Program.cs index 7b3022c33..320b9d49c 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/Program.cs +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/Program.cs @@ -11,7 +11,7 @@ namespace TestApp public static int Main(string[] args) { Console.WriteLine("This string came from ProjectA"); - return 100; + return 0; } } } diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/project.json.1 b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/project.json similarity index 100% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/project.json.1 rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectA/project.json diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectB/project.json.1 b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectB/project.json similarity index 100% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectB/project.json.1 rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectB/project.json diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/ProjectC.xproj b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/ProjectC.xproj index 75a8bd8d7..47fef9e1d 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/ProjectC.xproj +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/ProjectC.xproj @@ -16,8 +16,8 @@ 2.0 - - + + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/project.json.1 b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/project.json similarity index 91% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/project.json.1 rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/project.json index ef6bf69c3..3dab0b9a6 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/project.json.1 +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectC/project.json @@ -18,10 +18,10 @@ "target": "project", "version": "1.0.0-*" }, - "ClassLibrary1": { + "CsprojLibrary1": { "target": "project" }, - "ClassLibrary2": { + "CsprojLibrary2": { "target": "project" }, "NETStandard.Library": "1.6.0" diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectD/project.json.1 b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectD/project.json similarity index 100% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectD/project.json.1 rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectD/project.json diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/ProjectE.xproj b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/ProjectE.xproj index 3e583c67f..3cd98ff52 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/ProjectE.xproj +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/ProjectE.xproj @@ -16,8 +16,8 @@ 2.0 - - + + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/project.json.1 b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/project.json similarity index 87% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/project.json.1 rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/project.json index fae1dbe77..f21f103f3 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/project.json.1 +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectE/project.json @@ -10,10 +10,10 @@ ] }, "dependencies": { - "ClassLibrary2": { + "CsprojLibrary2": { "target": "project" }, - "ClassLibrary3": { + "CsprojLibrary3": { "target": "project" }, "NETStandard.Library": "1.6.0" diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/Program.cs b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/Program.cs new file mode 100644 index 000000000..5f68b57d5 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/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; + +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; + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/project.json b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/project.json new file mode 100644 index 000000000..9608ee1d3 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectG": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/Helper.cs b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/Helper.cs index a7d766b09..055698989 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/Helper.cs +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/Helper.cs @@ -5,7 +5,7 @@ using System; namespace TestLibrary { - public static class ProjectE + public static class ProjectG { public static string GetMessage() { diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/project.json.1 b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/project.json similarity index 100% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/project.json.1 rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectG/project.json diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/global.json b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/global.json new file mode 100644 index 000000000..2b2293b26 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/global.json @@ -0,0 +1,4 @@ + +{ + "projects": [ "src", "src with spaces", "src without projects" ] +} \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/.noautobuild b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs new file mode 100644 index 000000000..db2c801fd --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/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; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("This string came from ProjectJ"); + string helperStr = TestLibrary.ProjectI.GetMessage(); + Console.WriteLine(helperStr); + return 0; + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json new file mode 100644 index 000000000..7952dd345 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectI": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/.noautobuild b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/Program.cs b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/Program.cs new file mode 100644 index 000000000..27e455e98 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/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; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("This string came from ProjectH"); + string helperStr = TestLibrary.ProjectI.GetMessage(); + Console.WriteLine(helperStr); + return 0; + } + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/project.json b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/project.json new file mode 100644 index 000000000..7952dd345 --- /dev/null +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectH/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectI": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/.noautobuild b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/Helper.cs b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/Helper.cs similarity index 77% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/Helper.cs rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/Helper.cs index 5c17a2e36..d92100c45 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/Helper.cs +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/Helper.cs @@ -5,11 +5,11 @@ using System; namespace TestLibrary { - public static class ProjectE + public static class ProjectI { public static string GetMessage() { - return "This string came from ProjectF"; + return "This string came from ProjectI"; } } } diff --git a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/project.json.1 b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/project.json similarity index 77% rename from TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/project.json.1 rename to TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/project.json index d2b7a9a21..48bc772d8 100644 --- a/TestAssets/TestProjects/TestAppDependencyGraph/ProjectF/project.json.1 +++ b/TestAssets/TestProjects/TestAppDependencyGraph/ProjectsWithGlobalJson/src/ProjectI/project.json @@ -10,10 +10,6 @@ ] }, "dependencies": { - "ProjectG": { - "target": "project", - "version": "1.0.0-*" - }, "NETStandard.Library": "1.6.0" }, "frameworks": { diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationSettings.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationSettings.cs index 19e3cc678..60d266b44 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationSettings.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationSettings.cs @@ -23,7 +23,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration ProjectDirectory = projectDirectory; OutputDirectory = outputDirectory; SdkPackageVersion = sdkPackageVersion; - MSBuildProjectTemplate = msBuildProjectTemplate; + MSBuildProjectTemplate = msBuildProjectTemplate != null ? msBuildProjectTemplate.DeepClone() : null; ProjectXProjFilePath = projectXprojFilePath; } } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs index 5a907b902..5a29e7583 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectDependencyFinder.cs @@ -15,7 +15,7 @@ using NuGet.LibraryModel; namespace Microsoft.DotNet.ProjectJsonMigration { - internal class ProjectDependencyFinder + internal class ProjectDependencyFinder { public IEnumerable ResolveProjectDependencies(string projectDir, string xprojFile = null) { @@ -33,16 +33,17 @@ namespace Microsoft.DotNet.ProjectJsonMigration public IEnumerable ResolveProjectDependencies( IEnumerable projectContexts, - IEnumerable preResolvedProjects=null) + IEnumerable preResolvedProjects = null) { - foreach(var projectContext in projectContexts) + foreach (var projectContext in projectContexts) { - foreach(var projectDependency in ResolveProjectDependencies(projectContext, preResolvedProjects)) + foreach (var projectDependency in ResolveProjectDependencies(projectContext, preResolvedProjects)) { yield return projectDependency; } } } + public IEnumerable ResolveProjectDependenciesForFramework( Project project, NuGetFramework framework, @@ -70,10 +71,15 @@ namespace Microsoft.DotNet.ProjectJsonMigration var dependencyName = projectFileDependency.Name; ProjectDependency projectDependency; + + if (preResolvedProjects.Contains(dependencyName)) + { + continue; + } + if (!possibleProjectDependencies.TryGetValue(dependencyName, out projectDependency)) { - if (projectFileDependency.LibraryRange.TypeConstraint == LibraryDependencyTarget.Project - && !preResolvedProjects.Contains(dependencyName)) + if (projectFileDependency.LibraryRange.TypeConstraint == LibraryDependencyTarget.Project) { MigrationErrorCodes .MIGRATE1014($"Unresolved project dependency ({dependencyName})").Throw(); @@ -95,7 +101,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration preResolvedProjects = preResolvedProjects ?? new HashSet(); var projectExports = projectContext.CreateExporter("_").GetDependencies(); - var possibleProjectDependencies = + var possibleProjectDependencies = FindPossibleProjectDependencies(projectContext.ProjectFile.ProjectFilePath); var projectDependencies = new List(); @@ -104,10 +110,14 @@ namespace Microsoft.DotNet.ProjectJsonMigration var projectExportName = projectExport.Library.Identity.Name; ProjectDependency projectDependency; + if (preResolvedProjects.Contains(projectExportName)) + { + continue; + } + if (!possibleProjectDependencies.TryGetValue(projectExportName, out projectDependency)) { - if (projectExport.Library.Identity.Type.Equals(LibraryType.Project) - && !preResolvedProjects.Contains(projectExportName)) + if (projectExport.Library.Identity.Type.Equals(LibraryType.Project)) { MigrationErrorCodes .MIGRATE1014($"Unresolved project dependency ({projectExportName})").Throw(); @@ -264,7 +274,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration return projects; } - private static List GetGlobalPaths(string rootPath) + internal static List GetGlobalPaths(string rootPath) { var paths = new List(); @@ -347,7 +357,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration var projects = settings["projects"]; var dependencies = settings["dependencies"] as JObject; - globalSettings.ProjectPaths = projects == null ? new string[] { } : projects.Select(a => a.Value()).ToArray();; + globalSettings.ProjectPaths = projects == null ? new string[] { } : + projects.Select(a => a.Value()).ToArray(); globalSettings.PackagesPath = settings.Value("packages"); globalSettings.FilePath = globalJsonPath; } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs index b9eae2adc..c075ce1f4 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs @@ -35,6 +35,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration Exception exc = null; IEnumerable projectDependencies = null; + var tempMSBuildProjectTemplate = rootSettings.MSBuildProjectTemplate.DeepClone(); + try { projectDependencies = ResolveTransitiveClosureProjectDependencies( @@ -54,7 +56,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration } MigrateProject(rootSettings); - + if (skipProjectReferences) { return; @@ -66,7 +68,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration var settings = new MigrationSettings(projectDir, projectDir, rootSettings.SdkPackageVersion, - rootSettings.MSBuildProjectTemplate); + tempMSBuildProjectTemplate); MigrateProject(settings); } } @@ -93,7 +95,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration var projectDependencies = _projectDependencyFinder.ResolveProjectDependencies(rootProject, xprojFile); Queue projectsQueue = new Queue(projectDependencies); - while(projectsQueue.Count() != 0) + while (projectsQueue.Count() != 0) { var projectDependency = projectsQueue.Dequeue(); @@ -107,7 +109,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration var projectDir = Path.GetDirectoryName(projectDependency.ProjectFilePath); projectDependencies = _projectDependencyFinder.ResolveProjectDependencies(projectDir); - foreach(var project in projectDependencies) + foreach (var project in projectDependencies) { projectsQueue.Enqueue(project); } @@ -138,7 +140,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration { var projectContexts = ProjectContext.CreateContextForEachFramework(migrationSettings.ProjectDirectory); var xprojFile = migrationSettings.ProjectXProjFilePath ?? _projectDependencyFinder.FindXprojFile(migrationSettings.ProjectDirectory); - + ProjectRootElement xproj = null; if (xprojFile != null) { diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Properties/AssemblyInfo.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Properties/AssemblyInfo.cs index e09cbf4ec..af0d3c6ef 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/Properties/AssemblyInfo.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Properties/AssemblyInfo.cs @@ -4,3 +4,4 @@ using System.Runtime.CompilerServices; [assembly:InternalsVisibleTo("Microsoft.DotNet.ProjectJsonMigration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100039ac461fa5c82c7dd2557400c4fd4e9dcdf7ac47e3d572548c04cd4673e004916610f4ea5cbf86f2b1ca1cb824f2a7b3976afecfcf4eb72d9a899aa6786effa10c30399e6580ed848231fec48374e41b3acf8811931343fc2f73acf72dae745adbcb7063cc4b50550618383202875223fc75401351cd89c44bf9b50e7fa3796")] +[assembly: InternalsVisibleTo("dotnet, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs index cbdb2b6a6..7db6d751e 100644 --- a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs +++ b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Microsoft.Build.Construction; using Microsoft.DotNet.ProjectJsonMigration; using Microsoft.DotNet.ProjectModel; @@ -55,22 +56,33 @@ namespace Microsoft.DotNet.Tools.Migrate private IEnumerable GetProjectsToMigrate(string projectArg) { - if (projectArg.EndsWith(Project.FileName)) + IEnumerable projects = null; + + if (projectArg.EndsWith(Project.FileName, StringComparison.OrdinalIgnoreCase)) { - yield return GetProjectJsonPath(projectArg); + projects = Enumerable.Repeat(projectArg, 1); + } + else if (projectArg.EndsWith(GlobalSettings.FileName, StringComparison.OrdinalIgnoreCase)) + { + projects = GetProjectsFromGlobalJson(projectArg); } else if (Directory.Exists(projectArg)) { - var projects = Directory.EnumerateFiles(projectArg, Project.FileName, SearchOption.AllDirectories); - - foreach(var project in projects) - { - yield return GetProjectJsonPath(project); - } + projects = Directory.EnumerateFiles(projectArg, Project.FileName, SearchOption.AllDirectories); } else { - throw new Exception($"Invalid project argument - '{projectArg}' is not a project.json file and a directory named '{projectArg}' doesn't exist."); + throw new Exception($"Invalid project argument - '{projectArg}' is not a project.json or a global.json file and a directory named '{projectArg}' doesn't exist."); + } + + if (!projects.Any()) + { + throw new Exception($"Invalid project argument - Unable to find any projects in global.json or directory '{projectArg}'"); + } + + foreach(var project in projects) + { + yield return GetProjectJsonPath(project); } } @@ -93,5 +105,35 @@ namespace Microsoft.DotNet.Tools.Migrate throw new Exception($"Unable to find project file at {projectJson}"); } + + private IEnumerable GetProjectsFromGlobalJson(string globalJson) + { + if (!File.Exists(globalJson)) + { + throw new Exception($"Unable to find global settings file at {globalJson}"); + } + + var searchPaths = ProjectDependencyFinder.GetGlobalPaths(Path.GetDirectoryName(globalJson)); + + foreach (var searchPath in searchPaths) + { + var directory = new DirectoryInfo(searchPath); + + if (!directory.Exists) + { + continue; + } + + foreach (var projectDirectory in directory.EnumerateDirectories()) + { + var projectFilePath = Path.Combine(projectDirectory.FullName, "project.json"); + + if (File.Exists(projectFilePath)) + { + yield return projectFilePath; + } + } + } + } } } diff --git a/src/dotnet/commands/dotnet-migrate/Program.cs b/src/dotnet/commands/dotnet-migrate/Program.cs index dad8653e1..be3d656e6 100644 --- a/src/dotnet/commands/dotnet-migrate/Program.cs +++ b/src/dotnet/commands/dotnet-migrate/Program.cs @@ -26,10 +26,15 @@ namespace Microsoft.DotNet.Tools.Migrate app.HandleResponseFiles = true; app.HelpOption("-h|--help"); - CommandArgument projectArgument = app.Argument("", - "The path to project.json file or a directory to migrate." + - " If a directory is specified, then it will recursively search for project.json files to migrate." + - " Defaults to current directory if nothing is specified."); + CommandArgument projectArgument = app.Argument("", + string.Join(Environment.NewLine, + "The path to ", + " - a project.json file to migrate.", + "or", + " - a global.json file, it will migrate the folders specified in global.json.", + "or", + " - a directory to migrate, it will recursively search for project.json files to migrate.", + "Defaults to current directory if nothing is specified.")); CommandOption template = app.Option("-t|--template-file", "Base MSBuild template to use for migrated app. The default is the project included in dotnet new -t msbuild", CommandOptionType.SingleValue); CommandOption sdkVersion = app.Option("-v|--sdk-package-version", "The version of the sdk package that will be referenced in the migrated app. The default is the version of the sdk in dotnet new -t msbuild", CommandOptionType.SingleValue); diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs index 37a96e1f5..0d0ff8cdd 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs @@ -153,9 +153,7 @@ namespace Microsoft.DotNet.Migration.Tests var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.RefsTest").Path; - FixUpProjectJsons(projectDirectory); - - MigrateProject(Path.Combine(projectDirectory, projectName)); + MigrateProject(new [] { Path.Combine(projectDirectory, projectName) }); string[] migratedProjects = expectedProjects.Split(new char[] { ',' }); VerifyMigration(migratedProjects, projectDirectory); @@ -172,9 +170,7 @@ namespace Microsoft.DotNet.Migration.Tests var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.SkipRefsTest").Path; - FixUpProjectJsons(projectDirectory); - - MigrateCommand.Run(new [] { Path.Combine(projectDirectory, projectName), "--skip-project-references" }).Should().Be(0); + MigrateProject(new [] { Path.Combine(projectDirectory, projectName), "--skip-project-references" }); VerifyMigration(Enumerable.Repeat(projectName, 1), projectDirectory); } @@ -186,18 +182,16 @@ namespace Microsoft.DotNet.Migration.Tests { var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}").Path; - FixUpProjectJsons(projectDirectory); - if (skipRefs) { - MigrateCommand.Run(new [] { projectDirectory, "--skip-project-references" }).Should().Be(0); + MigrateProject(new [] { projectDirectory, "--skip-project-references" }); } else { - MigrateCommand.Run(new [] { projectDirectory }).Should().Be(0); + MigrateProject(new [] { projectDirectory }); } - string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE", "ProjectF", "ProjectG" }; + string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE", "ProjectF", "ProjectG", "ProjectH", "ProjectI", "ProjectJ" }; VerifyMigration(migratedProjects, projectDirectory); } @@ -206,30 +200,81 @@ namespace Microsoft.DotNet.Migration.Tests { var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; - FixUpProjectJsons(projectDirectory); - var project = Path.Combine(projectDirectory, "ProjectA", "project.json"); - MigrateCommand.Run(new [] { project }).Should().Be(0); + MigrateProject(new [] { project }); string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE" }; 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 restoreDirectories = new string[] + { + projectDirectory, + Path.Combine(assetsDir, "ProjectG") + }; - foreach(var pj in pjs) - { - var newPj = pj.Replace("project.json.1", "project.json"); - File.Move(pj, newPj); - } + var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, "ProjectF", new [] { projectDirectory }, restoreDirectories); + + var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs + .SetEquals(outputComparisonData.MSBuildBuildOutputs); + + if (!outputsIdentical) + { + OutputDiagnostics(outputComparisonData); + } + + outputsIdentical.Should().BeTrue(); + VerifyAllMSBuildOutputsRunnable(projectDirectory); + } + + [Theory] + [InlineData("src", "ProjectH")] + [InlineData("src with spaces", "ProjectJ")] + public void It_migrates_and_builds_projects_in_global_json(string path, string projectName) + { + var assetsDir = TestAssetsManager.CreateTestInstance(Path.Combine("TestAppDependencyGraph", "ProjectsWithGlobalJson"), + callingMethod: $"ProjectsWithGlobalJson.{projectName}") + .WithLockFiles().Path; + var globalJson = Path.Combine(assetsDir, "global.json"); + + var restoreDirectories = new string[] + { + Path.Combine(assetsDir, "src", "ProjectH"), + Path.Combine(assetsDir, "src", "ProjectI"), + Path.Combine(assetsDir, "src with spaces", "ProjectJ") + }; + + var projectDirectory = Path.Combine(assetsDir, path, projectName); + + var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, + projectName, + new [] { globalJson }, + restoreDirectories); + + var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs + .SetEquals(outputComparisonData.MSBuildBuildOutputs); + + if (!outputsIdentical) + { + OutputDiagnostics(outputComparisonData); + } + + outputsIdentical.Should().BeTrue(); + VerifyAllMSBuildOutputsRunnable(projectDirectory); } private void VerifyMigration(IEnumerable expectedProjects, string rootDir) { - var migratedProjects = Directory.EnumerateFiles(rootDir, "*.csproj", SearchOption.AllDirectories) - .Select(s => Path.GetFileNameWithoutExtension(s)); + var migratedProjects = Directory.EnumerateFiles(rootDir, "project.json", SearchOption.AllDirectories) + .Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s), "*.csproj").Count() == 1) + .Where(s => Path.GetFileName(Path.GetDirectoryName(s)).Contains("Project")) + .Select(s => Path.GetFileName(Path.GetDirectoryName(s))); migratedProjects.Should().BeEquivalentTo(expectedProjects); } @@ -240,7 +285,7 @@ namespace Microsoft.DotNet.Migration.Tests Restore(projectDirectory); var outputComparisonData = - BuildProjectJsonMigrateBuildMSBuild(projectDirectory); + BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory)); return outputComparisonData; } @@ -253,7 +298,7 @@ namespace Microsoft.DotNet.Migration.Tests foreach (var dll in runnableDlls) { - new TestCommand("dotnet").ExecuteWithCapturedOutput(dll).Should().Pass(); + new TestCommand("dotnet").ExecuteWithCapturedOutput($"\"{dll}\"").Should().Pass(); } } @@ -272,19 +317,36 @@ namespace Microsoft.DotNet.Migration.Tests } } - private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, string projectName=null) + private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, + string projectName) + { + return BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName, + new [] { projectDirectory }, new [] { projectDirectory }); + } + + private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, + string projectName, + string[] migrateArgs, + string[] restoreDirectories) { BuildProjectJson(projectDirectory); var projectJsonBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); CleanBinObj(projectDirectory); // Remove lock file for migration - File.Delete(Path.Combine(projectDirectory, "project.lock.json")); - - MigrateProject(projectDirectory); + foreach(var dir in restoreDirectories) + { + File.Delete(Path.Combine(dir, "project.lock.json")); + } + MigrateProject(migrateArgs); DeleteXproj(projectDirectory); - Restore3(projectDirectory, projectName); + + foreach(var dir in restoreDirectories) + { + Restore3(dir); + } + BuildMSBuild(projectDirectory, projectName); var msbuildBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); @@ -322,10 +384,10 @@ namespace Microsoft.DotNet.Migration.Tests result.Should().Pass(); } - private void MigrateProject(string projectDirectory) + private void MigrateProject(string[] migrateArgs) { var result = - MigrateCommand.Run(new [] { projectDirectory }); + MigrateCommand.Run(migrateArgs); result.Should().Be(0); } @@ -355,15 +417,15 @@ namespace Microsoft.DotNet.Migration.Tests if (projectName != null) { command.Execute($"{projectName}.csproj") - .Should() - .Pass(); + .Should() + .Pass(); } else { command.Execute() .Should() .Pass(); - } + } } private string BuildMSBuild(string projectDirectory, string projectName, string configuration="Debug")