2016-08-22 19:21:52 +00:00
// 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 ;
2016-09-26 21:16:17 +00:00
using System.Collections.Generic ;
2016-08-22 19:21:52 +00:00
using System.IO ;
2016-10-04 17:39:55 +00:00
using System.Linq ;
2016-10-04 21:59:04 +00:00
using System.Text ;
2016-08-22 19:21:52 +00:00
using Microsoft.Build.Construction ;
2016-10-04 21:59:04 +00:00
using Microsoft.DotNet.Cli.Utils ;
2016-08-22 19:21:52 +00:00
using Microsoft.DotNet.ProjectJsonMigration ;
2016-08-23 20:50:05 +00:00
using Microsoft.DotNet.ProjectModel ;
2016-08-22 19:21:52 +00:00
namespace Microsoft.DotNet.Tools.Migrate
{
public partial class MigrateCommand
{
2016-08-23 20:50:05 +00:00
private readonly string _templateFile ;
2016-09-26 21:16:17 +00:00
private readonly string _projectArg ;
2016-08-23 20:50:05 +00:00
private readonly string _sdkVersion ;
2016-09-22 00:27:02 +00:00
private readonly string _xprojFilePath ;
2016-09-23 07:30:41 +00:00
private readonly bool _skipProjectReferences ;
2016-10-04 21:59:04 +00:00
private readonly string _reportFile ;
private readonly bool _reportFormatJson ;
2016-08-22 19:21:52 +00:00
2016-08-23 20:50:05 +00:00
private readonly TemporaryDotnetNewTemplateProject _temporaryDotnetNewProject ;
2016-08-22 19:21:52 +00:00
2016-10-04 21:59:04 +00:00
public MigrateCommand (
string templateFile ,
string projectArg ,
string sdkVersion ,
string xprojFilePath ,
string reportFile ,
bool skipProjectReferences ,
bool reportFormatJson )
2016-08-22 19:21:52 +00:00
{
_templateFile = templateFile ;
2016-09-26 21:16:17 +00:00
_projectArg = projectArg ? ? Directory . GetCurrentDirectory ( ) ;
2016-08-22 19:21:52 +00:00
_sdkVersion = sdkVersion ;
2016-09-22 00:27:02 +00:00
_xprojFilePath = xprojFilePath ;
2016-09-23 07:30:41 +00:00
_skipProjectReferences = skipProjectReferences ;
2016-08-22 19:21:52 +00:00
_temporaryDotnetNewProject = new TemporaryDotnetNewTemplateProject ( ) ;
2016-10-04 21:59:04 +00:00
_reportFile = reportFile ;
_reportFormatJson = reportFormatJson ;
2016-08-22 19:21:52 +00:00
}
2016-08-23 20:50:05 +00:00
public int Execute ( )
2016-08-22 19:21:52 +00:00
{
2016-09-26 21:16:17 +00:00
var projectsToMigrate = GetProjectsToMigrate ( _projectArg ) ;
2016-08-22 19:21:52 +00:00
2016-08-23 20:50:05 +00:00
var msBuildTemplate = _templateFile ! = null ?
ProjectRootElement . TryOpen ( _templateFile ) : _temporaryDotnetNewProject . MSBuildProject ;
2016-09-27 23:11:16 +00:00
var sdkVersion = _sdkVersion ? ? _temporaryDotnetNewProject . MSBuildProject . GetSdkVersion ( ) ;
2016-08-22 19:21:52 +00:00
EnsureNotNull ( sdkVersion , "Null Sdk Version" ) ;
2016-10-04 21:59:04 +00:00
MigrationReport migrationReport = null ;
2016-09-26 21:16:17 +00:00
foreach ( var project in projectsToMigrate )
{
var projectDirectory = Path . GetDirectoryName ( project ) ;
var outputDirectory = projectDirectory ;
2016-10-05 23:25:04 +00:00
var migrationSettings = new MigrationSettings ( projectDirectory , outputDirectory , sdkVersion , msBuildTemplate , _xprojFilePath ) ;
2016-10-04 21:59:04 +00:00
var projectMigrationReport = new ProjectMigrator ( ) . Migrate ( migrationSettings , _skipProjectReferences ) ;
if ( migrationReport = = null )
{
migrationReport = projectMigrationReport ;
}
else
{
migrationReport = migrationReport . Merge ( projectMigrationReport ) ;
}
}
WriteReport ( migrationReport ) ;
return migrationReport . FailedProjectsCount ;
}
private void WriteReport ( MigrationReport migrationReport )
{
if ( ! string . IsNullOrEmpty ( _reportFile ) )
{
using ( var outputTextWriter = GetReportFileOutputTextWriter ( ) )
{
outputTextWriter . Write ( GetReportContent ( migrationReport ) ) ;
}
}
WriteReportToStdOut ( migrationReport ) ;
}
private void WriteReportToStdOut ( MigrationReport migrationReport )
{
StringBuilder sb = new StringBuilder ( ) ;
foreach ( var projectMigrationReport in migrationReport . ProjectMigrationReports )
{
var errorContent = GetProjectReportErrorContent ( projectMigrationReport , colored : true ) ;
var successContent = GetProjectReportSuccessContent ( projectMigrationReport , colored : true ) ;
if ( ! string . IsNullOrEmpty ( errorContent ) )
{
Reporter . Error . WriteLine ( errorContent ) ;
}
else
{
Reporter . Output . WriteLine ( successContent ) ;
}
}
Reporter . Output . WriteLine ( GetReportSummary ( migrationReport ) ) ;
}
private string GetReportContent ( MigrationReport migrationReport , bool colored = false )
{
if ( _reportFormatJson )
{
return Newtonsoft . Json . JsonConvert . SerializeObject ( migrationReport ) ;
}
StringBuilder sb = new StringBuilder ( ) ;
foreach ( var projectMigrationReport in migrationReport . ProjectMigrationReports )
{
var errorContent = GetProjectReportErrorContent ( projectMigrationReport , colored : colored ) ;
var successContent = GetProjectReportSuccessContent ( projectMigrationReport , colored : colored ) ;
if ( ! string . IsNullOrEmpty ( errorContent ) )
{
sb . AppendLine ( errorContent ) ;
}
else
{
sb . AppendLine ( successContent ) ;
}
}
sb . AppendLine ( GetReportSummary ( migrationReport ) ) ;
return sb . ToString ( ) ;
}
private string GetReportSummary ( MigrationReport migrationReport )
{
StringBuilder sb = new StringBuilder ( ) ;
sb . AppendLine ( "Summary" ) ;
sb . AppendLine ( $"Total Projects: {migrationReport.MigratedProjectsCount}" ) ;
sb . AppendLine ( $"Succeeded Projects: {migrationReport.SucceededProjectsCount}" ) ;
sb . AppendLine ( $"Failed Projects: {migrationReport.FailedProjectsCount}" ) ;
return sb . ToString ( ) ;
}
private string GetProjectReportSuccessContent ( ProjectMigrationReport projectMigrationReport , bool colored )
{
Func < string , string > GreenIfColored = ( str ) = > colored ? str . Green ( ) : str ;
return GreenIfColored ( $"Project {projectMigrationReport.ProjectName} migration succeeded ({projectMigrationReport.ProjectDirectory})" ) ;
}
private string GetProjectReportErrorContent ( ProjectMigrationReport projectMigrationReport , bool colored )
{
StringBuilder sb = new StringBuilder ( ) ;
Func < string , string > RedIfColored = ( str ) = > colored ? str . Red ( ) : str ;
if ( projectMigrationReport . Errors . Any ( ) )
{
sb . AppendLine ( RedIfColored ( $"Project {projectMigrationReport.ProjectName} migration failed ({projectMigrationReport.ProjectDirectory})" ) ) ;
foreach ( var error in projectMigrationReport . Errors . Select ( e = > e . GetFormattedErrorMessage ( ) ) )
{
sb . AppendLine ( RedIfColored ( error ) ) ;
}
2016-09-26 21:16:17 +00:00
}
2016-08-23 20:50:05 +00:00
2016-10-04 21:59:04 +00:00
return sb . ToString ( ) ;
}
private TextWriter GetReportFileOutputTextWriter ( )
{
return File . CreateText ( _reportFile ) ;
2016-08-22 19:21:52 +00:00
}
2016-09-26 21:16:17 +00:00
private IEnumerable < string > GetProjectsToMigrate ( string projectArg )
{
2016-10-04 17:39:55 +00:00
IEnumerable < string > projects = null ;
if ( projectArg . EndsWith ( Project . FileName , StringComparison . OrdinalIgnoreCase ) )
{
projects = Enumerable . Repeat ( projectArg , 1 ) ;
}
else if ( projectArg . EndsWith ( GlobalSettings . FileName , StringComparison . OrdinalIgnoreCase ) )
2016-09-26 21:16:17 +00:00
{
2016-10-04 17:39:55 +00:00
projects = GetProjectsFromGlobalJson ( projectArg ) ;
2016-09-26 21:16:17 +00:00
}
else if ( Directory . Exists ( projectArg ) )
{
2016-10-04 17:39:55 +00:00
projects = Directory . EnumerateFiles ( projectArg , Project . FileName , SearchOption . AllDirectories ) ;
2016-09-26 21:16:17 +00:00
}
else
{
2016-10-04 17:39:55 +00:00
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 ) ;
2016-09-26 21:16:17 +00:00
}
}
2016-08-22 19:21:52 +00:00
private void EnsureNotNull ( string variable , string message )
{
if ( variable = = null )
{
throw new Exception ( message ) ;
}
}
private string GetProjectJsonPath ( string projectJson )
{
2016-08-23 20:50:05 +00:00
projectJson = ProjectPathHelper . NormalizeProjectFilePath ( projectJson ) ;
2016-08-22 19:21:52 +00:00
if ( File . Exists ( projectJson ) )
{
return projectJson ;
}
throw new Exception ( $"Unable to find project file at {projectJson}" ) ;
}
2016-10-04 17:39:55 +00:00
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 ;
}
}
}
}
2016-08-22 19:21:52 +00:00
}
}