dotnet-migrate built in command for cli
This commit is contained in:
parent
46818ff3fa
commit
611e4ccfde
8 changed files with 311 additions and 1 deletions
|
@ -21,6 +21,7 @@ using Microsoft.DotNet.Tools.Restore;
|
|||
using Microsoft.DotNet.Tools.Restore3;
|
||||
using Microsoft.DotNet.Tools.Run;
|
||||
using Microsoft.DotNet.Tools.Test;
|
||||
using Microsoft.DotNet.Tools.Migrate;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli
|
||||
|
@ -42,6 +43,7 @@ namespace Microsoft.DotNet.Cli
|
|||
["run3"] = Run3Command.Run,
|
||||
["restore3"] = Restore3Command.Run,
|
||||
["pack3"] = Pack3Command.Run,
|
||||
["migrate"] = MigrateCommand.Run
|
||||
};
|
||||
|
||||
public static int Main(string[] args)
|
||||
|
|
|
@ -3,3 +3,4 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
[assembly: AssemblyMetadataAttribute("Serviceable", "True")]
|
||||
[assembly: InternalsVisibleTo("dotnet.Tests")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.DotNet.ProjectJsonMigration.Tests")]
|
|
@ -15,6 +15,5 @@ namespace Microsoft.DotNet.Cli
|
|||
{
|
||||
return new MSBuildForwardingApp(args).Execute();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
84
src/dotnet/commands/dotnet-migrate/MigrateCommand.cs
Normal file
84
src/dotnet/commands/dotnet-migrate/MigrateCommand.cs
Normal file
|
@ -0,0 +1,84 @@
|
|||
// 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.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.DotNet.ProjectJsonMigration;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Migrate
|
||||
{
|
||||
public partial class MigrateCommand
|
||||
{
|
||||
private string _templateFile;
|
||||
private string _outputDirectory;
|
||||
private string _projectJson;
|
||||
private string _sdkVersion;
|
||||
|
||||
private TemporaryDotnetNewTemplateProject _temporaryDotnetNewProject;
|
||||
|
||||
public MigrateCommand(string templateFile, string outputDirectory, string projectJson, string sdkVersion)
|
||||
{
|
||||
_templateFile = templateFile;
|
||||
_outputDirectory = outputDirectory;
|
||||
_projectJson = projectJson;
|
||||
_sdkVersion = sdkVersion;
|
||||
|
||||
_temporaryDotnetNewProject = new TemporaryDotnetNewTemplateProject();
|
||||
}
|
||||
|
||||
public int Start()
|
||||
{
|
||||
var project = GetProjectJsonPath(_projectJson) ?? _temporaryDotnetNewProject.ProjectJsonPath;
|
||||
EnsureNotNull(project, "Unable to find project.json");
|
||||
var projectDirectory = Path.GetDirectoryName(project);
|
||||
|
||||
var templateFile = _templateFile ?? _temporaryDotnetNewProject.MSBuildProjectPath;
|
||||
EnsureNotNull(templateFile, "Unable to find default msbuild template");
|
||||
|
||||
var outputDirectory = _outputDirectory ?? Path.GetDirectoryName(project);
|
||||
EnsureNotNull(outputDirectory, "Null output directory");
|
||||
|
||||
var sdkVersion = _sdkVersion ?? new ProjectJsonParser(_temporaryDotnetNewProject.ProjectJson).SdkPackageVersion;
|
||||
EnsureNotNull(sdkVersion, "Null Sdk Version");
|
||||
|
||||
var migrationSettings = new MigrationSettings(projectDirectory, outputDirectory, sdkVersion, templateFile);
|
||||
new ProjectMigrator().Migrate(migrationSettings);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void EnsureNotNull(string variable, string message)
|
||||
{
|
||||
if (variable == null)
|
||||
{
|
||||
throw new Exception(message);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetProjectJsonPath(string projectJson)
|
||||
{
|
||||
if (projectJson == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (File.Exists(projectJson))
|
||||
{
|
||||
return projectJson;
|
||||
}
|
||||
|
||||
if (Directory.Exists(projectJson))
|
||||
{
|
||||
var projectCandidate = Path.Combine(projectJson, "project.json");
|
||||
|
||||
if (File.Exists(projectCandidate))
|
||||
{
|
||||
return projectCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Unable to find project file at {projectJson}");
|
||||
}
|
||||
}
|
||||
}
|
55
src/dotnet/commands/dotnet-migrate/Program.cs
Normal file
55
src/dotnet/commands/dotnet-migrate/Program.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
// 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 Microsoft.DotNet.Cli.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Migrate
|
||||
{
|
||||
public partial class MigrateCommand
|
||||
{
|
||||
public static int Run(string[] args)
|
||||
{
|
||||
DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
||||
CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
app.Name = "dotnet migrate";
|
||||
app.FullName = ".NET Migrate Command";
|
||||
app.Description = "Command used to migrate project.json projects to msbuild";
|
||||
app.HandleResponseFiles = true;
|
||||
app.AllowArgumentSeparator = true;
|
||||
app.HelpOption("-h|--help");
|
||||
|
||||
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 output = app.Option("-o|--output", "Directory to output migrated project to. The default is the project directory", CommandOptionType.SingleValue);
|
||||
CommandOption project = app.Option("-p|--project", "The path to the project to run (defaults to the current directory). Can be a path to a project.json or a project directory", 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);
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
MigrateCommand migrateCommand = new MigrateCommand(
|
||||
template.Value(),
|
||||
output.Value(),
|
||||
project.Value(),
|
||||
sdkVersion.Value());
|
||||
|
||||
return migrateCommand.Start();
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
return app.Execute(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Reporter.Error.WriteLine(ex.ToString());
|
||||
#else
|
||||
Reporter.Error.WriteLine(ex.Message);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
src/dotnet/commands/dotnet-migrate/ProjectJsonParser.cs
Normal file
81
src/dotnet/commands/dotnet-migrate/ProjectJsonParser.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses select data from a project.json without relying on ProjectModel.
|
||||
/// Used to parse simple information.
|
||||
/// </summary>
|
||||
internal class ProjectJsonParser
|
||||
{
|
||||
public static string SdkPackageName => "Microsoft.DotNet.Core.Sdk";
|
||||
|
||||
public string SdkPackageVersion { get; }
|
||||
|
||||
public ProjectJsonParser(JObject projectJson)
|
||||
{
|
||||
SdkPackageVersion = GetSdkPackageVersion(projectJson);
|
||||
}
|
||||
|
||||
private string GetSdkPackageVersion(JObject projectJson)
|
||||
{
|
||||
var sdkPackageNode = SelectJsonNodes(projectJson, property => property.Name == SdkPackageName).First();
|
||||
|
||||
if (sdkPackageNode.Value.Type == JTokenType.String)
|
||||
{
|
||||
return (string)sdkPackageNode.Value;
|
||||
}
|
||||
else if (sdkPackageNode.Type == JTokenType.Object)
|
||||
{
|
||||
var sdkPackageNodeValue = (JObject)sdkPackageNode.Value;
|
||||
|
||||
JToken sdkVersionNode;
|
||||
if (sdkPackageNodeValue.TryGetValue("version", out sdkVersionNode))
|
||||
{
|
||||
return sdkVersionNode.Value<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to determine sdk version, no version node in default template.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to determine sdk version, no version information found");
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<JProperty> SelectJsonNodes(
|
||||
JToken jsonNode,
|
||||
Func<JProperty, bool> condition,
|
||||
List<JProperty> nodeAccumulator = null)
|
||||
{
|
||||
nodeAccumulator = nodeAccumulator ?? new List<JProperty>();
|
||||
|
||||
if (jsonNode.Type == JTokenType.Object)
|
||||
{
|
||||
var eligibleNodes = jsonNode.Children<JProperty>().Where(j => condition(j));
|
||||
nodeAccumulator.AddRange(eligibleNodes);
|
||||
|
||||
foreach (var child in jsonNode.Children<JProperty>())
|
||||
{
|
||||
SelectJsonNodes(child.Value, condition, nodeAccumulator: nodeAccumulator);
|
||||
}
|
||||
}
|
||||
else if (jsonNode.Type == JTokenType.Array)
|
||||
{
|
||||
foreach (var child in jsonNode.Children())
|
||||
{
|
||||
SelectJsonNodes(child, condition, nodeAccumulator: nodeAccumulator);
|
||||
}
|
||||
}
|
||||
|
||||
return nodeAccumulator;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli
|
||||
{
|
||||
internal class TemporaryDotnetNewTemplateProject
|
||||
{
|
||||
private static string s_temporaryDotnetNewMSBuildProjectName = "p";
|
||||
|
||||
public TemporaryDotnetNewTemplateProject()
|
||||
{
|
||||
ProjectDirectory = CreateDotnetNewMSBuild(s_temporaryDotnetNewMSBuildProjectName);
|
||||
MSBuildProject = GetMSBuildProject(ProjectDirectory);
|
||||
ProjectJson = GetProjectJson(ProjectDirectory);
|
||||
}
|
||||
|
||||
public ProjectRootElement MSBuildProject { get; }
|
||||
public JObject ProjectJson { get; }
|
||||
public string ProjectDirectory { get; }
|
||||
|
||||
public string ProjectJsonPath => Path.Combine(ProjectDirectory, "project.json");
|
||||
public string MSBuildProjectPath => Path.Combine(ProjectDirectory, s_temporaryDotnetNewMSBuildProjectName);
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
Directory.Delete(ProjectDirectory, true);
|
||||
}
|
||||
|
||||
private string CreateDotnetNewMSBuild(string projectName)
|
||||
{
|
||||
var guid = Guid.NewGuid().ToString();
|
||||
var tempDir = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
this.GetType().Namespace,
|
||||
guid,
|
||||
s_temporaryDotnetNewMSBuildProjectName);
|
||||
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, true);
|
||||
}
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
RunCommand("new", new string[] { "-t", "msbuild" }, tempDir);
|
||||
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
private ProjectRootElement GetMSBuildProject(string temporaryDotnetNewMSBuildDirectory)
|
||||
{
|
||||
var templateProjPath = Path.Combine(temporaryDotnetNewMSBuildDirectory,
|
||||
s_temporaryDotnetNewMSBuildProjectName + ".csproj");
|
||||
|
||||
return ProjectRootElement.Open(templateProjPath);
|
||||
}
|
||||
|
||||
private JObject GetProjectJson(string temporaryDotnetNewMSBuildDirectory)
|
||||
{
|
||||
var projectJsonFile = Path.Combine(temporaryDotnetNewMSBuildDirectory, "project.json");
|
||||
return JObject.Parse(File.ReadAllText(projectJsonFile));
|
||||
}
|
||||
|
||||
private void RunCommand(string commandToExecute, IEnumerable<string> args, string workingDirectory)
|
||||
{
|
||||
var command = new DotNetCommandFactory()
|
||||
.Create(commandToExecute, args)
|
||||
.WorkingDirectory(workingDirectory)
|
||||
.CaptureStdOut()
|
||||
.CaptureStdErr();
|
||||
|
||||
var commandResult = command.Execute();
|
||||
|
||||
if (commandResult.ExitCode != 0)
|
||||
{
|
||||
throw new Exception($"Failed to run {commandToExecute} in directory: {workingDirectory}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,9 @@
|
|||
"Microsoft.DotNet.Configurer": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.ProjectJsonMigration": {
|
||||
"target": "project"
|
||||
},
|
||||
"Microsoft.DotNet.Tools.Test": {
|
||||
"target": "project"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue