Allow migration of sln files (#4949)

* WIP Migrate sln files

* WIP add reference to redist

* Adding tests and fixing a few bugs

* Fix some tests

* Remove use of DeepClone

* Fix test build errors

* Fix more tests
This commit is contained in:
Justin Goshi 2016-12-07 11:49:15 -10:00 committed by GitHub
parent 79e6126b2a
commit 0831316321
33 changed files with 367 additions and 81 deletions

View file

@ -0,0 +1,17 @@
// 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(TestLibrary.Helper.GetMessage());
return 100;
}
}
}

View file

@ -0,0 +1,23 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestApp", "TestApp.xproj", "{0138CB8F-4AA9-4029-A21E-C07C30F425BA}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestLibrary", "..\TestLibrary\TestLibrary.xproj", "{DC0B35D0-8A36-4B52-8A11-B86739F055D2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Release|Any CPU.Build.0 = Release|Any CPU
{DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.23107" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.23107</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>0138cb8f-4aa9-4029-a21e-c07c30f425ba</ProjectGuid>
<RootNamespace>TestAppWithContents</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View file

@ -0,0 +1,30 @@
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"dependencies": {
"TestLibrary": {
"target": "project",
"version": "1.0.0-*"
},
"Microsoft.NETCore.App": "1.0.1"
},
"frameworks": {
"netcoreapp1.0": {}
},
"runtimes": {
"win7-x64": {},
"win7-x86": {},
"osx.10.10-x64": {},
"osx.10.11-x64": {},
"ubuntu.14.04-x64": {},
"ubuntu.16.04-x64": {},
"centos.7-x64": {},
"rhel.7.2-x64": {},
"debian.8-x64": {},
"fedora.23-x64": {},
"opensuse.13.2-x64": {}
}
}

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 Helper
{
public static string GetMessage()
{
return "This string came from the test library!";
}
}
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.23107" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.23107</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>dc0b35d0-8a36-4b52-8a11-b86739f055d2</ProjectGuid>
<RootNamespace>TestAppWithContents</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View file

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

View file

@ -15,6 +15,7 @@
<EmbeddedResource Include="sdkdefaults.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -3,41 +3,32 @@
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.Sln.Internal;
namespace Microsoft.DotNet.ProjectJsonMigration
{
internal class MigrationSettings
{
private string _msBuildProjectTemplatePath;
public string ProjectXProjFilePath { get; }
public string ProjectDirectory { get; }
public string OutputDirectory { get; }
public ProjectRootElement MSBuildProjectTemplate { get; }
public string MSBuildProjectTemplatePath { get; }
public string SdkDefaultsFilePath { get; }
public MigrationSettings(
string projectDirectory,
string outputDirectory,
ProjectRootElement msBuildProjectTemplate,
string projectXprojFilePath=null,
string sdkDefaultsFilePath=null) : this(
projectDirectory, outputDirectory, projectXprojFilePath, sdkDefaultsFilePath)
{
MSBuildProjectTemplate = msBuildProjectTemplate != null ? msBuildProjectTemplate.DeepClone() : null;
}
public SlnFile SolutionFile { get; }
public MigrationSettings(
string projectDirectory,
string outputDirectory,
string msBuildProjectTemplatePath,
string projectXprojFilePath=null,
string sdkDefaultsFilePath=null) : this(
projectDirectory, outputDirectory, projectXprojFilePath, sdkDefaultsFilePath)
string sdkDefaultsFilePath=null,
SlnFile solutionFile=null) : this(
projectDirectory, outputDirectory, projectXprojFilePath, sdkDefaultsFilePath, solutionFile)
{
_msBuildProjectTemplatePath = msBuildProjectTemplatePath;
MSBuildProjectTemplatePath = msBuildProjectTemplatePath;
MSBuildProjectTemplate = ProjectRootElement.Open(
_msBuildProjectTemplatePath,
MSBuildProjectTemplatePath,
new ProjectCollection(),
preserveFormatting: true);
}
@ -45,31 +36,44 @@ namespace Microsoft.DotNet.ProjectJsonMigration
private MigrationSettings(
string projectDirectory,
string outputDirectory,
ProjectRootElement msBuildProjectTemplate,
string projectXprojFilePath = null,
string sdkDefaultsFilePath=null)
string sdkDefaultsFilePath = null) : this(
projectDirectory, outputDirectory, projectXprojFilePath, sdkDefaultsFilePath, null)
{
MSBuildProjectTemplate = msBuildProjectTemplate != null ? msBuildProjectTemplate.DeepClone() : null;
}
private MigrationSettings(
string projectDirectory,
string outputDirectory,
string projectXprojFilePath,
string sdkDefaultsFilePath,
SlnFile solutionFile)
{
ProjectDirectory = projectDirectory;
OutputDirectory = outputDirectory;
ProjectXProjFilePath = projectXprojFilePath;
SdkDefaultsFilePath = sdkDefaultsFilePath;
SolutionFile = solutionFile;
}
public ProjectRootElement CloneMSBuildProjectTemplate()
public static MigrationSettings CreateMigrationSettingsTestHook(
string projectDirectory,
string outputDirectory,
ProjectRootElement msBuildProjectTemplate,
string projectXprojFilePath = null,
string sdkDefaultsFilePath = null)
{
ProjectRootElement msBuildProjectTemplateClone = null;
if(!string.IsNullOrEmpty(_msBuildProjectTemplatePath))
{
msBuildProjectTemplateClone = ProjectRootElement.Open(
_msBuildProjectTemplatePath,
new ProjectCollection(),
preserveFormatting: true);
}
else if(MSBuildProjectTemplate != null)
{
msBuildProjectTemplateClone = MSBuildProjectTemplate.DeepClone();
// Product code should not call this private constructor because we don't want to call DeepClone.
// Doing so means we lose formatting.
return new MigrationSettings(
projectDirectory,
outputDirectory,
msBuildProjectTemplate,
projectXprojFilePath,
sdkDefaultsFilePath);
}
return msBuildProjectTemplateClone;
}
}
}

