2016-08-22 12:21:52 -07: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 14:16:17 -07:00
|
|
|
|
using System.Collections.Generic;
|
2016-08-22 12:21:52 -07:00
|
|
|
|
using System.IO;
|
2016-10-04 10:39:55 -07:00
|
|
|
|
using System.Linq;
|
2016-10-04 14:59:04 -07:00
|
|
|
|
using System.Text;
|
2016-08-22 12:21:52 -07:00
|
|
|
|
using Microsoft.Build.Construction;
|
2016-10-12 16:22:58 -07:00
|
|
|
|
using Microsoft.Build.Evaluation;
|
2016-12-20 13:04:01 -10:00
|
|
|
|
using Microsoft.DotNet.Cli;
|
2016-12-07 11:49:15 -10:00
|
|
|
|
using Microsoft.DotNet.Cli.Sln.Internal;
|
2016-10-04 14:59:04 -07:00
|
|
|
|
using Microsoft.DotNet.Cli.Utils;
|
2016-08-22 12:21:52 -07:00
|
|
|
|
using Microsoft.DotNet.ProjectJsonMigration;
|
2016-10-27 18:46:43 -07:00
|
|
|
|
using Microsoft.DotNet.Internal.ProjectModel;
|
2016-10-29 01:58:37 -07:00
|
|
|
|
using Project = Microsoft.DotNet.Internal.ProjectModel.Project;
|
|
|
|
|
using Microsoft.DotNet.Tools.Common;
|
2016-08-22 12:21:52 -07:00
|
|
|
|
|
|
|
|
|
namespace Microsoft.DotNet.Tools.Migrate
|
|
|
|
|
{
|
|
|
|
|
public partial class MigrateCommand
|
|
|
|
|
{
|
2017-01-17 13:45:48 -08:00
|
|
|
|
private const string ProductDescription = "Visual Studio 15";
|
|
|
|
|
private const string VisualStudioVersion = "15.0.26114.2";
|
|
|
|
|
private const string MinimumVisualStudioVersion = "10.0.40219.1";
|
|
|
|
|
|
2016-12-07 11:49:15 -10:00
|
|
|
|
private SlnFile _slnFile;
|
2016-10-29 01:58:37 -07:00
|
|
|
|
private readonly DirectoryInfo _workspaceDirectory;
|
2016-08-23 13:50:05 -07:00
|
|
|
|
private readonly string _templateFile;
|
2016-09-26 14:16:17 -07:00
|
|
|
|
private readonly string _projectArg;
|
2016-08-23 13:50:05 -07:00
|
|
|
|
private readonly string _sdkVersion;
|
2016-09-21 17:27:02 -07:00
|
|
|
|
private readonly string _xprojFilePath;
|
2016-09-23 00:30:41 -07:00
|
|
|
|
private readonly bool _skipProjectReferences;
|
2016-10-04 14:59:04 -07:00
|
|
|
|
private readonly string _reportFile;
|
|
|
|
|
private readonly bool _reportFormatJson;
|
2016-10-29 01:58:37 -07:00
|
|
|
|
private readonly bool _skipBackup;
|
2016-08-22 12:21:52 -07:00
|
|
|
|
|
2016-10-04 14:59:04 -07:00
|
|
|
|
public MigrateCommand(
|
2016-12-20 14:19:37 -08:00
|
|
|
|
string templateFile,
|
|
|
|
|
string projectArg,
|
|
|
|
|
string sdkVersion,
|
|
|
|
|
string xprojFilePath,
|
|
|
|
|
string reportFile,
|
|
|
|
|
bool skipProjectReferences,
|
2016-10-29 01:58:37 -07:00
|
|
|
|
bool reportFormatJson,
|
|
|
|
|
bool skipBackup)
|
2016-12-20 14:19:37 -08:00
|
|
|
|
{
|
2016-08-22 12:21:52 -07:00
|
|
|
|
_templateFile = templateFile;
|
2016-09-26 14:16:17 -07:00
|
|
|
|
_projectArg = projectArg ?? Directory.GetCurrentDirectory();
|
2016-10-29 01:58:37 -07:00
|
|
|
|
_workspaceDirectory = File.Exists(_projectArg)
|
|
|
|
|
? new FileInfo(_projectArg).Directory
|
|
|
|
|
: new DirectoryInfo(_projectArg);
|
2016-08-22 12:21:52 -07:00
|
|
|
|
_sdkVersion = sdkVersion;
|
2016-09-21 17:27:02 -07:00
|
|
|
|
_xprojFilePath = xprojFilePath;
|
2016-09-23 00:30:41 -07:00
|
|
|
|
_skipProjectReferences = skipProjectReferences;
|
2016-10-04 14:59:04 -07:00
|
|
|
|
_reportFile = reportFile;
|
|
|
|
|
_reportFormatJson = reportFormatJson;
|
2016-10-29 01:58:37 -07:00
|
|
|
|
_skipBackup = skipBackup;
|
2016-08-22 12:21:52 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-23 13:50:05 -07:00
|
|
|
|
public int Execute()
|
2016-08-22 12:21:52 -07:00
|
|
|
|
{
|
2016-10-24 22:46:15 -07:00
|
|
|
|
var temporaryDotnetNewProject = new TemporaryDotnetNewTemplateProject();
|
2016-09-26 14:16:17 -07:00
|
|
|
|
var projectsToMigrate = GetProjectsToMigrate(_projectArg);
|
2016-08-22 12:21:52 -07:00
|
|
|
|
|
2016-10-24 22:46:15 -07:00
|
|
|
|
var msBuildTemplatePath = _templateFile ?? temporaryDotnetNewProject.MSBuildProjectPath;
|
2016-08-22 12:21:52 -07:00
|
|
|
|
|
2016-10-04 14:59:04 -07:00
|
|
|
|
MigrationReport migrationReport = null;
|
|
|
|
|
|
2016-09-26 14:16:17 -07:00
|
|
|
|
foreach (var project in projectsToMigrate)
|
|
|
|
|
{
|
|
|
|
|
var projectDirectory = Path.GetDirectoryName(project);
|
|
|
|
|
var outputDirectory = projectDirectory;
|
2016-10-24 22:46:15 -07:00
|
|
|
|
var migrationSettings = new MigrationSettings(
|
|
|
|
|
projectDirectory,
|
|
|
|
|
outputDirectory,
|
|
|
|
|
msBuildTemplatePath,
|
2016-12-07 11:49:15 -10:00
|
|
|
|
_xprojFilePath,
|
|
|
|
|
null,
|
|
|
|
|
_slnFile);
|
2016-10-04 14:59:04 -07:00
|
|
|
|
var projectMigrationReport = new ProjectMigrator().Migrate(migrationSettings, _skipProjectReferences);
|
|
|
|
|
|
|
|
|
|
if (migrationReport == null)
|
|
|
|
|
{
|
|
|
|
|
migrationReport = projectMigrationReport;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
migrationReport = migrationReport.Merge(projectMigrationReport);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteReport(migrationReport);
|
|
|
|
|
|
2016-10-24 22:46:15 -07:00
|
|
|
|
temporaryDotnetNewProject.Clean();
|
|
|
|
|
|
2016-12-07 11:49:15 -10:00
|
|
|
|
UpdateSolutionFile(migrationReport);
|
|
|
|
|
|
2016-10-29 01:58:37 -07:00
|
|
|
|
MoveProjectJsonArtifactsToBackup(migrationReport);
|
|
|
|
|
|
2016-10-04 14:59:04 -07:00
|
|
|
|
return migrationReport.FailedProjectsCount;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-07 11:49:15 -10:00
|
|
|
|
private void UpdateSolutionFile(MigrationReport migrationReport)
|
|
|
|
|
{
|
|
|
|
|
if (_slnFile == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (migrationReport.FailedProjectsCount > 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-19 11:23:01 -08:00
|
|
|
|
var csprojFilesToAdd = new HashSet<string>();
|
2016-12-20 13:04:01 -10:00
|
|
|
|
|
|
|
|
|
var slnPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory);
|
|
|
|
|
foreach (var report in migrationReport.ProjectMigrationReports)
|
2016-12-07 11:49:15 -10:00
|
|
|
|
{
|
2016-12-20 13:04:01 -10:00
|
|
|
|
var reportPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(report.ProjectDirectory);
|
2017-01-20 12:21:04 -08:00
|
|
|
|
var relativeReportPath = PathUtility.GetRelativePath(
|
2017-01-19 11:23:01 -08:00
|
|
|
|
slnPathWithTrailingSlash,
|
|
|
|
|
reportPathWithTrailingSlash);
|
2016-12-07 11:49:15 -10:00
|
|
|
|
|
2017-01-20 12:21:04 -08:00
|
|
|
|
var xprojPath = Path.Combine(relativeReportPath, report.ProjectName + ".xproj");
|
|
|
|
|
var xprojProjectsReferencedBySolution = _slnFile.Projects.Where(p => p.FilePath == xprojPath);
|
2016-12-07 11:49:15 -10:00
|
|
|
|
|
2016-12-20 13:04:01 -10:00
|
|
|
|
var migratedProjectName = report.ProjectName + ".csproj";
|
2017-01-20 12:21:04 -08:00
|
|
|
|
if (xprojProjectsReferencedBySolution.Count() == 1)
|
2016-12-20 13:04:01 -10:00
|
|
|
|
{
|
2017-01-20 12:21:04 -08:00
|
|
|
|
var slnProject = xprojProjectsReferencedBySolution.Single();
|
2016-12-20 13:04:01 -10:00
|
|
|
|
slnProject.FilePath = Path.Combine(
|
|
|
|
|
Path.GetDirectoryName(slnProject.FilePath),
|
|
|
|
|
migratedProjectName);
|
|
|
|
|
slnProject.TypeGuid = ProjectTypeGuids.CSharpProjectTypeGuid;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-01-20 12:21:04 -08:00
|
|
|
|
var csprojPath = Path.Combine(relativeReportPath, migratedProjectName);
|
|
|
|
|
var solutionContainsCsprojPriorToMigration = _slnFile.Projects
|
2017-01-19 11:23:01 -08:00
|
|
|
|
.Where(p => p.FilePath == csprojPath)
|
|
|
|
|
.Any();
|
|
|
|
|
|
2017-01-20 12:21:04 -08:00
|
|
|
|
if (!solutionContainsCsprojPriorToMigration)
|
2017-01-19 11:23:01 -08:00
|
|
|
|
{
|
|
|
|
|
csprojFilesToAdd.Add(Path.Combine(report.ProjectDirectory, migratedProjectName));
|
|
|
|
|
}
|
2016-12-20 13:04:01 -10:00
|
|
|
|
}
|
2016-12-07 11:49:15 -10:00
|
|
|
|
|
2016-12-20 13:04:01 -10:00
|
|
|
|
foreach (var preExisting in report.PreExistingCsprojDependencies)
|
2016-12-07 11:49:15 -10:00
|
|
|
|
{
|
2016-12-20 13:04:01 -10:00
|
|
|
|
csprojFilesToAdd.Add(Path.Combine(report.ProjectDirectory, preExisting));
|
2016-12-07 11:49:15 -10:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-17 14:48:54 -08:00
|
|
|
|
Version version;
|
|
|
|
|
if (!Version.TryParse(_slnFile.VisualStudioVersion, out version) || version.Major < 15)
|
|
|
|
|
{
|
|
|
|
|
_slnFile.ProductDescription = ProductDescription;
|
|
|
|
|
_slnFile.VisualStudioVersion = VisualStudioVersion;
|
|
|
|
|
_slnFile.MinimumVisualStudioVersion = MinimumVisualStudioVersion;
|
|
|
|
|
}
|
2017-01-17 13:45:48 -08:00
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
|
_slnFile.Write();
|
2016-12-20 13:04:01 -10:00
|
|
|
|
|
|
|
|
|
foreach (var csprojFile in csprojFilesToAdd)
|
|
|
|
|
{
|
|
|
|
|
AddProject(_slnFile.FullPath, csprojFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddProject(string slnPath, string csprojPath)
|
|
|
|
|
{
|
|
|
|
|
List<string> args = new List<string>()
|
|
|
|
|
{
|
2017-01-06 10:58:23 -10:00
|
|
|
|
"sln",
|
2016-12-20 13:04:01 -10:00
|
|
|
|
slnPath,
|
2017-01-06 10:58:23 -10:00
|
|
|
|
"add",
|
2016-12-20 13:04:01 -10:00
|
|
|
|
csprojPath,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var dotnetPath = Path.Combine(AppContext.BaseDirectory, "dotnet.dll");
|
|
|
|
|
var addCommand = new ForwardingApp(dotnetPath, args);
|
|
|
|
|
addCommand.Execute();
|
2016-12-07 11:49:15 -10:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-29 01:58:37 -07:00
|
|
|
|
private void MoveProjectJsonArtifactsToBackup(MigrationReport migrationReport)
|
|
|
|
|
{
|
|
|
|
|
if (_skipBackup)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-12-20 14:19:37 -08:00
|
|
|
|
|
2016-10-29 01:58:37 -07:00
|
|
|
|
if (migrationReport.FailedProjectsCount > 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BackupProjects(migrationReport);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void BackupProjects(MigrationReport migrationReport)
|
2016-10-04 14:59:04 -07:00
|
|
|
|
{
|
Create backup folder in the directory where 'dotnet migrate' is executed (#5306)
* Create backup folder in the directory where 'dotnet migrate' is executed
With this change, 'dotnet migrate' will create the backup folder in the workspace directory rather
than the parent of the workspace directory. This solves two problems:
1. It makes it easier for the user where the backup is -- it's in the directory they targeted with
'dotnet migrate'.
2. It solves a problem of file oollisions with global.json files when migrating multiple projects.
Consider the following directory structure:
root
|
project1
|
global.json
|
src
|
project1
project2
|
global.json
|
src
|
project2
Prior to this change, running 'dotnet migrate' project1 and then running it again in project2
would have caused an exception to be thrown because the migration would try to produce a backup
folder like so:
root
|
backup
| |
| global.json
| |
| project1
| |
| project2
|
|
project1
|
src
|
project1
project2
|
src
|
project2
Now, we produce the following structure, which has no collisions:
root
|
project1
|
backup
| |
| global.json
| |
| project1
|
src
|
project1
|
project2
|
backup
| |
| global.json
| |
| project2
|
src
|
project2
In addition, to help avoid further collisions, a number is appened to the backup folder's name if
it already exists. So, if the user runs dotnet migrate again for some reason, they'll see backup_1,
backup_2, etc.
* Fix test helper
* Fix foolish bug causing infinite loop
* Fix up a couple more tests
* Rework MigrationBackupPlan to process all projects at once
* Fix up tests
* Still fixing tests
* Compute common root folder of projects to determine where backup folder should be placed
* Fix typo
* Fix test to not look in backup folder now that it's in a better location
2017-01-21 01:58:28 -08:00
|
|
|
|
var projectDirectories = new List<DirectoryInfo>();
|
2016-10-29 01:58:37 -07:00
|
|
|
|
foreach (var report in migrationReport.ProjectMigrationReports)
|
|
|
|
|
{
|
Create backup folder in the directory where 'dotnet migrate' is executed (#5306)
* Create backup folder in the directory where 'dotnet migrate' is executed
With this change, 'dotnet migrate' will create the backup folder in the workspace directory rather
than the parent of the workspace directory. This solves two problems:
1. It makes it easier for the user where the backup is -- it's in the directory they targeted with
'dotnet migrate'.
2. It solves a problem of file oollisions with global.json files when migrating multiple projects.
Consider the following directory structure:
root
|
project1
|
global.json
|
src
|
project1
project2
|
global.json
|
src
|
project2
Prior to this change, running 'dotnet migrate' project1 and then running it again in project2
would have caused an exception to be thrown because the migration would try to produce a backup
folder like so:
root
|
backup
| |
| global.json
| |
| project1
| |
| project2
|
|
project1
|
src
|
project1
project2
|
src
|
project2
Now, we produce the following structure, which has no collisions:
root
|
project1
|
backup
| |
| global.json
| |
| project1
|
src
|
project1
|
project2
|
backup
| |
| global.json
| |
| project2
|
src
|
project2
In addition, to help avoid further collisions, a number is appened to the backup folder's name if
it already exists. So, if the user runs dotnet migrate again for some reason, they'll see backup_1,
backup_2, etc.
* Fix test helper
* Fix foolish bug causing infinite loop
* Fix up a couple more tests
* Rework MigrationBackupPlan to process all projects at once
* Fix up tests
* Still fixing tests
* Compute common root folder of projects to determine where backup folder should be placed
* Fix typo
* Fix test to not look in backup folder now that it's in a better location
2017-01-21 01:58:28 -08:00
|
|
|
|
projectDirectories.Add(new DirectoryInfo(report.ProjectDirectory));
|
2016-10-29 01:58:37 -07:00
|
|
|
|
}
|
Create backup folder in the directory where 'dotnet migrate' is executed (#5306)
* Create backup folder in the directory where 'dotnet migrate' is executed
With this change, 'dotnet migrate' will create the backup folder in the workspace directory rather
than the parent of the workspace directory. This solves two problems:
1. It makes it easier for the user where the backup is -- it's in the directory they targeted with
'dotnet migrate'.
2. It solves a problem of file oollisions with global.json files when migrating multiple projects.
Consider the following directory structure:
root
|
project1
|
global.json
|
src
|
project1
project2
|
global.json
|
src
|
project2
Prior to this change, running 'dotnet migrate' project1 and then running it again in project2
would have caused an exception to be thrown because the migration would try to produce a backup
folder like so:
root
|
backup
| |
| global.json
| |
| project1
| |
| project2
|
|
project1
|
src
|
project1
project2
|
src
|
project2
Now, we produce the following structure, which has no collisions:
root
|
project1
|
backup
| |
| global.json
| |
| project1
|
src
|
project1
|
project2
|
backup
| |
| global.json
| |
| project2
|
src
|
project2
In addition, to help avoid further collisions, a number is appened to the backup folder's name if
it already exists. So, if the user runs dotnet migrate again for some reason, they'll see backup_1,
backup_2, etc.
* Fix test helper
* Fix foolish bug causing infinite loop
* Fix up a couple more tests
* Rework MigrationBackupPlan to process all projects at once
* Fix up tests
* Still fixing tests
* Compute common root folder of projects to determine where backup folder should be placed
* Fix typo
* Fix test to not look in backup folder now that it's in a better location
2017-01-21 01:58:28 -08:00
|
|
|
|
|
|
|
|
|
var backupPlan = new MigrationBackupPlan(
|
|
|
|
|
projectDirectories,
|
|
|
|
|
_workspaceDirectory);
|
|
|
|
|
|
|
|
|
|
backupPlan.PerformBackup();
|
|
|
|
|
|
2017-01-23 20:19:53 -08:00
|
|
|
|
Reporter.Output.WriteLine(string.Format(
|
|
|
|
|
LocalizableStrings.MigrateFilesBackupLocation,
|
|
|
|
|
backupPlan.RootBackupDirectory.FullName));
|
2016-10-29 01:58:37 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void WriteReport(MigrationReport migrationReport)
|
|
|
|
|
{
|
2016-10-04 14:59:04 -07:00
|
|
|
|
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));
|
2017-01-19 12:41:48 -08:00
|
|
|
|
|
|
|
|
|
Reporter.Output.WriteLine(LocalizableStrings.MigrationAdditionalHelp);
|
2016-10-04 14:59:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
2017-01-23 20:19:53 -08:00
|
|
|
|
sb.AppendLine(LocalizableStrings.MigrationReportSummary);
|
|
|
|
|
sb.AppendLine(
|
|
|
|
|
string.Format(LocalizableStrings.MigrationReportTotalProjects, migrationReport.MigratedProjectsCount));
|
|
|
|
|
sb.AppendLine(string.Format(
|
|
|
|
|
LocalizableStrings.MigrationReportSucceededProjects,
|
|
|
|
|
migrationReport.SucceededProjectsCount));
|
|
|
|
|
sb.AppendLine(string.Format(
|
|
|
|
|
LocalizableStrings.MigrationReportFailedProjects,
|
|
|
|
|
migrationReport.FailedProjectsCount));
|
2016-10-04 14:59:04 -07:00
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetProjectReportSuccessContent(ProjectMigrationReport projectMigrationReport, bool colored)
|
|
|
|
|
{
|
|
|
|
|
Func<string, string> GreenIfColored = (str) => colored ? str.Green() : str;
|
2017-01-23 20:19:53 -08:00
|
|
|
|
return GreenIfColored(string.Format(
|
|
|
|
|
LocalizableStrings.ProjectMigrationSucceeded,
|
|
|
|
|
projectMigrationReport.ProjectName,
|
|
|
|
|
projectMigrationReport.ProjectDirectory));
|
2016-10-04 14:59:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetProjectReportErrorContent(ProjectMigrationReport projectMigrationReport, bool colored)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
Func<string, string> RedIfColored = (str) => colored ? str.Red() : str;
|
|
|
|
|
|
|
|
|
|
if (projectMigrationReport.Errors.Any())
|
|
|
|
|
{
|
2017-01-23 20:19:53 -08:00
|
|
|
|
sb.AppendLine(RedIfColored(string.Format(
|
|
|
|
|
LocalizableStrings.ProjectMigrationFailed,
|
|
|
|
|
projectMigrationReport.ProjectName,
|
|
|
|
|
projectMigrationReport.ProjectDirectory)));
|
2016-10-04 14:59:04 -07:00
|
|
|
|
|
|
|
|
|
foreach (var error in projectMigrationReport.Errors.Select(e => e.GetFormattedErrorMessage()))
|
|
|
|
|
{
|
|
|
|
|
sb.AppendLine(RedIfColored(error));
|
|
|
|
|
}
|
2016-09-26 14:16:17 -07:00
|
|
|
|
}
|
2016-08-23 13:50:05 -07:00
|
|
|
|
|
2016-10-04 14:59:04 -07:00
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private TextWriter GetReportFileOutputTextWriter()
|
|
|
|
|
{
|
|
|
|
|
return File.CreateText(_reportFile);
|
2016-08-22 12:21:52 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 14:16:17 -07:00
|
|
|
|
private IEnumerable<string> GetProjectsToMigrate(string projectArg)
|
|
|
|
|
{
|
2016-10-04 10:39:55 -07:00
|
|
|
|
IEnumerable<string> projects = null;
|
|
|
|
|
|
2016-10-29 01:58:37 -07:00
|
|
|
|
if (projectArg.EndsWith(Project.FileName, StringComparison.OrdinalIgnoreCase))
|
2016-10-04 10:39:55 -07:00
|
|
|
|
{
|
|
|
|
|
projects = Enumerable.Repeat(projectArg, 1);
|
|
|
|
|
}
|
|
|
|
|
else if (projectArg.EndsWith(GlobalSettings.FileName, StringComparison.OrdinalIgnoreCase))
|
2016-09-26 14:16:17 -07:00
|
|
|
|
{
|
2016-12-07 11:49:15 -10:00
|
|
|
|
projects = GetProjectsFromGlobalJson(projectArg);
|
2016-10-29 01:58:37 -07:00
|
|
|
|
|
2016-10-10 15:38:25 -07:00
|
|
|
|
if (!projects.Any())
|
|
|
|
|
{
|
2017-01-23 20:19:53 -08:00
|
|
|
|
throw new GracefulException(LocalizableStrings.MigrationFailedToFindProjectInGlobalJson);
|
2016-10-10 15:38:25 -07:00
|
|
|
|
}
|
2016-09-26 14:16:17 -07:00
|
|
|
|
}
|
2016-12-07 11:49:15 -10:00
|
|
|
|
else if (File.Exists(projectArg) &&
|
|
|
|
|
string.Equals(Path.GetExtension(projectArg), ".sln", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
projects = GetProjectsFromSolution(projectArg);
|
|
|
|
|
|
|
|
|
|
if (!projects.Any())
|
|
|
|
|
{
|
2017-01-23 20:19:53 -08:00
|
|
|
|
throw new GracefulException(
|
|
|
|
|
string.Format(LocalizableStrings.MigrationUnableToFindProjects, projectArg));
|
2016-12-07 11:49:15 -10:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-26 14:16:17 -07:00
|
|
|
|
else if (Directory.Exists(projectArg))
|
|
|
|
|
{
|
2016-10-29 01:58:37 -07:00
|
|
|
|
projects = Directory.EnumerateFiles(projectArg, Project.FileName, SearchOption.AllDirectories);
|
|
|
|
|
|
2016-10-10 15:38:25 -07:00
|
|
|
|
if (!projects.Any())
|
|
|
|
|
{
|
2017-01-23 20:19:53 -08:00
|
|
|
|
throw new GracefulException(
|
|
|
|
|
string.Format(LocalizableStrings.MigrationProjectJsonNotFound, projectArg));
|
2016-10-10 15:38:25 -07:00
|
|
|
|
}
|
2016-09-26 14:16:17 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-01-23 20:19:53 -08:00
|
|
|
|
throw new GracefulException(
|
|
|
|
|
string.Format(LocalizableStrings.MigrationInvalidProjectArgument, projectArg));
|
2016-10-04 10:39:55 -07:00
|
|
|
|
}
|
2016-12-20 14:19:37 -08:00
|
|
|
|
|
|
|
|
|
foreach (var project in projects)
|
2016-10-04 10:39:55 -07:00
|
|
|
|
{
|
|
|
|
|
yield return GetProjectJsonPath(project);
|
2016-09-26 14:16:17 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-22 12:21:52 -07:00
|
|
|
|
private void EnsureNotNull(string variable, string message)
|
|
|
|
|
{
|
|
|
|
|
if (variable == null)
|
|
|
|
|
{
|
2017-01-12 15:42:36 -08:00
|
|
|
|
throw new GracefulException(message);
|
2016-08-22 12:21:52 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetProjectJsonPath(string projectJson)
|
|
|
|
|
{
|
2016-08-23 13:50:05 -07:00
|
|
|
|
projectJson = ProjectPathHelper.NormalizeProjectFilePath(projectJson);
|
|
|
|
|
|
2016-08-22 12:21:52 -07:00
|
|
|
|
if (File.Exists(projectJson))
|
|
|
|
|
{
|
|
|
|
|
return projectJson;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-23 20:19:53 -08:00
|
|
|
|
throw new GracefulException(string.Format(LocalizableStrings.MigratonUnableToFindProjectJson, projectJson));
|
2016-08-22 12:21:52 -07:00
|
|
|
|
}
|
2016-10-04 10:39:55 -07:00
|
|
|
|
|
|
|
|
|
private IEnumerable<string> GetProjectsFromGlobalJson(string globalJson)
|
|
|
|
|
{
|
2017-01-19 10:32:32 -08:00
|
|
|
|
var searchPaths = ProjectDependencyFinder.GetGlobalPaths(GetGlobalJsonDirectory(globalJson));
|
2016-10-04 10:39:55 -07:00
|
|
|
|
|
|
|
|
|
foreach (var searchPath in searchPaths)
|
|
|
|
|
{
|
|
|
|
|
var directory = new DirectoryInfo(searchPath);
|
|
|
|
|
|
|
|
|
|
if (!directory.Exists)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var projectDirectory in directory.EnumerateDirectories())
|
|
|
|
|
{
|
2016-12-07 11:49:15 -10:00
|
|
|
|
var projectFilePath = Path.Combine(projectDirectory.FullName, Project.FileName);
|
2016-10-04 10:39:55 -07:00
|
|
|
|
|
|
|
|
|
if (File.Exists(projectFilePath))
|
|
|
|
|
{
|
|
|
|
|
yield return projectFilePath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-07 11:49:15 -10:00
|
|
|
|
|
2017-01-19 10:32:32 -08:00
|
|
|
|
private string GetGlobalJsonDirectory(string globalJson)
|
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(globalJson))
|
|
|
|
|
{
|
2017-01-23 20:19:53 -08:00
|
|
|
|
throw new GracefulException(
|
|
|
|
|
string.Format(LocalizableStrings.MigrationUnableToFindGlobalJson, globalJson));
|
2017-01-19 10:32:32 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var globalJsonDirectory = Path.GetDirectoryName(globalJson);
|
|
|
|
|
return string.IsNullOrEmpty(globalJsonDirectory) ? "." : globalJsonDirectory;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-07 11:49:15 -10:00
|
|
|
|
private IEnumerable<string> GetProjectsFromSolution(string slnPath)
|
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(slnPath))
|
|
|
|
|
{
|
2017-01-23 20:19:53 -08:00
|
|
|
|
throw new GracefulException(
|
|
|
|
|
string.Format(LocalizableStrings.MigrationUnableToFindSolutionFile, slnPath));
|
2016-12-07 11:49:15 -10:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-13 06:45:00 -10:00
|
|
|
|
_slnFile = SlnFile.Read(slnPath);
|
2016-12-07 11:49:15 -10:00
|
|
|
|
|
|
|
|
|
foreach (var project in _slnFile.Projects)
|
|
|
|
|
{
|
2016-12-13 06:45:00 -10:00
|
|
|
|
var projectFilePath = Path.Combine(
|
|
|
|
|
_slnFile.BaseDirectory,
|
|
|
|
|
Path.GetDirectoryName(project.FilePath),
|
|
|
|
|
Project.FileName);
|
2016-12-07 11:49:15 -10:00
|
|
|
|
|
|
|
|
|
if (File.Exists(projectFilePath))
|
|
|
|
|
{
|
|
|
|
|
yield return projectFilePath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-22 12:21:52 -07:00
|
|
|
|
}
|
|
|
|
|
}
|