dotnet-installer/src/Microsoft.DotNet.ProjectJsonMigration/transforms/IncludeContextTransform.cs

228 lines
9 KiB
C#
Raw Normal View History

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.Internal.ProjectModel.Files;
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-23 13:50:05 -07:00
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
{
internal 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),
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-10-20 11:24:58 -07:00
private Func<AddItemTransform<IncludeContext>, string, AddItemTransform<IncludeContext>> _mappingsToTransfrom;
2016-08-23 13:50:05 -07:00
private readonly string _itemName;
private bool _transformMappings;
2016-08-23 13:50:05 -07:00
private readonly List<ItemMetadataValue<IncludeContext>> _metadata = new List<ItemMetadataValue<IncludeContext>>();
public IncludeContextTransform(
string itemName,
bool transformMappings = true,
Func<IncludeContext, bool> condition = null) : base(condition)
{
_itemName = itemName;
_transformMappings = transformMappings;
2016-10-20 11:24:58 -07:00
_mappingsToTransfrom = (addItemTransform, targetPath) =>
{
var msbuildLinkMetadataValue = ConvertTargetPathToMsbuildMetadata(targetPath);
return addItemTransform.WithMetadata("Link", msbuildLinkMetadataValue);
};
}
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-10-20 11:24:58 -07:00
public IncludeContextTransform WithMappingsToTransform(
Func<AddItemTransform<IncludeContext>, string, AddItemTransform<IncludeContext>> mappingsToTransfrom)
{
_mappingsToTransfrom = mappingsToTransfrom;
return this;
}
2016-09-08 14:40:46 -07:00
private IEnumerable<Tuple<AddItemTransform<IncludeContext>, IncludeContext>> CreateTransformSet(IncludeContext source)
{
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-09-08 14:40:46 -07:00
if (source == null)
{
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-09-08 14:40:46 -07:00
foreach (var metadataElement in _metadata)
{
2016-09-08 14:40:46 -07:00
foreach (var transform in transformSet)
{
transform.Item1.WithMetadata(metadataElement);
}
}
return transformSet;
}
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)
{
if (patterns == null)
{
return string.Empty;
}
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)
{
2016-10-20 11:24:58 -07:00
return _mappingsToTransfrom(addItemTransform, targetPath);
2016-09-08 14:40:46 -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-10-20 11:24:58 -07:00
private string ConvertTargetPathToMsbuildMetadata(string targetPath)
2016-09-08 14:40:46 -07:00
{
2016-10-20 11:24:58 -07:00
var targetIsFile = MappingsTargetPathIsFile(targetPath);
2016-09-08 14:40:46 -07:00
if (targetIsFile)
{
return targetPath;
}
return $"{targetPath}%(FileName)%(Extension)";
}
private bool MappingsTargetPathIsFile(string targetPath)
{
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;
}
}
}