View file

@ -9,6 +9,7 @@ using Microsoft.DotNet.Internal.ProjectModel.Graph;
using System.Linq;
using System.IO;
using Newtonsoft.Json.Linq;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Tools.Common;
using NuGet.Frameworks;
using NuGet.LibraryModel;
@ -19,18 +20,21 @@ namespace Microsoft.DotNet.ProjectJsonMigration
{
public IEnumerable<ProjectDependency> ResolveProjectDependencies(
IEnumerable<ProjectContext> projectContexts,
IEnumerable<string> preResolvedProjects = null)
IEnumerable<string> preResolvedProjects = null,
SlnFile solutionFile=null)
{
foreach (var projectContext in projectContexts)
{
foreach (var projectDependency in ResolveProjectDependencies(projectContext, preResolvedProjects))
foreach (var projectDependency in
ResolveProjectDependencies(projectContext, preResolvedProjects, solutionFile))
{
yield return projectDependency;
}
}
}
public IEnumerable<ProjectDependency> ResolveProjectDependencies(string projectDir, string xprojFile = null)
public IEnumerable<ProjectDependency> ResolveProjectDependencies(string projectDir,
string xprojFile = null, SlnFile solutionFile = null)
{
var projectContexts = ProjectContext.CreateContextForEachFramework(projectDir);
xprojFile = xprojFile ?? FindXprojFile(projectDir);
@ -41,13 +45,17 @@ namespace Microsoft.DotNet.ProjectJsonMigration
xproj = ProjectRootElement.Open(xprojFile);
}
return ResolveProjectDependencies(projectContexts, ResolveXProjProjectDependencyNames(xproj));
return ResolveProjectDependencies(
projectContexts,
ResolveXProjProjectDependencyNames(xproj),
solutionFile);
}
public IEnumerable<ProjectDependency> ResolveAllProjectDependenciesForFramework(
ProjectDependency projectToResolve,
NuGetFramework framework,
IEnumerable<string> preResolvedProjects=null)
IEnumerable<string> preResolvedProjects=null,
SlnFile solutionFile=null)
{
var projects = new List<ProjectDependency> { projectToResolve };
var allDependencies = new HashSet<ProjectDependency>();
@ -72,6 +80,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
projectContext.ProjectFile,
framework,
preResolvedProjects,
solutionFile,
HoistDependenciesThatAreNotDirectDependencies(projectToResolve, project)
);
projects.AddRange(dependencies);
@ -92,12 +101,13 @@ namespace Microsoft.DotNet.ProjectJsonMigration
Project project,
NuGetFramework framework,
IEnumerable<string> preResolvedProjects=null,
SlnFile solutionFile = null,
bool hoistedDependencies = false)
{
preResolvedProjects = preResolvedProjects ?? new HashSet<string>();
var possibleProjectDependencies =
FindPossibleProjectDependencies(project.ProjectFilePath, hoistedDependencies);
FindPossibleProjectDependencies(solutionFile, project.ProjectFilePath, hoistedDependencies);
var projectDependencies = new List<ProjectDependency>();
@ -174,13 +184,14 @@ namespace Microsoft.DotNet.ProjectJsonMigration
private IEnumerable<ProjectDependency> ResolveProjectDependencies(
ProjectContext projectContext,
IEnumerable<string> preResolvedProjects=null)
IEnumerable<string> preResolvedProjects=null,
SlnFile slnFile=null)
{
preResolvedProjects = preResolvedProjects ?? new HashSet<string>();
var projectExports = projectContext.CreateExporter("_").GetDependencies();
var possibleProjectDependencies =
FindPossibleProjectDependencies(projectContext.ProjectFile.ProjectFilePath);
FindPossibleProjectDependencies(slnFile, projectContext.ProjectFile.ProjectFilePath);
var projectDependencies = new List<ProjectDependency>();
foreach (var projectExport in
@ -221,6 +232,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
}
private Dictionary<string, ProjectDependency> FindPossibleProjectDependencies(
SlnFile slnFile,
string projectJsonFilePath,
bool hoistedDependencies = false)
{
@ -232,6 +244,9 @@ namespace Microsoft.DotNet.ProjectJsonMigration
var globalPaths = GetGlobalPaths(projectRootDirectory);
projectSearchPaths = projectSearchPaths.Union(globalPaths).ToList();
var solutionPaths = GetSolutionPaths(slnFile);
projectSearchPaths = projectSearchPaths.Union(solutionPaths).ToList();
var projects = new Dictionary<string, ProjectDependency>(StringComparer.Ordinal);
foreach (var project in GetPotentialProjects(projectSearchPaths, hoistedDependencies))
@ -352,6 +367,14 @@ namespace Microsoft.DotNet.ProjectJsonMigration
return paths;
}
internal static List<string> GetSolutionPaths(SlnFile solutionFile)
{
return (solutionFile == null)
? new List<string>()
: new List<string>(solutionFile.Projects.Select(p =>
Path.Combine(solutionFile.BaseDirectory.FullPath, Path.GetDirectoryName(p.FilePath))));
}
private static string ResolveRootDirectory(string projectPath)
{
var di = new DirectoryInfo(projectPath);

View file

@ -9,6 +9,7 @@ using Microsoft.DotNet.Internal.ProjectModel.Graph;
using Microsoft.DotNet.Cli;
using System.Linq;
using System.IO;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.ProjectJsonMigration.Rules;
using Microsoft.DotNet.Tools.Common;
@ -37,8 +38,6 @@ namespace Microsoft.DotNet.ProjectJsonMigration
MigrationRuleInputs rootInputs = ComputeMigrationRuleInputs(rootSettings);
IEnumerable<ProjectDependency> projectDependencies = null;
var tempMSBuildProjectTemplate = rootSettings.CloneMSBuildProjectTemplate();
try
{
// Verify up front so we can prefer these errors over an unresolved project dependency
@ -46,7 +45,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration
projectDependencies = ResolveTransitiveClosureProjectDependencies(
rootSettings.ProjectDirectory,
rootSettings.ProjectXProjFilePath);
rootSettings.ProjectXProjFilePath,
rootSettings.SolutionFile);
}
catch (MigrationException e)
{
@ -74,7 +74,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
var projectDir = Path.GetDirectoryName(project.ProjectFilePath);
var settings = new MigrationSettings(projectDir,
projectDir,
tempMSBuildProjectTemplate);
rootSettings.MSBuildProjectTemplatePath);
MigrateProject(settings);
projectMigrationReports.Add(MigrateProject(settings));
}
@ -98,10 +98,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration
}
}
private IEnumerable<ProjectDependency> ResolveTransitiveClosureProjectDependencies(string rootProject, string xprojFile)
private IEnumerable<ProjectDependency> ResolveTransitiveClosureProjectDependencies(
string rootProject, string xprojFile, SlnFile solutionFile)
{
HashSet<ProjectDependency> projectsMap = new HashSet<ProjectDependency>(new ProjectDependencyComparer());
var projectDependencies = _projectDependencyFinder.ResolveProjectDependencies(rootProject, xprojFile);
var projectDependencies = _projectDependencyFinder.ResolveProjectDependencies(rootProject, xprojFile, solutionFile);
Queue<ProjectDependency> projectsQueue = new Queue<ProjectDependency>(projectDependencies);
while (projectsQueue.Count() != 0)

View file

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
using Microsoft.DotNet.Internal.ProjectModel;
@ -51,6 +52,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
null,
project.Dependencies,
migrationRuleInputs.ProjectXproj,
migrationSettings.SolutionFile,
itemGroup: noFrameworkPackageReferenceItemGroup);
MigrationTrace.Instance.WriteLine($"Migrating {targetFrameworks.Count()} target frameworks");
@ -65,7 +67,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
migrationRuleInputs.OutputMSBuildProject,
targetFramework.FrameworkName,
targetFramework.Dependencies,
migrationRuleInputs.ProjectXproj);
migrationRuleInputs.ProjectXproj,
migrationSettings.SolutionFile);
}
MigrateTools(project, migrationRuleInputs.OutputMSBuildProject);
@ -213,9 +216,10 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
NuGetFramework framework,
IEnumerable<ProjectLibraryDependency> dependencies,
ProjectRootElement xproj,
SlnFile solutionFile,
ProjectItemGroupElement itemGroup=null)
{
var projectDependencies = new HashSet<string>(GetAllProjectReferenceNames(project, framework, xproj));
var projectDependencies = new HashSet<string>(GetAllProjectReferenceNames(project, framework, xproj, solutionFile));
var packageDependencies = dependencies.Where(d => !projectDependencies.Contains(d.Name)).ToList();
string condition = framework?.GetMSBuildCondition() ?? "";
@ -360,7 +364,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
private IEnumerable<string> GetAllProjectReferenceNames(
Project project,
NuGetFramework framework,
ProjectRootElement xproj)
ProjectRootElement xproj,
SlnFile solutionFile)
{
var csprojReferenceItems = _projectDependencyFinder.ResolveXProjProjectDependencies(xproj);
var migratedXProjDependencyPaths = csprojReferenceItems.SelectMany(p => p.Includes());
@ -370,7 +375,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
var projectDependencies = _projectDependencyFinder.ResolveDirectProjectDependenciesForFramework(
project,
framework,
preResolvedProjects: migratedXProjDependencyNames);
preResolvedProjects: migratedXProjDependencyNames,
solutionFile: solutionFile);
return projectDependencies.Select(p => p.Name).Concat(migratedXProjDependencyNames);
}

