2016-08-22 12:21:34 -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.
|
|
|
|
|
|
2016-09-21 17:27:02 -07:00
|
|
|
|
using System;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
using System.Collections.Generic;
|
2016-08-23 13:50:05 -07:00
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
using Microsoft.Build.Construction;
|
2016-12-07 11:49:15 -10:00
|
|
|
|
using Microsoft.DotNet.Cli.Sln.Internal;
|
2016-08-23 13:50:05 -07:00
|
|
|
|
using Microsoft.DotNet.ProjectJsonMigration.Transforms;
|
2016-10-27 18:46:43 -07:00
|
|
|
|
using Microsoft.DotNet.Internal.ProjectModel;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
using Microsoft.DotNet.Tools.Common;
|
2016-09-21 21:14:48 -07:00
|
|
|
|
using NuGet.Frameworks;
|
2016-11-03 16:54:15 -07:00
|
|
|
|
using NuGet.LibraryModel;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
|
2016-08-23 13:50:05 -07:00
|
|
|
|
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
2016-10-27 18:46:43 -07:00
|
|
|
|
internal class MigrateProjectDependenciesRule : IMigrationRule
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
|
|
|
|
private readonly ITransformApplicator _transformApplicator;
|
2016-09-21 21:14:48 -07:00
|
|
|
|
private readonly ProjectDependencyFinder _projectDependencyFinder;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
private string _projectDirectory;
|
|
|
|
|
|
2016-08-23 13:50:05 -07:00
|
|
|
|
public MigrateProjectDependenciesRule(ITransformApplicator transformApplicator = null)
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
|
|
|
|
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
2016-09-21 21:14:48 -07:00
|
|
|
|
_projectDependencyFinder = new ProjectDependencyFinder();
|
2016-08-22 12:21:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
|
|
|
|
{
|
|
|
|
|
_projectDirectory = migrationSettings.ProjectDirectory;
|
|
|
|
|
|
2016-09-23 14:48:54 -07:00
|
|
|
|
var migratedXProjDependencyPaths = MigrateXProjProjectDependencies(migrationRuleInputs);
|
2016-10-27 16:35:35 -07:00
|
|
|
|
var migratedXProjDependencyNames = new HashSet<string>(
|
|
|
|
|
migratedXProjDependencyPaths.Select(p =>
|
|
|
|
|
Path.GetFileNameWithoutExtension(PathUtility.GetPathWithDirectorySeparator(p))));
|
2016-09-21 21:14:48 -07:00
|
|
|
|
MigrateProjectJsonProjectDependencies(
|
|
|
|
|
migrationRuleInputs.ProjectContexts,
|
2016-12-07 11:49:15 -10:00
|
|
|
|
migratedXProjDependencyNames,
|
|
|
|
|
migrationSettings.SolutionFile,
|
2016-09-21 21:14:48 -07:00
|
|
|
|
migrationRuleInputs.OutputMSBuildProject);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-23 14:48:54 -07:00
|
|
|
|
private IEnumerable<string> MigrateXProjProjectDependencies(MigrationRuleInputs migrationRuleInputs)
|
2016-09-21 17:27:02 -07:00
|
|
|
|
{
|
2016-09-23 14:48:54 -07:00
|
|
|
|
var csprojReferenceItems = _projectDependencyFinder.ResolveXProjProjectDependencies(migrationRuleInputs.ProjectXproj);
|
|
|
|
|
|
|
|
|
|
if (!csprojReferenceItems.Any())
|
2016-09-21 17:27:02 -07:00
|
|
|
|
{
|
|
|
|
|
return Enumerable.Empty<string>();
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-22 12:51:23 -07:00
|
|
|
|
var csprojTransformedReferences = new List<ProjectItemElement>();
|
|
|
|
|
|
|
|
|
|
foreach (var csprojReferenceItem in csprojReferenceItems)
|
2016-09-21 17:27:02 -07:00
|
|
|
|
{
|
2016-09-22 12:51:23 -07:00
|
|
|
|
var conditionChain = csprojReferenceItem.ConditionChain();
|
|
|
|
|
var condition = string.Join(" and ", conditionChain);
|
2016-09-21 17:27:02 -07:00
|
|
|
|
|
2016-09-22 12:51:23 -07:00
|
|
|
|
var referenceInclude = string.Join(";", csprojReferenceItem.Includes()
|
|
|
|
|
.Where(include =>
|
|
|
|
|
string.Equals(Path.GetExtension(include), ".csproj", StringComparison.OrdinalIgnoreCase)));
|
|
|
|
|
|
|
|
|
|
var transformItem = ProjectDependencyStringTransform.Transform(referenceInclude);
|
|
|
|
|
transformItem.Condition = condition;
|
|
|
|
|
|
|
|
|
|
csprojTransformedReferences.Add(transformItem);
|
|
|
|
|
}
|
2016-09-23 14:48:54 -07:00
|
|
|
|
|
2016-12-16 20:47:54 -08:00
|
|
|
|
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.MigratingCountXprojToCsprojReferences, nameof(MigrateProjectDependenciesRule), csprojTransformedReferences.Count()));
|
2016-09-21 17:27:02 -07:00
|
|
|
|
|
2016-09-22 12:51:23 -07:00
|
|
|
|
foreach (var csprojTransformedReference in csprojTransformedReferences)
|
2016-09-21 17:27:02 -07:00
|
|
|
|
{
|
2016-10-20 11:00:41 -07:00
|
|
|
|
_transformApplicator.Execute(csprojTransformedReference, migrationRuleInputs.CommonItemGroup, true);
|
2016-09-21 17:27:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-22 12:51:23 -07:00
|
|
|
|
return csprojTransformedReferences.SelectMany(r => r.Includes());
|
2016-09-21 17:27:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void MigrateProjectJsonProjectDependencies(
|
2016-09-21 21:14:48 -07:00
|
|
|
|
IEnumerable<ProjectContext> projectContexts,
|
2016-09-22 17:44:34 -07:00
|
|
|
|
HashSet<string> migratedXProjDependencyNames,
|
2016-12-07 11:49:15 -10:00
|
|
|
|
SlnFile solutionFile,
|
2016-09-21 21:14:48 -07:00
|
|
|
|
ProjectRootElement outputMSBuildProject)
|
2016-09-21 17:27:02 -07:00
|
|
|
|
{
|
2016-10-21 18:00:17 -07:00
|
|
|
|
if(projectContexts.Any())
|
|
|
|
|
{
|
|
|
|
|
MigrateProjectJsonProjectDependency(
|
|
|
|
|
projectContexts.First().ProjectFile,
|
|
|
|
|
null,
|
|
|
|
|
migratedXProjDependencyNames,
|
2016-12-07 11:49:15 -10:00
|
|
|
|
solutionFile,
|
2016-10-21 18:00:17 -07:00
|
|
|
|
outputMSBuildProject);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-21 21:14:48 -07:00
|
|
|
|
foreach (var projectContext in projectContexts)
|
2016-09-21 17:27:02 -07:00
|
|
|
|
{
|
2016-10-21 18:00:17 -07:00
|
|
|
|
MigrateProjectJsonProjectDependency(
|
|
|
|
|
projectContext.ProjectFile,
|
|
|
|
|
projectContext.TargetFramework,
|
|
|
|
|
migratedXProjDependencyNames,
|
2016-12-07 11:49:15 -10:00
|
|
|
|
solutionFile,
|
2016-10-21 18:00:17 -07:00
|
|
|
|
outputMSBuildProject);
|
2016-09-21 17:27:02 -07:00
|
|
|
|
}
|
2016-10-21 18:00:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void MigrateProjectJsonProjectDependency(
|
|
|
|
|
Project project,
|
|
|
|
|
NuGetFramework framework,
|
|
|
|
|
HashSet<string> migratedXProjDependencyNames,
|
2016-12-07 11:49:15 -10:00
|
|
|
|
SlnFile solutionFile,
|
2016-10-21 18:00:17 -07:00
|
|
|
|
ProjectRootElement outputMSBuildProject)
|
|
|
|
|
{
|
2016-10-27 16:35:35 -07:00
|
|
|
|
var projectDependencies = _projectDependencyFinder.ResolveAllProjectDependenciesForFramework(
|
2016-11-03 10:27:51 -07:00
|
|
|
|
new ProjectDependency(project.Name, project.ProjectFilePath, false),
|
2016-10-21 18:00:17 -07:00
|
|
|
|
framework,
|
2016-12-07 11:49:15 -10:00
|
|
|
|
migratedXProjDependencyNames,
|
|
|
|
|
solutionFile);
|
2016-10-21 18:00:17 -07:00
|
|
|
|
|
|
|
|
|
var projectDependencyTransformResults =
|
2016-11-03 10:27:51 -07:00
|
|
|
|
projectDependencies.Select(p =>
|
|
|
|
|
p.Hoisted ?
|
|
|
|
|
HoistedDependencyTransform.Transform(p) :
|
|
|
|
|
ProjectDependencyTransform.Transform(p));
|
2016-09-21 17:27:02 -07:00
|
|
|
|
|
2016-10-21 18:00:17 -07:00
|
|
|
|
if (projectDependencyTransformResults.Any())
|
|
|
|
|
{
|
|
|
|
|
AddProjectDependenciesToNewItemGroup(
|
|
|
|
|
outputMSBuildProject.AddItemGroup(),
|
|
|
|
|
projectDependencyTransformResults,
|
|
|
|
|
framework);
|
|
|
|
|
}
|
2016-11-03 16:54:15 -07:00
|
|
|
|
|
|
|
|
|
HoistFrameworkAssembliesForProjectDependencies(projectDependencies, outputMSBuildProject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HoistFrameworkAssembliesForProjectDependencies(
|
|
|
|
|
IEnumerable<ProjectDependency> projectDependencies,
|
|
|
|
|
ProjectRootElement outputMSBuildProject)
|
|
|
|
|
{
|
|
|
|
|
foreach (var projectDependency in projectDependencies)
|
|
|
|
|
{
|
|
|
|
|
HoistFrameworkAssembliesForDesktopFrameworks(projectDependency, outputMSBuildProject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HoistFrameworkAssembliesForDesktopFrameworks(
|
|
|
|
|
ProjectDependency projectDependency,
|
|
|
|
|
ProjectRootElement outputMSBuildProject)
|
|
|
|
|
{
|
|
|
|
|
var targetFrameworks = ProjectReader
|
|
|
|
|
.GetProject(projectDependency.ProjectFilePath)
|
|
|
|
|
.GetTargetFrameworks().Where(p => !p.FrameworkName.IsPackageBased);
|
|
|
|
|
|
|
|
|
|
foreach (var targetFramework in targetFrameworks)
|
|
|
|
|
{
|
|
|
|
|
HoistFrameworkAssemblies(targetFramework, outputMSBuildProject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HoistFrameworkAssemblies(
|
|
|
|
|
TargetFrameworkInformation targetFramework,
|
|
|
|
|
ProjectRootElement outputMSBuildProject)
|
|
|
|
|
{
|
|
|
|
|
var frameworkAssemblies = targetFramework.Dependencies.Where(d =>
|
|
|
|
|
d.LibraryRange.TypeConstraint == LibraryDependencyTarget.Reference);
|
|
|
|
|
if(frameworkAssemblies.Any())
|
|
|
|
|
{
|
|
|
|
|
var condition = targetFramework.FrameworkName.GetMSBuildCondition();
|
|
|
|
|
var itemGroup =
|
|
|
|
|
outputMSBuildProject.ItemGroups.FirstOrDefault(i => i.Condition == condition) ??
|
|
|
|
|
outputMSBuildProject.AddItemGroup();
|
|
|
|
|
itemGroup.Condition = condition;
|
|
|
|
|
|
|
|
|
|
foreach (var frameworkAssembly in frameworkAssemblies)
|
|
|
|
|
{
|
|
|
|
|
_transformApplicator.Execute(
|
|
|
|
|
FrameworkDependencyTransform.Transform(frameworkAssembly),
|
|
|
|
|
itemGroup,
|
|
|
|
|
mergeExisting: true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-23 13:50:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-21 21:14:48 -07:00
|
|
|
|
private void AddProjectDependenciesToNewItemGroup(
|
|
|
|
|
ProjectItemGroupElement itemGroup,
|
|
|
|
|
IEnumerable<ProjectItemElement> projectDependencyTransformResults,
|
|
|
|
|
NuGetFramework targetFramework)
|
2016-08-23 13:50:05 -07:00
|
|
|
|
{
|
2016-09-21 21:14:48 -07:00
|
|
|
|
if (targetFramework != null)
|
|
|
|
|
{
|
2016-10-12 14:59:36 -07:00
|
|
|
|
itemGroup.Condition = targetFramework.GetMSBuildCondition();
|
2016-09-21 21:14:48 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-23 13:50:05 -07:00
|
|
|
|
foreach (var projectDependencyTransformResult in projectDependencyTransformResults)
|
|
|
|
|
{
|
2016-10-20 11:00:41 -07:00
|
|
|
|
_transformApplicator.Execute(projectDependencyTransformResult, itemGroup, true);
|
2016-08-23 13:50:05 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-20 11:00:41 -07:00
|
|
|
|
|
2016-11-03 10:27:51 -07:00
|
|
|
|
private AddItemTransform<ProjectDependency> ProjectDependencyTransform =>
|
|
|
|
|
GetProjectDependencyTransfrom();
|
|
|
|
|
|
|
|
|
|
private AddItemTransform<ProjectDependency> HoistedDependencyTransform =>
|
|
|
|
|
GetProjectDependencyTransfrom()
|
|
|
|
|
.WithMetadata("FromP2P", "true");
|
|
|
|
|
|
|
|
|
|
private Func<AddItemTransform<ProjectDependency>> GetProjectDependencyTransfrom =>
|
|
|
|
|
() => new AddItemTransform<ProjectDependency>(
|
|
|
|
|
"ProjectReference",
|
|
|
|
|
dep =>
|
|
|
|
|
{
|
|
|
|
|
var projectDir = Path.GetDirectoryName(dep.ProjectFilePath);
|
|
|
|
|
var migratedProjectFileName = Path.GetFileName(projectDir) + ".csproj";
|
|
|
|
|
var relativeProjectDir = PathUtility.GetRelativePath(_projectDirectory + "/", projectDir);
|
|
|
|
|
|
|
|
|
|
return Path.Combine(relativeProjectDir, migratedProjectFileName);
|
|
|
|
|
},
|
|
|
|
|
dep => "",
|
|
|
|
|
dep => true);
|
2016-09-21 17:27:02 -07:00
|
|
|
|
|
|
|
|
|
private AddItemTransform<string> ProjectDependencyStringTransform => new AddItemTransform<string>(
|
|
|
|
|
"ProjectReference",
|
|
|
|
|
path => path,
|
|
|
|
|
path => "",
|
|
|
|
|
path => true);
|
2016-11-03 16:54:15 -07:00
|
|
|
|
|
|
|
|
|
private AddItemTransform<ProjectLibraryDependency> FrameworkDependencyTransform =>
|
|
|
|
|
new AddItemTransform<ProjectLibraryDependency>(
|
|
|
|
|
"Reference",
|
|
|
|
|
dep => dep.Name,
|
|
|
|
|
dep => "",
|
|
|
|
|
dep => true)
|
|
|
|
|
.WithMetadata("FromP2P", "true");
|
2016-08-22 12:21:34 -07:00
|
|
|
|
}
|
|
|
|
|
}
|