Add support to migrate folders specified in global.json

This commit is contained in:
Sridhar Periyasamy 2016-10-04 10:39:55 -07:00
parent a396630576
commit 1d85c241b1
14 changed files with 247 additions and 35 deletions

View file

@ -0,0 +1,4 @@
{
"projects": [ "src", "src with spaces", "src without projects" ]
}

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 ProjectJ");
string helperStr = TestLibrary.ProjectI.GetMessage();
Console.WriteLine(helperStr);
return 0;
}
}
}

View file

@ -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": {}
}
}

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 ProjectH");
string helperStr = TestLibrary.ProjectI.GetMessage();
Console.WriteLine(helperStr);
return 0;
}
}
}

View file

@ -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": {}
}
}

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 ProjectI
{
public static string GetMessage()
{
return "This string came from ProjectI";
}
}
}

View file

@ -0,0 +1,18 @@
{
"version": "1.0.0-*",
"buildOptions": {
"nowarn": [
"CS1591"
],
"xmlDoc": true,
"additionalArguments": [
"-highentropyva+"
]
},
"dependencies": {
"NETStandard.Library": "1.6.0"
},
"frameworks": {
"netstandard1.5": {}
}
}

View file

@ -269,7 +269,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
return projects;
}
private static List<string> GetGlobalPaths(string rootPath)
public static List<string> GetGlobalPaths(string rootPath)
{
var paths = new List<string>();

View file

@ -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;
@ -46,7 +47,7 @@ namespace Microsoft.DotNet.Tools.Migrate
Console.WriteLine($"Migrating project {project}..");
var projectDirectory = Path.GetDirectoryName(project);
var outputDirectory = projectDirectory;
var migrationSettings = new MigrationSettings(projectDirectory, outputDirectory, sdkVersion, msBuildTemplate, _xprojFilePath);
var migrationSettings = new MigrationSettings(projectDirectory, outputDirectory, sdkVersion, msBuildTemplate.DeepClone(), _xprojFilePath);
new ProjectMigrator().Migrate(migrationSettings, _skipProjectReferences);
}
@ -55,22 +56,33 @@ namespace Microsoft.DotNet.Tools.Migrate
private IEnumerable<string> GetProjectsToMigrate(string projectArg)
{
if (projectArg.EndsWith(Project.FileName))
IEnumerable<string> 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<string> 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;
}
}
}
}
}
}

View file

@ -26,10 +26,14 @@ namespace Microsoft.DotNet.Tools.Migrate
app.HandleResponseFiles = true;
app.HelpOption("-h|--help");
CommandArgument projectArgument = app.Argument("<PROJECT_JSON/PROJECT_DIR>",
"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("<PROJECT_JSON/GLOBAL_JSON/PROJECT_DIR>",
"The path to " + Environment.NewLine +
" - a project.json file to migrate." + Environment.NewLine +
"or" + Environment.NewLine +
" - a global.json file, it will migrate the folders specified in global.json." + Environment.NewLine +
"or" + Environment.NewLine +
" - a directory to migrate, it will recursively search for project.json files to migrate." + Environment.NewLine +
"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);

View file

@ -153,7 +153,7 @@ namespace Microsoft.DotNet.Migration.Tests
var projectDirectory =
TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.RefsTest").Path;
MigrateProject(Path.Combine(projectDirectory, projectName));
MigrateProject(new [] { Path.Combine(projectDirectory, projectName) });
string[] migratedProjects = expectedProjects.Split(new char[] { ',' });
VerifyMigration(migratedProjects, projectDirectory);
@ -170,7 +170,7 @@ namespace Microsoft.DotNet.Migration.Tests
var projectDirectory =
TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"{projectName}.SkipRefsTest").Path;
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);
}
@ -184,14 +184,14 @@ namespace Microsoft.DotNet.Migration.Tests
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);
}
@ -201,7 +201,7 @@ namespace Microsoft.DotNet.Migration.Tests
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path;
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);
@ -213,8 +213,13 @@ namespace Microsoft.DotNet.Migration.Tests
{
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);
var restoreDirectories = new string[]
{
projectDirectory,
Path.Combine(assetsDir, "ProjectG")
};
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, "ProjectF", new [] { projectDirectory }, restoreDirectories);
var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs
.SetEquals(outputComparisonData.MSBuildBuildOutputs);
@ -228,6 +233,42 @@ namespace Microsoft.DotNet.Migration.Tests
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<string> expectedProjects, string rootDir)
{
var migratedProjects = Directory.EnumerateFiles(rootDir, "project.migrated.json", SearchOption.AllDirectories)
@ -242,7 +283,7 @@ namespace Microsoft.DotNet.Migration.Tests
Restore(projectDirectory);
var outputComparisonData =
BuildProjectJsonMigrateBuildMSBuild(projectDirectory);
BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory));
return outputComparisonData;
}
@ -255,7 +296,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();
}
}
@ -274,22 +315,32 @@ namespace Microsoft.DotNet.Migration.Tests
}
}
private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, string projectName, List<string> additonalRestoreDirectories = 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<string>(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);
additonalRestoreDirectories = additonalRestoreDirectories ?? new List<string>();
foreach(var dir in additonalRestoreDirectories)
foreach(var dir in restoreDirectories)
{
Restore3(dir);
}
@ -331,10 +382,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);
}