View file

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
using Microsoft.DotNet.Internal.ProjectModel;
using Microsoft.DotNet.Tools.Common;
@ -37,6 +38,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
MigrateProjectJsonProjectDependencies(
migrationRuleInputs.ProjectContexts,
migratedXProjDependencyNames,
migrationSettings.SolutionFile,
migrationRuleInputs.OutputMSBuildProject);
}
@ -79,6 +81,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
public void MigrateProjectJsonProjectDependencies(
IEnumerable<ProjectContext> projectContexts,
HashSet<string> migratedXProjDependencyNames,
SlnFile solutionFile,
ProjectRootElement outputMSBuildProject)
{
if(projectContexts.Any())
@ -87,6 +90,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
projectContexts.First().ProjectFile,
null,
migratedXProjDependencyNames,
solutionFile,
outputMSBuildProject);
}
@ -96,6 +100,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
projectContext.ProjectFile,
projectContext.TargetFramework,
migratedXProjDependencyNames,
solutionFile,
outputMSBuildProject);
}
}
@ -104,12 +109,14 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
Project project,
NuGetFramework framework,
HashSet<string> migratedXProjDependencyNames,
SlnFile solutionFile,
ProjectRootElement outputMSBuildProject)
{
var projectDependencies = _projectDependencyFinder.ResolveAllProjectDependenciesForFramework(
new ProjectDependency(project.Name, project.ProjectFilePath, false),
framework,
migratedXProjDependencyNames);
migratedXProjDependencyNames,
solutionFile);
var projectDependencyTransformResults =
projectDependencies.Select(p =>

View file

@ -6,12 +6,14 @@ namespace Microsoft.DotNet.Tools.Migrate
public const string AppDescription = "Command used to migrate project.json projects to msbuild";
public const string CmdProjectArgument = "PROJECT_JSON/GLOBAL_JSON/PROJECT_DIR";
public const string CmdProjectArgument = "PROJECT_JSON/GLOBAL_JSON/SOLUTION_FILE/PROJECT_DIR";
public const string CmdProjectArgumentDescription =
@"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 solution.sln file, it will migrate the projects referenced in the solution.
or
- a directory to migrate, it will recursively search for project.json files to migrate.
Defaults to current directory if nothing is specified.";

View file

@ -8,6 +8,7 @@ using System.Linq;
using System.Text;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectJsonMigration;
using Microsoft.DotNet.Internal.ProjectModel;
@ -18,6 +19,9 @@ namespace Microsoft.DotNet.Tools.Migrate
{
public partial class MigrateCommand
{
private const string CSharpProjectTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
private SlnFile _slnFile;
private readonly DirectoryInfo _workspaceDirectory;
private readonly DirectoryInfo _backupDirectory;
private readonly string _templateFile;
@ -70,7 +74,9 @@ namespace Microsoft.DotNet.Tools.Migrate
projectDirectory,
outputDirectory,
msBuildTemplatePath,
_xprojFilePath);
_xprojFilePath,
null,
_slnFile);
var projectMigrationReport = new ProjectMigrator().Migrate(migrationSettings, _skipProjectReferences);
if (migrationReport == null)
@ -87,11 +93,46 @@ namespace Microsoft.DotNet.Tools.Migrate
temporaryDotnetNewProject.Clean();
UpdateSolutionFile(migrationReport);
MoveProjectJsonArtifactsToBackup(migrationReport);
return migrationReport.FailedProjectsCount;
}
private void UpdateSolutionFile(MigrationReport migrationReport)
{
if (_slnFile == null)
{
return;
}
if (migrationReport.FailedProjectsCount > 0)
{
return;
}
foreach (var project in _slnFile.Projects)
{
var projectDirectory = Path.Combine(
_slnFile.BaseDirectory.FullPath,
Path.GetDirectoryName(project.FilePath));
var csprojFiles = new DirectoryInfo(projectDirectory)
.EnumerateFiles()
.Where(f => f.Extension == ".csproj");
if (csprojFiles.Count() == 1)
{
project.FilePath = Path.Combine(Path.GetDirectoryName(project.FilePath), csprojFiles.First().Name);
project.TypeGuid = CSharpProjectTypeGuid;
}
}
_slnFile.Write(Path.Combine(_slnFile.BaseDirectory.FullPath,
Path.GetFileName(_slnFile.FileName)));
}
private void MoveProjectJsonArtifactsToBackup(MigrationReport migrationReport)
{
if (_skipBackup)
@ -276,6 +317,16 @@ namespace Microsoft.DotNet.Tools.Migrate
throw new Exception("Unable to find any projects in global.json");
}
}
else if (File.Exists(projectArg) &&
string.Equals(Path.GetExtension(projectArg), ".sln", StringComparison.OrdinalIgnoreCase))
{
projects = GetProjectsFromSolution(projectArg);
if (!projects.Any())
{
throw new Exception($"Unable to find any projects in {projectArg}");
}
}
else if (Directory.Exists(projectArg))
{
projects = Directory.EnumerateFiles(projectArg, Project.FileName, SearchOption.AllDirectories);
@ -287,7 +338,7 @@ namespace Microsoft.DotNet.Tools.Migrate
}
else
{
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.");
throw new Exception($"Invalid project argument - '{projectArg}' is not a project.json, global.json, or solution.sln file and a directory named '{projectArg}' doesn't exist.");
}
foreach(var project in projects)
@ -336,7 +387,7 @@ namespace Microsoft.DotNet.Tools.Migrate
foreach (var projectDirectory in directory.EnumerateDirectories())
{
var projectFilePath = Path.Combine(projectDirectory.FullName, "project.json");
var projectFilePath = Path.Combine(projectDirectory.FullName, Project.FileName);
if (File.Exists(projectFilePath))
{
@ -345,5 +396,28 @@ namespace Microsoft.DotNet.Tools.Migrate
}
}
}
private IEnumerable<string> GetProjectsFromSolution(string slnPath)
{
if (!File.Exists(slnPath))
{
throw new Exception($"Unable to find the solution file at {slnPath}");
}
_slnFile = new SlnFile();
_slnFile.Read(slnPath);
foreach (var project in _slnFile.Projects)
{
var projectFilePath = Path.Combine(_slnFile.BaseDirectory.FullPath,
Path.Combine(Path.GetDirectoryName(project.FilePath), Project.FileName));
if (File.Exists(projectFilePath))
{
yield return projectFilePath;
}
}
}
}
}

