2016-09-22 14:35:31 -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 Microsoft.DotNet.ProjectModel.Files;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Microsoft.Build.Construction;
|
|
|
|
|
using Microsoft.DotNet.Cli.Utils;
|
2016-08-23 13:50:05 -07:00
|
|
|
|
using Microsoft.DotNet.ProjectJsonMigration.Models;
|
2016-09-08 14:40:46 -07:00
|
|
|
|
using Microsoft.DotNet.Tools.Common;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
|
2016-08-23 13:50:05 -07:00
|
|
|
|
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
|
|
|
|
public class IncludeContextTransform : ConditionalTransform<IncludeContext, IEnumerable<ProjectItemElement>>
|
|
|
|
|
{
|
2016-09-08 14:40:46 -07:00
|
|
|
|
private Func<string, AddItemTransform<IncludeContext>> IncludeFilesExcludeFilesTransformGetter =>
|
|
|
|
|
(itemName) =>
|
|
|
|
|
new AddItemTransform<IncludeContext>(
|
|
|
|
|
itemName,
|
|
|
|
|
includeContext => FormatGlobPatternsForMsbuild(includeContext.IncludeFiles, includeContext.SourceBasePath),
|
|
|
|
|
includeContext => FormatGlobPatternsForMsbuild(includeContext.ExcludeFiles, includeContext.SourceBasePath),
|
2016-10-12 16:01:22 -07:00
|
|
|
|
includeContext => includeContext != null
|
|
|
|
|
&& includeContext.IncludeFiles != null
|
|
|
|
|
&& includeContext.IncludeFiles.Count > 0);
|
2016-09-08 14:40:46 -07:00
|
|
|
|
|
|
|
|
|
private Func<string, AddItemTransform<IncludeContext>> IncludeExcludeTransformGetter =>
|
|
|
|
|
(itemName) => new AddItemTransform<IncludeContext>(
|
|
|
|
|
itemName,
|
|
|
|
|
includeContext =>
|
|
|
|
|
{
|
|
|
|
|
var fullIncludeSet = includeContext.IncludePatterns.OrEmptyIfNull()
|
|
|
|
|
.Union(includeContext.BuiltInsInclude.OrEmptyIfNull());
|
|
|
|
|
|
|
|
|
|
return FormatGlobPatternsForMsbuild(fullIncludeSet, includeContext.SourceBasePath);
|
|
|
|
|
},
|
|
|
|
|
includeContext =>
|
|
|
|
|
{
|
|
|
|
|
var fullExcludeSet = includeContext.ExcludePatterns.OrEmptyIfNull()
|
|
|
|
|
.Union(includeContext.BuiltInsExclude.OrEmptyIfNull())
|
|
|
|
|
.Union(includeContext.ExcludeFiles.OrEmptyIfNull());
|
|
|
|
|
|
|
|
|
|
return FormatGlobPatternsForMsbuild(fullExcludeSet, includeContext.SourceBasePath);
|
|
|
|
|
},
|
|
|
|
|
includeContext =>
|
|
|
|
|
{
|
|
|
|
|
return includeContext != null &&
|
|
|
|
|
(
|
|
|
|
|
(includeContext.IncludePatterns != null && includeContext.IncludePatterns.Count > 0)
|
|
|
|
|
||
|
|
|
|
|
(includeContext.BuiltInsInclude != null && includeContext.BuiltInsInclude.Count > 0)
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
private Func<string, string, AddItemTransform<IncludeContext>> MappingsIncludeFilesExcludeFilesTransformGetter =>
|
|
|
|
|
(itemName, targetPath) => AddMappingToTransform(IncludeFilesExcludeFilesTransformGetter(itemName), targetPath);
|
|
|
|
|
|
|
|
|
|
private Func<string, string, AddItemTransform<IncludeContext>> MappingsIncludeExcludeTransformGetter =>
|
|
|
|
|
(itemName, targetPath) => AddMappingToTransform(IncludeExcludeTransformGetter(itemName), targetPath);
|
2016-08-22 12:21:34 -07:00
|
|
|
|
|
2016-08-23 13:50:05 -07:00
|
|
|
|
private readonly string _itemName;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
private bool _transformMappings;
|
2016-08-23 13:50:05 -07:00
|
|
|
|
private readonly List<ItemMetadataValue<IncludeContext>> _metadata = new List<ItemMetadataValue<IncludeContext>>();
|
2016-08-22 12:21:34 -07:00
|
|
|
|
|
|
|
|
|
public IncludeContextTransform(
|
|
|
|
|
string itemName,
|
|
|
|
|
bool transformMappings = true,
|
|
|
|
|
Func<IncludeContext, bool> condition = null) : base(condition)
|
|
|
|
|
{
|
|
|
|
|
_itemName = itemName;
|
|
|
|
|
_transformMappings = transformMappings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IncludeContextTransform WithMetadata(string metadataName, string metadataValue)
|
|
|
|
|
{
|
|
|
|
|
_metadata.Add(new ItemMetadataValue<IncludeContext>(metadataName, metadataValue));
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IncludeContextTransform WithMetadata(string metadataName, Func<IncludeContext, string> metadataValueFunc)
|
|
|
|
|
{
|
|
|
|
|
_metadata.Add(new ItemMetadataValue<IncludeContext>(metadataName, metadataValueFunc));
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 14:40:46 -07:00
|
|
|
|
private IEnumerable<Tuple<AddItemTransform<IncludeContext>, IncludeContext>> CreateTransformSet(IncludeContext source)
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
2016-09-08 14:40:46 -07:00
|
|
|
|
var transformSet = new List<Tuple<AddItemTransform<IncludeContext>, IncludeContext>>
|
|
|
|
|
{
|
|
|
|
|
Tuple.Create(IncludeFilesExcludeFilesTransformGetter(_itemName), source),
|
|
|
|
|
Tuple.Create(IncludeExcludeTransformGetter(_itemName), source)
|
|
|
|
|
};
|
2016-08-22 12:21:34 -07:00
|
|
|
|
|
2016-09-08 14:40:46 -07:00
|
|
|
|
if (source == null)
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
2016-09-08 14:40:46 -07:00
|
|
|
|
return transformSet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mappings must be executed before the transform set to prevent a the
|
|
|
|
|
// non-mapped items that will merge with mapped items from being encompassed
|
|
|
|
|
foreach (var mappingEntry in source.Mappings.OrEmptyIfNull())
|
|
|
|
|
{
|
|
|
|
|
var targetPath = mappingEntry.Key;
|
|
|
|
|
var includeContext = mappingEntry.Value;
|
|
|
|
|
|
|
|
|
|
transformSet.Insert(0,
|
|
|
|
|
Tuple.Create(
|
|
|
|
|
MappingsIncludeExcludeTransformGetter(_itemName, targetPath),
|
|
|
|
|
includeContext));
|
|
|
|
|
|
|
|
|
|
transformSet.Insert(0,
|
|
|
|
|
Tuple.Create(
|
|
|
|
|
MappingsIncludeFilesExcludeFilesTransformGetter(_itemName, targetPath),
|
|
|
|
|
includeContext));
|
2016-08-22 12:21:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 14:40:46 -07:00
|
|
|
|
foreach (var metadataElement in _metadata)
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
2016-09-08 14:40:46 -07:00
|
|
|
|
foreach (var transform in transformSet)
|
|
|
|
|
{
|
|
|
|
|
transform.Item1.WithMetadata(metadataElement);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return transformSet;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 14:40:46 -07:00
|
|
|
|
public override IEnumerable<ProjectItemElement> ConditionallyTransform(IncludeContext source)
|
|
|
|
|
{
|
|
|
|
|
var transformSet = CreateTransformSet(source);
|
|
|
|
|
return transformSet.Select(t => t.Item1.Transform(t.Item2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string FormatGlobPatternsForMsbuild(IEnumerable<string> patterns, string projectDirectory)
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
2016-10-12 16:01:22 -07:00
|
|
|
|
if (patterns == null)
|
|
|
|
|
{
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-22 12:21:34 -07:00
|
|
|
|
List<string> mutatedPatterns = new List<string>(patterns.Count());
|
|
|
|
|
|
|
|
|
|
foreach (var pattern in patterns)
|
|
|
|
|
{
|
|
|
|
|
// Do not use forward slashes
|
|
|
|
|
// https://github.com/Microsoft/msbuild/issues/724
|
|
|
|
|
var mutatedPattern = pattern.Replace('/', '\\');
|
|
|
|
|
|
|
|
|
|
// MSBuild cannot copy directories
|
|
|
|
|
mutatedPattern = ReplaceDirectoriesWithGlobs(mutatedPattern, projectDirectory);
|
|
|
|
|
|
|
|
|
|
mutatedPatterns.Add(mutatedPattern);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string.Join(";", mutatedPatterns);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string ReplaceDirectoriesWithGlobs(string pattern, string projectDirectory)
|
|
|
|
|
{
|
|
|
|
|
if (PatternIsDirectory(pattern, projectDirectory))
|
|
|
|
|
{
|
|
|
|
|
return $"{pattern.TrimEnd(new char[] { '\\' })}\\**\\*";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return pattern;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 14:40:46 -07:00
|
|
|
|
private AddItemTransform<IncludeContext> AddMappingToTransform(
|
|
|
|
|
AddItemTransform<IncludeContext> addItemTransform,
|
|
|
|
|
string targetPath)
|
|
|
|
|
{
|
|
|
|
|
var targetIsFile = MappingsTargetPathIsFile(targetPath);
|
|
|
|
|
var msbuildLinkMetadataValue = ConvertTargetPathToMsbuildMetadata(targetPath, targetIsFile);
|
|
|
|
|
|
|
|
|
|
return addItemTransform.WithMetadata("Link", msbuildLinkMetadataValue);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-22 12:21:34 -07:00
|
|
|
|
private bool PatternIsDirectory(string pattern, string projectDirectory)
|
|
|
|
|
{
|
|
|
|
|
// TODO: what about /some/path/**/somedir?
|
|
|
|
|
// Should this even be migrated?
|
|
|
|
|
var path = pattern;
|
|
|
|
|
|
|
|
|
|
if (!Path.IsPathRooted(path))
|
|
|
|
|
{
|
|
|
|
|
path = Path.Combine(projectDirectory, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Directory.Exists(path);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 14:40:46 -07:00
|
|
|
|
private string ConvertTargetPathToMsbuildMetadata(string targetPath, bool targetIsFile)
|
|
|
|
|
{
|
|
|
|
|
if (targetIsFile)
|
|
|
|
|
{
|
|
|
|
|
return targetPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $"{targetPath}%(FileName)%(Extension)";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool MappingsTargetPathIsFile(string targetPath)
|
2016-08-22 12:21:34 -07:00
|
|
|
|
{
|
2016-09-08 14:40:46 -07:00
|
|
|
|
var normalizedTargetPath = PathUtility.GetPathWithDirectorySeparator(targetPath);
|
2016-08-23 13:50:05 -07:00
|
|
|
|
|
2016-09-08 14:40:46 -07:00
|
|
|
|
return normalizedTargetPath[normalizedTargetPath.Length - 1] != Path.DirectorySeparatorChar;
|
2016-08-22 12:21:34 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|