View file

@ -26,6 +26,7 @@
<ProjectReference Include="../Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.csproj" />
<ProjectReference Include="../Microsoft.DotNet.Archive/Microsoft.DotNet.Archive.csproj" />
<ProjectReference Include="../Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj" />
<ProjectReference Include="../Microsoft.DotNet.Cli.Sln.Internal/Microsoft.DotNet.Cli.Sln.Internal.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -41,6 +41,7 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">
<ProjectReference Include="..\dotnet\dotnet.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Archive\Microsoft.DotNet.Archive.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Configurer\Microsoft.DotNet.Configurer.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.InternalAbstractions\Microsoft.DotNet.InternalAbstractions.csproj" />

View file

@ -27,7 +27,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectDirectoryRelativeFilePaths = EnumerateFilesWithRelativePath(testProjectDirectory);
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(testProjectDirectory, outputDirectory, mockProj);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(testProjectDirectory, outputDirectory, mockProj);
var projectMigrator = new ProjectMigrator(new FakeEmptyMigrationRule());
projectMigrator.Migrate(testSettings);
@ -46,7 +46,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
.Path;
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(testProjectDirectory, testProjectDirectory, mockProj);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(testProjectDirectory, testProjectDirectory, mockProj);
var projectMigrator = new ProjectMigrator(new FakeEmptyMigrationRule());
var report = projectMigrator.Migrate(testSettings);
@ -67,7 +67,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
.Path;
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(testProjectDirectory, testProjectDirectory, mockProj);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(testProjectDirectory, testProjectDirectory, mockProj);
var projectMigrator = new ProjectMigrator(new FakeEmptyMigrationRule());
var report = projectMigrator.Migrate(testSettings);

View file

@ -22,6 +22,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.ProjectJsonMigration\Microsoft.DotNet.ProjectJsonMigration.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />

View file

@ -25,7 +25,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext =
ProjectContext.Create(projectDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
_mockProject = ProjectRootElement.Create();
var testSettings = new MigrationSettings(projectDirectory, projectDirectory, _mockProject, null);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(projectDirectory, projectDirectory, _mockProject, null);
var testInputs = new MigrationRuleInputs(
new[] {projectContext},
_mockProject,

View file

@ -40,7 +40,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var testProjectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithRuntimeOptions").Path;
var projectContext = ProjectContext.Create(testProjectDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var testSettings = new MigrationSettings(testProjectDirectory, testProjectDirectory, templateProj);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(testProjectDirectory, testProjectDirectory, templateProj);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, templateProj, templateProj.AddItemGroup(),
templateProj.AddPropertyGroup());
new MigrateBuildOptionsRule().Apply(testSettings, testInputs);

View file

@ -27,7 +27,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(appDirectory, appDirectory, mockProj, null);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(appDirectory, appDirectory, mockProj, null);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),
mockProj.AddPropertyGroup());
new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
@ -51,7 +51,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(appDirectory, appDirectory, mockProj, null);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(appDirectory, appDirectory, mockProj, null);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),
mockProj.AddPropertyGroup());
new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
@ -71,7 +71,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(appDirectory, appDirectory, mockProj, null);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(appDirectory, appDirectory, mockProj, null);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),
mockProj.AddPropertyGroup());
new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
@ -97,7 +97,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(appDirectory, appDirectory, mockProj);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(appDirectory, appDirectory, mockProj);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(), mockProj.AddPropertyGroup());
Action action = () => new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
@ -260,7 +260,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(appDirectory, FrameworkConstants.CommonFrameworks.Net451);
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(appDirectory, appDirectory, mockProj, null);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(appDirectory, appDirectory, mockProj, null);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),
mockProj.AddPropertyGroup());
new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);
@ -338,7 +338,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(appDirectory, targetFramework);
var mockProj = ProjectRootElement.Create();
var testSettings = new MigrationSettings(appDirectory, appDirectory, mockProj, null);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(appDirectory, appDirectory, mockProj, null);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, mockProj, mockProj.AddItemGroup(),
mockProj.AddPropertyGroup());
new MigrateProjectDependenciesRule().Apply(testSettings, testInputs);

View file

@ -34,7 +34,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(projectDir, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var testSettings = new MigrationSettings(projectDir, projectDir, default(ProjectRootElement));
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(projectDir, projectDir, default(ProjectRootElement));
var testInputs = new MigrationRuleInputs(new[] { projectContext }, null, null, null);
new MigrateRuntimeOptionsRule().Apply(testSettings, testInputs);
@ -54,7 +54,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(projectDir, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var testSettings = new MigrationSettings(projectDir, projectDir, default(ProjectRootElement));
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(projectDir, projectDir, default(ProjectRootElement));
var testInputs = new MigrationRuleInputs(new[] { projectContext }, null, null, null);
new MigrateRuntimeOptionsRule().Apply(testSettings, testInputs);

View file

@ -30,7 +30,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContext = ProjectContext.Create(testDirectory, FrameworkConstants.CommonFrameworks.NetCoreApp10);
var mockProj = ProjectRootElement.Create();
var migrationSettings = new MigrationSettings(testDirectory, testDirectory, mockProj);
var migrationSettings = MigrationSettings.CreateMigrationSettingsTestHook(testDirectory, testDirectory, mockProj);
var migrationInputs = new MigrationRuleInputs(
new[] { projectContext },
mockProj,
@ -54,7 +54,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContexts = ProjectContext.CreateContextForEachFramework(testDirectory);
var mockProj = ProjectRootElement.Create();
var migrationSettings = new MigrationSettings(testDirectory, testDirectory, mockProj);
var migrationSettings = MigrationSettings.CreateMigrationSettingsTestHook(testDirectory, testDirectory, mockProj);
var migrationInputs = new MigrationRuleInputs(
projectContexts,
mockProj,
@ -79,7 +79,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var projectContexts = ProjectContext.CreateContextForEachFramework(testDirectory);
var mockProj = ProjectRootElement.Create();
var migrationSettings = new MigrationSettings(testDirectory, testDirectory, mockProj);
var migrationSettings = MigrationSettings.CreateMigrationSettingsTestHook(testDirectory, testDirectory, mockProj);
var migrationInputs = new MigrationRuleInputs(
projectContexts,
mockProj,
@ -109,7 +109,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
var mockProj = ProjectRootElement.Create();
// Run BuildOptionsRule
var migrationSettings = new MigrationSettings(testDirectory, testDirectory, mockProj);
var migrationSettings = MigrationSettings.CreateMigrationSettingsTestHook(testDirectory, testDirectory, mockProj);
var migrationInputs = new MigrationRuleInputs(
projectContexts,
mockProj,

View file

@ -28,7 +28,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
ProjectContext projectContext, string testDirectory, ProjectRootElement xproj)
{
var project = ProjectRootElement.Create();
var testSettings = new MigrationSettings(testDirectory, testDirectory, project);
var testSettings = MigrationSettings.CreateMigrationSettingsTestHook(testDirectory, testDirectory, project);
var testInputs = new MigrationRuleInputs(new[] {projectContext}, project,
project.AddItemGroup(),
project.AddPropertyGroup(),

View file

@ -449,6 +449,25 @@ namespace Microsoft.DotNet.Migration.Tests
File.ReadAllText(migrationOutputFile).Should().Contain("MIGRATE1018");
}
[Fact]
public void It_migrates_sln()
{
var rootDirectory = TestAssetsManager.CreateTestInstance(
"TestAppWithSlnAndMultipleProjects",
callingMethod: "a").Path;
var testAppProjectDirectory = Path.Combine(rootDirectory, "TestApp");
var testLibProjectDirectory = Path.Combine(rootDirectory, "TestLibrary");
string slnPath = Path.Combine(testAppProjectDirectory, "TestApp.sln");
CleanBinObj(testAppProjectDirectory);
CleanBinObj(testLibProjectDirectory);
MigrateProject(slnPath);
Restore(testAppProjectDirectory, "TestApp.csproj");
BuildMSBuild(testAppProjectDirectory, "TestApp.sln", "Release");
}
private void VerifyAutoInjectedDesktopReferences(string projectDirectory, string projectName, bool shouldBePresent)
{
if (projectName != null)
@ -637,7 +656,11 @@ namespace Microsoft.DotNet.Migration.Tests
if (projectName != null)
{
command.Execute($"{projectName}.csproj /p:SkipInvalidConfigurations=true;_InvalidConfigurationWarning=false")
if (!Path.HasExtension(projectName))
{
projectName += ".csproj";
}
command.Execute($"{projectName} /p:SkipInvalidConfigurations=true;_InvalidConfigurationWarning=false")
.Should().Pass();
}
else
@ -653,7 +676,7 @@ namespace Microsoft.DotNet.Migration.Tests
string configuration="Debug",
string runtime=null)
{
if (projectName != null)
if (projectName != null && !Path.HasExtension(projectName))
{
projectName = projectName + ".csproj";
}

View file

@ -19,6 +19,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.ProjectJsonMigration\Microsoft.DotNet.ProjectJsonMigration.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />

View file

@ -18,6 +18,7 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\dotnet\dotnet.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.TestFramework\Microsoft.DotNet.TestFramework.csproj">
<FromP2P>true</FromP2P>
</ProjectReference>

View file

@ -18,6 +18,7 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\dotnet\dotnet.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.TestFramework\Microsoft.DotNet.TestFramework.csproj">
<FromP2P>true</FromP2P>
</ProjectReference>

View file

@ -17,6 +17,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\dotnet\dotnet.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj">
<FromP2P>true</FromP2P>

View file

@ -31,6 +31,7 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\dotnet\dotnet.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.TestFramework\Microsoft.DotNet.TestFramework.csproj">
<FromP2P>true</FromP2P>