Project Json mapping migration support
This commit is contained in:
parent
3a567e5957
commit
362f71a94a
17 changed files with 910 additions and 201 deletions
|
@ -7,7 +7,7 @@ namespace ConsoleApplication
|
|||
public static int Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
return 100;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,29 +3,30 @@
|
|||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"copyToOutput": {
|
||||
"include": "testcontentfile.txt"
|
||||
"include": "testcontentfile.txt",
|
||||
"mappings": {
|
||||
"dir/mappingfile.txt":{
|
||||
"include": "testcontentfile2.txt"
|
||||
},
|
||||
"out/": {
|
||||
"include": ["project.json", "Program.cs"],
|
||||
"exclude": ["Program.cs"],
|
||||
"includeFiles": ["Program.cs"],
|
||||
"excludeFiles": ["Program.cs"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": "1.0.1"
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.1",
|
||||
"type": "platform"
|
||||
}
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {}
|
||||
},
|
||||
"publishOptions": {
|
||||
"include": "testcontentfile.txt"
|
||||
},
|
||||
"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": {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,79 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
{
|
||||
public static class MSBuildExtensions
|
||||
{
|
||||
public static bool IsEquivalentTo(this ProjectItemElement item, ProjectItemElement otherItem)
|
||||
{
|
||||
// Different includes
|
||||
if (item.IntersectIncludes(otherItem).Count() != item.Includes().Count())
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine("ms: includes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Different Excludes
|
||||
if (item.IntersectExcludes(otherItem).Count() != item.Excludes().Count())
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine("ms: excludes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Different remove
|
||||
if (item.Remove != otherItem.Remove)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine("ms: remove");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Different Metadata
|
||||
var metadataTuples = otherItem.Metadata.Select(m => Tuple.Create(m, item)).Concat(
|
||||
item.Metadata.Select(m => Tuple.Create(m, otherItem)));
|
||||
foreach (var metadataTuple in metadataTuples)
|
||||
{
|
||||
var metadata = metadataTuple.Item1;
|
||||
var itemToCompare = metadataTuple.Item2;
|
||||
|
||||
var otherMetadata = itemToCompare.GetMetadataWithName(metadata.Name);
|
||||
if (otherMetadata == null)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine($"ms: metadata doesn't exist {{ {metadata.Name} {metadata.Value} }}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!metadata.ValueEquals(otherMetadata))
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine("ms: metadata has another value {{ {metadata.Name} {metadata.Value} {otherMetadata.Value} }}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ISet<string> ConditionChain(this ProjectElement projectElement)
|
||||
{
|
||||
var conditionChainSet = new HashSet<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(projectElement.Condition))
|
||||
{
|
||||
conditionChainSet.Add(projectElement.Condition);
|
||||
}
|
||||
|
||||
foreach (var parent in projectElement.AllParents)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(parent.Condition))
|
||||
{
|
||||
conditionChainSet.Add(parent.Condition);
|
||||
}
|
||||
}
|
||||
|
||||
return conditionChainSet;
|
||||
}
|
||||
|
||||
public static bool ConditionChainsAreEquivalent(this ProjectElement projectElement, ProjectElement otherProjectElement)
|
||||
{
|
||||
return projectElement.ConditionChain().SetEquals(otherProjectElement.ConditionChain());
|
||||
}
|
||||
|
||||
public static IEnumerable<ProjectPropertyElement> PropertiesWithoutConditions(
|
||||
this ProjectRootElement projectRoot)
|
||||
{
|
||||
|
@ -39,6 +112,12 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
return SplitSemicolonDelimitedValues(item.Exclude);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Removes(
|
||||
this ProjectItemElement item)
|
||||
{
|
||||
return SplitSemicolonDelimitedValues(item.Remove);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> AllConditions(this ProjectElement projectElement)
|
||||
{
|
||||
return new string[] { projectElement.Condition }.Concat(projectElement.AllParents.Select(p=> p.Condition));
|
||||
|
@ -49,6 +128,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
return item.Includes().Intersect(otherItem.Includes());
|
||||
}
|
||||
|
||||
public static IEnumerable<string> IntersectExcludes(this ProjectItemElement item, ProjectItemElement otherItem)
|
||||
{
|
||||
return item.Excludes().Intersect(otherItem.Excludes());
|
||||
}
|
||||
|
||||
public static void RemoveIncludes(this ProjectItemElement item, IEnumerable<string> includesToRemove)
|
||||
{
|
||||
item.Include = string.Join(";", item.Includes().Except(includesToRemove));
|
||||
|
@ -64,11 +148,6 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
item.Exclude = string.Join(";", item.Excludes().Union(excludesToAdd));
|
||||
}
|
||||
|
||||
public static ProjectMetadataElement GetMetadataWithName(this ProjectItemElement item, string name)
|
||||
{
|
||||
return item.Metadata.FirstOrDefault(m => m.Name.Equals(name, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
public static bool ValueEquals(this ProjectMetadataElement metadata, ProjectMetadataElement otherMetadata)
|
||||
{
|
||||
return metadata.Value.Equals(otherMetadata.Value, StringComparison.Ordinal);
|
||||
|
@ -90,6 +169,24 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
}
|
||||
}
|
||||
|
||||
public static ProjectMetadataElement GetMetadataWithName(this ProjectItemElement item, string name)
|
||||
{
|
||||
return item.Metadata.FirstOrDefault(m => m.Name.Equals(name, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
public static bool HasConflictingMetadata(this ProjectItemElement item, ProjectItemElement otherItem)
|
||||
{
|
||||
foreach (var metadata in item.Metadata)
|
||||
{
|
||||
if (otherItem.Metadata.Any(m => m.Name == metadata.Name && m.Value != metadata.Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void AddMetadata(this ProjectItemElement item, ProjectMetadataElement metadata)
|
||||
{
|
||||
var existingMetadata = item.GetMetadataWithName(metadata.Name);
|
||||
|
|
|
@ -18,13 +18,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
public class ProjectMigrator
|
||||
{
|
||||
// TODO: Migrate PackOptions
|
||||
// TODO: Support Mappings in IncludeContext Transformations
|
||||
// TODO: Migrate Multi-TFM projects
|
||||
// TODO: Tests
|
||||
// TODO: Out of Scope
|
||||
// - Globs that resolve to directories: /some/path/**/somedir
|
||||
// - Migrating Deprecated project.jsons
|
||||
// - Configuration dependent source exclusion
|
||||
|
||||
private readonly IMigrationRule _ruleSet;
|
||||
|
||||
|
@ -85,7 +83,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
if (diagnostics.Any())
|
||||
{
|
||||
MigrationErrorCodes.MIGRATE1011(
|
||||
$"{projectDirectory}{Environment.NewLine}{string.Join(Environment.NewLine, diagnostics.Select(d => d.Message))}")
|
||||
$"{projectDirectory}{Environment.NewLine}{string.Join(Environment.NewLine, diagnostics.Select(d => FormatDiagnosticMessage(d)))}")
|
||||
.Throw();
|
||||
}
|
||||
|
||||
|
@ -99,6 +97,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration
|
|||
}
|
||||
}
|
||||
|
||||
private string FormatDiagnosticMessage(DiagnosticMessage d)
|
||||
{
|
||||
return $"{d.Message} (line: {d.StartLine}, file: {d.SourceFilePath})";
|
||||
}
|
||||
|
||||
private void SetupOutputDirectory(string projectDirectory, string outputDirectory)
|
||||
{
|
||||
if (!Directory.Exists(outputDirectory))
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
new AddPropertyTransform<CommonCompilerOptions>("OutputType", "Exe",
|
||||
compilerOptions => compilerOptions.EmitEntryPoint != null && compilerOptions.EmitEntryPoint.Value),
|
||||
new AddPropertyTransform<CommonCompilerOptions>("OutputType", "Library",
|
||||
compilerOptions => compilerOptions.EmitEntryPoint == null || !compilerOptions.EmitEntryPoint.Value)
|
||||
compilerOptions => compilerOptions.EmitEntryPoint != null && !compilerOptions.EmitEntryPoint.Value)
|
||||
};
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions>[] KeyFileTransforms
|
||||
|
@ -39,12 +39,12 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
|
||||
private AddPropertyTransform<CommonCompilerOptions> DefineTransform => new AddPropertyTransform<CommonCompilerOptions>(
|
||||
"DefineConstants",
|
||||
compilerOptions => string.Join(";", compilerOptions.Defines),
|
||||
compilerOptions => "$(DefineConstants);" + string.Join(";", compilerOptions.Defines),
|
||||
compilerOptions => compilerOptions.Defines != null && compilerOptions.Defines.Any());
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> NoWarnTransform => new AddPropertyTransform<CommonCompilerOptions>(
|
||||
"NoWarn",
|
||||
compilerOptions => string.Join(";", compilerOptions.SuppressWarnings),
|
||||
compilerOptions => "$(NoWarn);" + string.Join(";", compilerOptions.SuppressWarnings),
|
||||
compilerOptions => compilerOptions.SuppressWarnings != null && compilerOptions.SuppressWarnings.Any());
|
||||
|
||||
private AddPropertyTransform<CommonCompilerOptions> PreserveCompilationContextTransform =>
|
||||
|
@ -129,11 +129,10 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
private Func<CommonCompilerOptions, string, IEnumerable<ProjectItemElement>> CopyToOutputFilesTransformExecute =>
|
||||
(compilerOptions, projectDirectory) =>
|
||||
CopyToOutputFilesTransform.Transform(GetCopyToOutputIncludeContext(compilerOptions, projectDirectory));
|
||||
|
||||
private readonly string _configuration;
|
||||
private readonly NuGetFramework _framework;
|
||||
|
||||
private readonly ProjectPropertyGroupElement _configurationPropertyGroup;
|
||||
private readonly ProjectItemGroupElement _configurationItemGroup;
|
||||
private readonly CommonCompilerOptions _configurationBuildOptions;
|
||||
|
||||
private List<AddPropertyTransform<CommonCompilerOptions>> _propertyTransforms;
|
||||
private List<Func<CommonCompilerOptions, string, IEnumerable<ProjectItemElement>>> _includeContextTransformExecutes;
|
||||
|
@ -147,14 +146,12 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
}
|
||||
|
||||
public MigrateBuildOptionsRule(
|
||||
string configuration,
|
||||
NuGetFramework framework,
|
||||
CommonCompilerOptions configurationBuildOptions,
|
||||
ProjectPropertyGroupElement configurationPropertyGroup,
|
||||
ProjectItemGroupElement configurationItemGroup,
|
||||
ITransformApplicator transformApplicator = null)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_framework = framework;
|
||||
_configurationBuildOptions = configurationBuildOptions;
|
||||
_configurationPropertyGroup = configurationPropertyGroup;
|
||||
_configurationItemGroup = configurationItemGroup;
|
||||
_transformApplicator = transformApplicator ?? new TransformApplicator();
|
||||
|
@ -201,13 +198,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
var propertyGroup = _configurationPropertyGroup ?? migrationRuleInputs.CommonPropertyGroup;
|
||||
var itemGroup = _configurationItemGroup ?? migrationRuleInputs.CommonItemGroup;
|
||||
|
||||
var compilerOptions = projectContext.ProjectFile.GetCompilerOptions(projectContext.TargetFramework, null);
|
||||
var configurationCompilerOptions =
|
||||
projectContext.ProjectFile.GetCompilerOptions(_framework, _configuration);
|
||||
var compilerOptions = projectContext.ProjectFile.GetCompilerOptions(null, null);
|
||||
|
||||
// If we're in a configuration, we need to be careful not to overwrite values from BuildOptions
|
||||
// without a configuration
|
||||
if (_configuration == null)
|
||||
if (_configurationBuildOptions == null)
|
||||
{
|
||||
CleanExistingProperties(csproj);
|
||||
|
||||
|
@ -222,7 +217,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
{
|
||||
PerformConfigurationPropertyAndItemMappings(
|
||||
compilerOptions,
|
||||
configurationCompilerOptions,
|
||||
_configurationBuildOptions,
|
||||
propertyGroup,
|
||||
itemGroup,
|
||||
_transformApplicator,
|
||||
|
@ -254,47 +249,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
var nonConfigurationOutput = includeContextTransformExecute(compilerOptions, projectDirectory);
|
||||
var configurationOutput = includeContextTransformExecute(configurationCompilerOptions, projectDirectory).ToArray();
|
||||
|
||||
if (configurationOutput != null && nonConfigurationOutput != null)
|
||||
{
|
||||
// TODO: HACK: this is leaky, see top comments, the throw at least covers the scenario
|
||||
ThrowIfConfigurationHasAdditionalExcludes(configurationOutput, nonConfigurationOutput);
|
||||
RemoveCommonIncludes(configurationOutput, nonConfigurationOutput);
|
||||
configurationOutput = configurationOutput.Where(i => i != null && !string.IsNullOrEmpty(i.Include)).ToArray();
|
||||
}
|
||||
|
||||
// Don't merge with existing items when doing a configuration
|
||||
transformApplicator.Execute(configurationOutput, itemGroup, mergeExisting: false);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfConfigurationHasAdditionalExcludes(IEnumerable<ProjectItemElement> configurationOutput, IEnumerable<ProjectItemElement> nonConfigurationOutput)
|
||||
{
|
||||
foreach (var item1 in configurationOutput)
|
||||
{
|
||||
if (item1 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var item2Excludes = new HashSet<string>();
|
||||
foreach (var item2 in nonConfigurationOutput)
|
||||
{
|
||||
if (item2 != null)
|
||||
{
|
||||
item2Excludes.UnionWith(item2.Excludes());
|
||||
}
|
||||
}
|
||||
var configurationHasAdditionalExclude =
|
||||
item1.Excludes().Any(exclude => item2Excludes.All(item2Exclude => item2Exclude != exclude));
|
||||
|
||||
if (configurationHasAdditionalExclude)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine(item1.Exclude);
|
||||
MigrationTrace.Instance.WriteLine(item2Excludes.ToString());
|
||||
|
||||
MigrationErrorCodes.MIGRATE20012("Unable to migrate projects with excluded files in configurations.")
|
||||
.Throw();
|
||||
}
|
||||
transformApplicator.Execute(configurationOutput, itemGroup, mergeExisting: true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
using NuGet.Frameworks;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
||||
{
|
||||
|
@ -13,56 +14,75 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Rules
|
|||
{
|
||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine($"Executing rule: {nameof(MigrateConfigurationsRule)}");
|
||||
var projectContext = migrationRuleInputs.DefaultProjectContext;
|
||||
var configurations = projectContext.ProjectFile.GetConfigurations().ToList();
|
||||
|
||||
var frameworks = new List<NuGetFramework>();
|
||||
frameworks.Add(null);
|
||||
frameworks.AddRange(projectContext.ProjectFile.GetTargetFrameworks().Select(t => t.FrameworkName));
|
||||
|
||||
if (!configurations.Any())
|
||||
if (!configurations.Any() && !frameworks.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var frameworkConfigurationCombinations = frameworks.SelectMany(f => configurations, Tuple.Create);
|
||||
|
||||
foreach (var entry in frameworkConfigurationCombinations)
|
||||
foreach (var framework in frameworks)
|
||||
{
|
||||
var framework = entry.Item1;
|
||||
var configuration = entry.Item2;
|
||||
MigrateConfiguration(projectContext.ProjectFile, framework, migrationSettings, migrationRuleInputs);
|
||||
}
|
||||
|
||||
MigrateConfiguration(configuration, framework, migrationSettings, migrationRuleInputs);
|
||||
foreach (var configuration in configurations)
|
||||
{
|
||||
MigrateConfiguration(projectContext.ProjectFile, configuration, migrationSettings, migrationRuleInputs);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateConfiguration(
|
||||
Project project,
|
||||
string configuration,
|
||||
NuGetFramework framework,
|
||||
MigrationSettings migrationSettings,
|
||||
MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var buildOptions = project.GetRawCompilerOptions(configuration);
|
||||
var configurationCondition = $" '$(Configuration)' == '{configuration}' ";
|
||||
|
||||
MigrateConfiguration(buildOptions, configurationCondition, migrationSettings, migrationRuleInputs);
|
||||
}
|
||||
|
||||
private void MigrateConfiguration(
|
||||
Project project,
|
||||
NuGetFramework framework,
|
||||
MigrationSettings migrationSettings,
|
||||
MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var buildOptions = project.GetRawCompilerOptions(framework);
|
||||
var configurationCondition = $" '$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)' == '{framework.DotNetFrameworkName}' ";
|
||||
|
||||
MigrateConfiguration(buildOptions, configurationCondition, migrationSettings, migrationRuleInputs);
|
||||
}
|
||||
|
||||
private void MigrateConfiguration(
|
||||
CommonCompilerOptions buildOptions,
|
||||
string configurationCondition,
|
||||
MigrationSettings migrationSettings,
|
||||
MigrationRuleInputs migrationRuleInputs)
|
||||
{
|
||||
var csproj = migrationRuleInputs.OutputMSBuildProject;
|
||||
|
||||
var propertyGroup = CreatePropertyGroupAtEndOfProject(csproj);
|
||||
var itemGroup = CreateItemGroupAtEndOfProject(csproj);
|
||||
|
||||
var configurationCondition = $" '$(Configuration)' == '{configuration}' ";
|
||||
if (framework != null)
|
||||
{
|
||||
configurationCondition +=
|
||||
$" and '$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)' == '{framework.DotNetFrameworkName}' ";
|
||||
}
|
||||
propertyGroup.Condition = configurationCondition;
|
||||
itemGroup.Condition = configurationCondition;
|
||||
|
||||
new MigrateBuildOptionsRule(configuration, framework, propertyGroup, itemGroup)
|
||||
new MigrateBuildOptionsRule(buildOptions, propertyGroup, itemGroup)
|
||||
.Apply(migrationSettings, migrationRuleInputs);
|
||||
|
||||
propertyGroup.RemoveIfEmpty();
|
||||
itemGroup.RemoveIfEmpty();
|
||||
}
|
||||
|
||||
|
||||
private ProjectPropertyGroupElement CreatePropertyGroupAtEndOfProject(ProjectRootElement csproj)
|
||||
{
|
||||
var propertyGroup = csproj.CreatePropertyGroupElement();
|
||||
|
|
|
@ -7,19 +7,57 @@ using System.Threading.Tasks;
|
|||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectJsonMigration.Models;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
||||
{
|
||||
public class IncludeContextTransform : ConditionalTransform<IncludeContext, IEnumerable<ProjectItemElement>>
|
||||
{
|
||||
// TODO: If a directory is specified in project.json does this need to be replaced with a glob in msbuild?
|
||||
// - Partially solved, what if the resolved glob is a directory?
|
||||
// TODO: Support mappings
|
||||
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.Count > 0);
|
||||
|
||||
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);
|
||||
|
||||
private readonly string _itemName;
|
||||
private bool _transformMappings;
|
||||
private readonly List<ItemMetadataValue<IncludeContext>> _metadata = new List<ItemMetadataValue<IncludeContext>>();
|
||||
private AddItemTransform<IncludeContext>[] _transformSet;
|
||||
|
||||
public IncludeContextTransform(
|
||||
string itemName,
|
||||
|
@ -42,55 +80,55 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
|||
return this;
|
||||
}
|
||||
|
||||
private void CreateTransformSet()
|
||||
private IEnumerable<Tuple<AddItemTransform<IncludeContext>, IncludeContext>> CreateTransformSet(IncludeContext source)
|
||||
{
|
||||
var includeFilesExcludeFilesTransformation = new AddItemTransform<IncludeContext>(
|
||||
_itemName,
|
||||
includeContext => FormatPatterns(includeContext.IncludeFiles, includeContext.SourceBasePath),
|
||||
includeContext => FormatPatterns(includeContext.ExcludeFiles, includeContext.SourceBasePath),
|
||||
includeContext => includeContext != null && includeContext.IncludeFiles.Count > 0);
|
||||
|
||||
var includeExcludeTransformation = new AddItemTransform<IncludeContext>(
|
||||
_itemName,
|
||||
includeContext =>
|
||||
{
|
||||
var fullIncludeSet = includeContext.IncludePatterns.OrEmptyIfNull()
|
||||
.Union(includeContext.BuiltInsInclude.OrEmptyIfNull());
|
||||
|
||||
return FormatPatterns(fullIncludeSet, includeContext.SourceBasePath);
|
||||
},
|
||||
includeContext =>
|
||||
{
|
||||
var fullExcludeSet = includeContext.ExcludePatterns.OrEmptyIfNull()
|
||||
.Union(includeContext.BuiltInsExclude.OrEmptyIfNull())
|
||||
.Union(includeContext.ExcludeFiles.OrEmptyIfNull());
|
||||
|
||||
return FormatPatterns(fullExcludeSet, includeContext.SourceBasePath);
|
||||
},
|
||||
includeContext =>
|
||||
{
|
||||
return includeContext != null &&
|
||||
(
|
||||
(includeContext.IncludePatterns != null && includeContext.IncludePatterns.Count > 0)
|
||||
||
|
||||
(includeContext.BuiltInsInclude != null && includeContext.BuiltInsInclude.Count > 0)
|
||||
);
|
||||
});
|
||||
|
||||
foreach (var metadata in _metadata)
|
||||
var transformSet = new List<Tuple<AddItemTransform<IncludeContext>, IncludeContext>>
|
||||
{
|
||||
includeFilesExcludeFilesTransformation.WithMetadata(metadata);
|
||||
includeExcludeTransformation.WithMetadata(metadata);
|
||||
Tuple.Create(IncludeFilesExcludeFilesTransformGetter(_itemName), source),
|
||||
Tuple.Create(IncludeExcludeTransformGetter(_itemName), source)
|
||||
};
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
_transformSet = new []
|
||||
foreach (var metadataElement in _metadata)
|
||||
{
|
||||
includeFilesExcludeFilesTransformation,
|
||||
includeExcludeTransformation
|
||||
};
|
||||
foreach (var transform in transformSet)
|
||||
{
|
||||
transform.Item1.WithMetadata(metadataElement);
|
||||
}
|
||||
}
|
||||
|
||||
return transformSet;
|
||||
}
|
||||
|
||||
private string FormatPatterns(IEnumerable<string> patterns, string projectDirectory)
|
||||
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)
|
||||
{
|
||||
List<string> mutatedPatterns = new List<string>(patterns.Count());
|
||||
|
||||
|
@ -121,6 +159,16 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
|||
}
|
||||
}
|
||||
|
||||
private AddItemTransform<IncludeContext> AddMappingToTransform(
|
||||
AddItemTransform<IncludeContext> addItemTransform,
|
||||
string targetPath)
|
||||
{
|
||||
var targetIsFile = MappingsTargetPathIsFile(targetPath);
|
||||
var msbuildLinkMetadataValue = ConvertTargetPathToMsbuildMetadata(targetPath, targetIsFile);
|
||||
|
||||
return addItemTransform.WithMetadata("Link", msbuildLinkMetadataValue);
|
||||
}
|
||||
|
||||
private bool PatternIsDirectory(string pattern, string projectDirectory)
|
||||
{
|
||||
// TODO: what about /some/path/**/somedir?
|
||||
|
@ -135,11 +183,21 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
|||
return Directory.Exists(path);
|
||||
}
|
||||
|
||||
public override IEnumerable<ProjectItemElement> ConditionallyTransform(IncludeContext source)
|
||||
private string ConvertTargetPathToMsbuildMetadata(string targetPath, bool targetIsFile)
|
||||
{
|
||||
CreateTransformSet();
|
||||
if (targetIsFile)
|
||||
{
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
return _transformSet.Select(t => t.Transform(source));
|
||||
return $"{targetPath}%(FileName)%(Extension)";
|
||||
}
|
||||
|
||||
private bool MappingsTargetPathIsFile(string targetPath)
|
||||
{
|
||||
var normalizedTargetPath = PathUtility.GetPathWithDirectorySeparator(targetPath);
|
||||
|
||||
return normalizedTargetPath[normalizedTargetPath.Length - 1] != Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,34 +66,109 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
|||
return;
|
||||
}
|
||||
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: Item {{ ItemType: {item.ItemType}, Condition: {item.Condition}, Include: {item.Include}, Exclude: {item.Exclude} }}");
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: ItemGroup {{ Condition: {destinationItemGroup.Condition} }}");
|
||||
|
||||
if (mergeExisting)
|
||||
{
|
||||
var existingItems = FindExistingItems(item, destinationItemGroup.ContainingProject);
|
||||
item = MergeWithExistingItemsWithSameCondition(item, destinationItemGroup);
|
||||
|
||||
foreach (var existingItem in existingItems)
|
||||
// Item will be null when it's entire set of includes has been merged.
|
||||
if (item == null)
|
||||
{
|
||||
var mergeResult = MergeItems(item, existingItem);
|
||||
item = mergeResult.InputItem;
|
||||
|
||||
// Existing Item is null when it's entire set of includes has been merged with the MergeItem
|
||||
if (mergeResult.ExistingItem == null)
|
||||
{
|
||||
existingItem.Parent.RemoveChild(existingItem);
|
||||
}
|
||||
|
||||
Execute(mergeResult.MergedItem, destinationItemGroup);
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: Item completely merged");
|
||||
return;
|
||||
}
|
||||
|
||||
// Item will be null only when it's entire set of includes is merged with existing items
|
||||
if (item != null)
|
||||
item = MergeWithExistingItemsWithDifferentCondition(item, destinationItemGroup);
|
||||
|
||||
// Item will be null when it is equivalent to a conditionless item
|
||||
if (item == null)
|
||||
{
|
||||
Execute(item, destinationItemGroup);
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: Item c");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Execute(item, destinationItemGroup);
|
||||
}
|
||||
|
||||
private ProjectItemElement MergeWithExistingItemsWithDifferentCondition(ProjectItemElement item, ProjectItemGroupElement destinationItemGroup)
|
||||
{
|
||||
var existingItemsWithDifferentCondition =
|
||||
FindExistingItemsWithDifferentCondition(item, destinationItemGroup.ContainingProject, destinationItemGroup);
|
||||
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: Merging Item with {existingItemsWithDifferentCondition.Count()} existing items with a different condition chain.");
|
||||
|
||||
foreach (var existingItem in existingItemsWithDifferentCondition)
|
||||
{
|
||||
Execute(item, destinationItemGroup);
|
||||
// When the existing item encompasses this item and it's condition is empty, ignore the current item
|
||||
if (item.IsEquivalentTo(existingItem))
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: equivalent {existingItem.ConditionChain().Count()}");
|
||||
|
||||
if (existingItem.ConditionChain().Count() == 0)
|
||||
{
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: Ignoring Item {{ ItemType: {existingItem.ItemType}, Condition: {existingItem.Condition}, Include: {existingItem.Include}, Exclude: {existingItem.Exclude} }}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't returned, and there are existing items with a separate condition, we need to
|
||||
// overwrite with those items inside the destinationItemGroup by using a Remove
|
||||
// Unless this is a conditionless item, in which case this the conditioned items should be doing the
|
||||
// overwriting.
|
||||
if (existingItemsWithDifferentCondition.Any() &&
|
||||
(item.ConditionChain().Count() > 0 || destinationItemGroup.ConditionChain().Count() > 0))
|
||||
{
|
||||
// Merge with the first remove if possible
|
||||
var existingRemoveItem = destinationItemGroup.Items
|
||||
.Where(i =>
|
||||
string.IsNullOrEmpty(i.Include)
|
||||
&& string.IsNullOrEmpty(i.Exclude)
|
||||
&& !string.IsNullOrEmpty(i.Remove))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (existingRemoveItem != null)
|
||||
{
|
||||
existingRemoveItem.Remove += ";" + item.Include;
|
||||
}
|
||||
else
|
||||
{
|
||||
var clearPreviousItem = _projectElementGenerator.CreateItemElement(item.ItemType);
|
||||
clearPreviousItem.Remove = item.Include;
|
||||
|
||||
Execute(clearPreviousItem, destinationItemGroup);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private ProjectItemElement MergeWithExistingItemsWithSameCondition(ProjectItemElement item, ProjectItemGroupElement destinationItemGroup)
|
||||
{
|
||||
var existingItemsWithSameCondition =
|
||||
FindExistingItemsWithSameCondition(item, destinationItemGroup.ContainingProject, destinationItemGroup);
|
||||
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: Merging Item with {existingItemsWithSameCondition.Count()} existing items with the same condition chain.");
|
||||
|
||||
foreach (var existingItem in existingItemsWithSameCondition)
|
||||
{
|
||||
var mergeResult = MergeItems(item, existingItem);
|
||||
item = mergeResult.InputItem;
|
||||
|
||||
// Existing Item is null when it's entire set of includes has been merged with the MergeItem
|
||||
if (mergeResult.ExistingItem == null)
|
||||
{
|
||||
existingItem.Parent.RemoveChild(existingItem);
|
||||
}
|
||||
|
||||
MigrationTrace.Instance.WriteLine($"{nameof(TransformApplicator)}: Adding Merged Item {{ ItemType: {mergeResult.MergedItem.ItemType}, Condition: {mergeResult.MergedItem.Condition}, Include: {mergeResult.MergedItem.Include}, Exclude: {mergeResult.MergedItem.Exclude} }}");
|
||||
Execute(mergeResult.MergedItem, destinationItemGroup);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public void Execute(
|
||||
|
@ -132,9 +207,6 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
|||
}
|
||||
|
||||
var commonIncludes = item.IntersectIncludes(existingItem).ToList();
|
||||
item.RemoveIncludes(commonIncludes);
|
||||
existingItem.RemoveIncludes(commonIncludes);
|
||||
|
||||
var mergedItem = _projectElementGenerator.AddItem(item.ItemType, string.Join(";", commonIncludes));
|
||||
|
||||
mergedItem.UnionExcludes(existingItem.Excludes());
|
||||
|
@ -143,6 +215,9 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
|||
mergedItem.AddMetadata(existingItem.Metadata);
|
||||
mergedItem.AddMetadata(item.Metadata);
|
||||
|
||||
item.RemoveIncludes(commonIncludes);
|
||||
existingItem.RemoveIncludes(commonIncludes);
|
||||
|
||||
var mergeResult = new MergeResult
|
||||
{
|
||||
InputItem = string.IsNullOrEmpty(item.Include) ? null : item,
|
||||
|
@ -153,13 +228,29 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
|
|||
return mergeResult;
|
||||
}
|
||||
|
||||
private IEnumerable<ProjectItemElement> FindExistingItems(ProjectItemElement item, ProjectRootElement project)
|
||||
private IEnumerable<ProjectItemElement> FindExistingItemsWithSameCondition(
|
||||
ProjectItemElement item,
|
||||
ProjectRootElement project,
|
||||
ProjectElementContainer destinationContainer)
|
||||
{
|
||||
return project.ItemsWithoutConditions()
|
||||
.Where(i => string.Equals(i.ItemType, item.ItemType, StringComparison.Ordinal))
|
||||
return project.Items
|
||||
.Where(i => i.Condition == item.Condition)
|
||||
.Where(i => i.Parent.ConditionChainsAreEquivalent(destinationContainer))
|
||||
.Where(i => i.ItemType == item.ItemType)
|
||||
.Where(i => i.IntersectIncludes(item).Any());
|
||||
}
|
||||
|
||||
private IEnumerable<ProjectItemElement> FindExistingItemsWithDifferentCondition(
|
||||
ProjectItemElement item,
|
||||
ProjectRootElement project,
|
||||
ProjectElementContainer destinationContainer)
|
||||
{
|
||||
return project.Items
|
||||
.Where(i => !i.ConditionChainsAreEquivalent(item) || !i.Parent.ConditionChainsAreEquivalent(destinationContainer))
|
||||
.Where(i => i.ItemType == item.ItemType)
|
||||
.Where(i => i.IntersectIncludes(item).Any());
|
||||
}
|
||||
|
||||
private class MergeResult
|
||||
{
|
||||
public ProjectItemElement InputItem { get; set; }
|
||||
|
|
|
@ -98,8 +98,8 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
// Get all project options and combine them
|
||||
var rootOptions = GetCompilerOptions();
|
||||
var configurationOptions = configurationName != null ? GetCompilerOptions(configurationName) : null;
|
||||
var targetFrameworkOptions = targetFramework != null ? GetCompilerOptions(targetFramework) : null;
|
||||
var configurationOptions = configurationName != null ? GetRawCompilerOptions(configurationName) : null;
|
||||
var targetFrameworkOptions = targetFramework != null ? GetRawCompilerOptions(targetFramework) : null;
|
||||
|
||||
// Combine all of the options
|
||||
var compilerOptions = CommonCompilerOptions.Combine(rootOptions, configurationOptions, targetFrameworkOptions);
|
||||
|
@ -136,7 +136,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
return _defaultCompilerOptions;
|
||||
}
|
||||
|
||||
private CommonCompilerOptions GetCompilerOptions(string configurationName)
|
||||
internal CommonCompilerOptions GetRawCompilerOptions(string configurationName)
|
||||
{
|
||||
CommonCompilerOptions options;
|
||||
if (_compilerOptionsByConfiguration.TryGetValue(configurationName, out options))
|
||||
|
@ -147,7 +147,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
return null;
|
||||
}
|
||||
|
||||
private CommonCompilerOptions GetCompilerOptions(NuGetFramework frameworkName)
|
||||
internal CommonCompilerOptions GetRawCompilerOptions(NuGetFramework frameworkName)
|
||||
{
|
||||
return GetTargetFramework(frameworkName)?.CompilerOptions;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ using System.Runtime.InteropServices;
|
|||
[assembly: Guid("303677d5-7312-4c3f-baee-beb1a9bd9fe6")]
|
||||
|
||||
[assembly: AssemblyMetadataAttribute("Serviceable", "True")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.DotNet.ProjectJsonMigration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.DotNet.ProjectModel.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100039ac461fa5c82c7dd2557400c4fd4e9dcdf7ac47e3d572548c04cd4673e004916610f4ea5cbf86f2b1ca1cb824f2a7b3976afecfcf4eb72d9a899aa6786effa10c30399e6580ed848231fec48374e41b3acf8811931343fc2f73acf72dae745adbcb7063cc4b50550618383202875223fc75401351cd89c44bf9b50e7fa3796")]
|
||||
[assembly:
|
||||
InternalsVisibleTo(
|
||||
|
|
|
@ -51,8 +51,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
|
||||
migrateAction.ShouldThrow<Exception>().Where(
|
||||
e => e.Message.Contains("MIGRATE1011::Deprecated Project:")
|
||||
&& e.Message.Contains("The 'packInclude' option is deprecated. Use 'files' in 'packOptions' instead.")
|
||||
&& e.Message.Contains("The 'compilationOptions' option is deprecated. Use 'buildOptions' instead."));
|
||||
&& e.Message.Contains("The 'packInclude' option is deprecated. Use 'files' in 'packOptions' instead. (line: 6, file:")
|
||||
&& e.Message.Contains("The 'compilationOptions' option is deprecated. Use 'buildOptions' instead. (line: 3, file:"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -7,6 +7,154 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
{
|
||||
public class GivenMSBuildExtensions
|
||||
{
|
||||
[Fact]
|
||||
public void ConditionChain_is_empty_when_element_and_parents_have_no_condition()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup = project.AddItemGroup();
|
||||
|
||||
var item1 = itemGroup.AddItem("test", "include1");
|
||||
|
||||
item1.ConditionChain().Should().HaveCount(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChain_has_parent_conditions_when_element_is_empty()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup = project.AddItemGroup();
|
||||
itemGroup.Condition = "condition";
|
||||
|
||||
var item1 = itemGroup.AddItem("test", "include1");
|
||||
|
||||
item1.ConditionChain().Should().HaveCount(1);
|
||||
item1.ConditionChain().First().Should().Be("condition");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChain_has_element_and_parent_conditions_when_they_exist()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup = project.AddItemGroup();
|
||||
itemGroup.Condition = "itemGroup";
|
||||
|
||||
var item1 = itemGroup.AddItem("test", "include1");
|
||||
item1.Condition = "item";
|
||||
|
||||
item1.ConditionChain().Should().HaveCount(2);
|
||||
item1.ConditionChain().Should().BeEquivalentTo("itemGroup", "item");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChainsAreEquivalent_is_true_when_neither_element_or_parents_have_conditions()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup = project.AddItemGroup();
|
||||
|
||||
var item1 = itemGroup.AddItem("test", "include1");
|
||||
var item2 = itemGroup.AddItem("test", "include2");
|
||||
|
||||
item1.ConditionChainsAreEquivalent(item2).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChainsAreEquivalent_is_true_when_elements_have_the_same_condition()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup = project.AddItemGroup();
|
||||
|
||||
var item1 = itemGroup.AddItem("test", "include1");
|
||||
var item2 = itemGroup.AddItem("test", "include2");
|
||||
item1.Condition = "item";
|
||||
item2.Condition = "item";
|
||||
|
||||
item1.ConditionChainsAreEquivalent(item2).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChainsAreEquivalent_is_true_when_element_condition_matches_condition_of_other_element_parent()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup1 = project.AddItemGroup();
|
||||
var itemGroup2 = project.AddItemGroup();
|
||||
itemGroup1.Condition = "item";
|
||||
|
||||
var item1 = itemGroup1.AddItem("test", "include1");
|
||||
var item2 = itemGroup2.AddItem("test", "include2");
|
||||
item2.Condition = "item";
|
||||
|
||||
item1.ConditionChainsAreEquivalent(item2).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChainsAreEquivalent_is_false_when_elements_have_different_conditions()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup = project.AddItemGroup();
|
||||
|
||||
var item1 = itemGroup.AddItem("test", "include1");
|
||||
var item2 = itemGroup.AddItem("test", "include2");
|
||||
item1.Condition = "item";
|
||||
item2.Condition = "item2";
|
||||
|
||||
item1.ConditionChainsAreEquivalent(item2).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChainsAreEquivalent_is_false_when_other_element_parent_has_a_condition()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup1 = project.AddItemGroup();
|
||||
var itemGroup2 = project.AddItemGroup();
|
||||
itemGroup1.Condition = "item";
|
||||
|
||||
var item1 = itemGroup1.AddItem("test", "include1");
|
||||
var item2 = itemGroup2.AddItem("test", "include2");
|
||||
|
||||
item1.ConditionChainsAreEquivalent(item2).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionChainsAreEquivalent_is_false_when_both_element_parent_conditions_dont_match()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var itemGroup1 = project.AddItemGroup();
|
||||
var itemGroup2 = project.AddItemGroup();
|
||||
itemGroup1.Condition = "item";
|
||||
itemGroup2.Condition = "item2";
|
||||
|
||||
var item1 = itemGroup1.AddItem("test", "include1");
|
||||
var item2 = itemGroup2.AddItem("test", "include2");
|
||||
|
||||
item1.ConditionChainsAreEquivalent(item2).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasConflictingMetadata_returns_true_when_items_have_metadata_with_same_name_but_different_value()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item1 = project.AddItem("test", "include1");
|
||||
item1.AddMetadata("name", "value");
|
||||
|
||||
var item2 = project.AddItem("test1", "include1");
|
||||
item2.AddMetadata("name", "value2");
|
||||
|
||||
item1.HasConflictingMetadata(item2).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasConflictingMetadata_returns_false_when_items_have_metadata_with_same_nameand_value()
|
||||
{
|
||||
var project = ProjectRootElement.Create();
|
||||
var item1 = project.AddItem("test", "include1");
|
||||
item1.AddMetadata("name", "value");
|
||||
|
||||
var item2 = project.AddItem("test1", "include1");
|
||||
item2.AddMetadata("name", "value");
|
||||
|
||||
item1.HasConflictingMetadata(item2).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Includes_returns_include_value_split_by_semicolon()
|
||||
{
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>1F2EF070-AC5F-4078-AFB0-65745AC691B9</ProjectGuid>
|
||||
<RootNamespace>Microsoft.DotNet.ProjectJsonMigration.Tests</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' “>..\artifact\obj\$(RootNamespace)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' “>..\artifacts\bin\</OutputPath>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifact\obj\$(RootNamespace)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\artifacts\bin\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
|
|
|
@ -48,18 +48,15 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Migrating_empty_buildOptions_populates_only_AssemblyName_and_OutputType()
|
||||
public void Migrating_empty_buildOptions_populates_only_AssemblyName_Compile_and_EmbeddedResource()
|
||||
{
|
||||
var mockProj = RunBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": { }
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count().Should().Be(2);
|
||||
mockProj.Properties.Any(
|
||||
p =>
|
||||
!(p.Name.Equals("AssemblyName", StringComparison.Ordinal) ||
|
||||
p.Name.Equals("OutputType", StringComparison.Ordinal))).Should().BeFalse();
|
||||
mockProj.Properties.Count().Should().Be(1);
|
||||
mockProj.Properties.Any(p => !p.Name.Equals("AssemblyName", StringComparison.Ordinal)).Should().BeFalse();
|
||||
|
||||
mockProj.Items.Count().Should().Be(2);
|
||||
mockProj.Items.First(i => i.ItemType == "Compile").Include.Should().Be(@"**\*.cs");
|
||||
|
@ -107,7 +104,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "DefineConstants").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "DefineConstants").Value.Should().Be("DEBUG;TRACE");
|
||||
mockProj.Properties.First(p => p.Name == "DefineConstants")
|
||||
.Value.Should().Be("$(DefineConstants);DEBUG;TRACE");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -121,7 +119,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
}");
|
||||
|
||||
mockProj.Properties.Count(p => p.Name == "NoWarn").Should().Be(1);
|
||||
mockProj.Properties.First(p => p.Name == "NoWarn").Value.Should().Be("CS0168;CS0219");
|
||||
mockProj.Properties.First(p => p.Name == "NoWarn").Value.Should().Be("$(NoWarn);CS0168;CS0219");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -39,6 +39,29 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
.Contain("'$(Configuration)' == 'testconfig'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Frameworks_buildOptions_produce_expected_properties_in_a_group_with_a_condition()
|
||||
{
|
||||
var mockProj = RunConfigurationsRuleOnPj(@"
|
||||
{
|
||||
""frameworks"": {
|
||||
""netcoreapp1.0"": {
|
||||
""buildOptions"": {
|
||||
""emitEntryPoint"": ""true"",
|
||||
""debugType"": ""full""
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
mockProj.Properties.Count(
|
||||
prop => prop.Name == "OutputType" || prop.Name == "DebugType").Should().Be(2);
|
||||
|
||||
mockProj.Properties.First(p => p.Name == "OutputType")
|
||||
.Parent.Condition.Should()
|
||||
.Contain("'$(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion)' == '.NETCoreApp,Version=v1.0'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_properties_are_not_written_when_they_overlap_with_buildOptions()
|
||||
{
|
||||
|
@ -67,11 +90,10 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
{
|
||||
property.Parent.Condition.Should().Be(string.Empty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_includes_are_not_written_when_they_overlap_with_buildOptions()
|
||||
public void Configuration_buildOptions_includes_and_Remove_are_written_when_they_differ_from_base_buildOptions()
|
||||
{
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
|
@ -97,25 +119,31 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
}
|
||||
}");
|
||||
|
||||
mockProj.Items.Count(item => item.ItemType == "Content").Should().Be(3);
|
||||
var contentItems = mockProj.Items.Where(item => item.ItemType == "Content");
|
||||
|
||||
mockProj.Items.Where(item => item.ItemType == "Content")
|
||||
.Count(item => !string.IsNullOrEmpty(item.Parent.Condition))
|
||||
.Should()
|
||||
.Be(1);
|
||||
contentItems.Count().Should().Be(4);
|
||||
|
||||
var configContent = mockProj.Items
|
||||
.Where(item => item.ItemType == "Content").First(item => !string.IsNullOrEmpty(item.Parent.Condition));
|
||||
// 2 for Base Build options
|
||||
contentItems.Where(i => i.ConditionChain().Count() == 0).Should().HaveCount(2);
|
||||
|
||||
// 2 for Configuration BuildOptions (1 Remove, 1 Include)
|
||||
contentItems.Where(i => i.ConditionChain().Count() == 1).Should().HaveCount(2);
|
||||
|
||||
var configIncludeContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0 && !string.IsNullOrEmpty(item.Include));
|
||||
var configRemoveContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0 && !string.IsNullOrEmpty(item.Remove));
|
||||
|
||||
// Directories are not converted to globs in the result because we did not write the directory
|
||||
configContent.Include.Should().Be(@"root;rootfile.cs");
|
||||
configContent.Exclude.Should().Be(@"src;rootfile.cs;src\file2.cs");
|
||||
configRemoveContentItem.Remove.Should().Be(@"root;src;rootfile.cs");
|
||||
configIncludeContentItem.Include.Should().Be(@"root;src;rootfile.cs");
|
||||
configIncludeContentItem.Exclude.Should().Be(@"src;rootfile.cs;src\file2.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_includes_which_have_different_excludes_than_buildOptions_throws()
|
||||
public void Configuration_buildOptions_which_have_different_excludes_than_buildOptions_overwrites()
|
||||
{
|
||||
Action action = () => RunConfigurationsRuleOnPj(@"
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
|
@ -130,7 +158,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""root"", ""src"", ""rootfile.cs""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""exclude"": [""rootfile.cs"", ""someotherfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
|
@ -139,10 +167,307 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
|
|||
}
|
||||
}");
|
||||
|
||||
action.ShouldThrow<Exception>()
|
||||
.WithMessage(
|
||||
"MIGRATE20012::Configuration Exclude: Unable to migrate projects with excluded files in configurations.");
|
||||
var contentItems = mockProj.Items.Where(item => item.ItemType == "Content");
|
||||
|
||||
contentItems.Count().Should().Be(5);
|
||||
|
||||
// 2 for Base Build options
|
||||
contentItems.Where(i => i.ConditionChain().Count() == 0).Should().HaveCount(2);
|
||||
|
||||
// 3 for Configuration BuildOptions (1 Remove, 2 Include)
|
||||
contentItems.Where(i => i.ConditionChain().Count() == 1).Should().HaveCount(3);
|
||||
|
||||
var configIncludeContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include.Contains("root"));
|
||||
|
||||
var configIncludeContentItem2 = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include.Contains(@"src\file1.cs"));
|
||||
|
||||
var configRemoveContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0 && !string.IsNullOrEmpty(item.Remove));
|
||||
|
||||
// Directories are not converted to globs in the result because we did not write the directory
|
||||
configRemoveContentItem.Removes()
|
||||
.Should().BeEquivalentTo("root", "src", "rootfile.cs", @"src\file1.cs", @"src\file2.cs");
|
||||
|
||||
configIncludeContentItem.Includes().Should().BeEquivalentTo("root", "src", "rootfile.cs");
|
||||
configIncludeContentItem.Excludes()
|
||||
.Should().BeEquivalentTo("rootfile.cs", "someotherfile.cs", @"src\file2.cs");
|
||||
|
||||
configIncludeContentItem2.Includes().Should().BeEquivalentTo(@"src\file1.cs", @"src\file2.cs");
|
||||
configIncludeContentItem2.Excludes().Should().BeEquivalentTo(@"src\file2.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_which_have_mappings_to_directory_add_link_metadata_with_item_metadata()
|
||||
{
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""mappings"": {
|
||||
""/some/dir/"" : {
|
||||
""include"": [""src"", ""root""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
var contentItems = mockProj.Items.Where(item => item.ItemType == "Content");
|
||||
|
||||
contentItems.Count().Should().Be(2);
|
||||
contentItems.Where(i => i.ConditionChain().Count() == 1).Should().HaveCount(2);
|
||||
|
||||
var configIncludeContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include.Contains("root"));
|
||||
|
||||
var configIncludeContentItem2 = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include.Contains(@"src\file1.cs"));
|
||||
|
||||
configIncludeContentItem.Includes().Should().BeEquivalentTo("root", "src");
|
||||
configIncludeContentItem.Excludes()
|
||||
.Should().BeEquivalentTo("rootfile.cs", "src", @"src\file2.cs");
|
||||
|
||||
configIncludeContentItem.GetMetadataWithName("Link").Should().NotBeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("Link").Value.Should().Be("/some/dir/%(FileName)%(Extension)");
|
||||
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
|
||||
configIncludeContentItem2.Includes().Should().BeEquivalentTo(@"src\file1.cs", @"src\file2.cs");
|
||||
configIncludeContentItem2.Excludes().Should().BeEquivalentTo(@"src\file2.cs");
|
||||
|
||||
configIncludeContentItem2.GetMetadataWithName("Link").Should().NotBeNull();
|
||||
configIncludeContentItem2.GetMetadataWithName("Link").Value.Should().Be("/some/dir/%(FileName)%(Extension)");
|
||||
|
||||
configIncludeContentItem2.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem2.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_which_have_mappings_overlapping_with_includes_in_same_configuration_merged_items_have_Link_metadata()
|
||||
{
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""src"", ""root""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""],
|
||||
""mappings"": {
|
||||
""/some/dir/"" : {
|
||||
""include"": [""src""],
|
||||
""exclude"": [""src"", ""src/rootfile.cs""]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
var contentItems = mockProj.Items.Where(item => item.ItemType == "Content");
|
||||
|
||||
contentItems.Count().Should().Be(3);
|
||||
contentItems.Where(i => i.ConditionChain().Count() == 1).Should().HaveCount(3);
|
||||
|
||||
var configIncludeContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include == "root");
|
||||
|
||||
var configIncludeContentItem2 = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include == "src");
|
||||
|
||||
var configIncludeContentItem3 = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include.Contains(@"src\file1.cs"));
|
||||
|
||||
// Directories are not converted to globs in the result because we did not write the directory
|
||||
|
||||
configIncludeContentItem.Includes().Should().BeEquivalentTo("root");
|
||||
configIncludeContentItem.Excludes()
|
||||
.Should().BeEquivalentTo("rootfile.cs", "src", @"src\file2.cs");
|
||||
|
||||
configIncludeContentItem.GetMetadataWithName("Link").Should().BeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
|
||||
configIncludeContentItem2.Include.Should().Be("src");
|
||||
configIncludeContentItem2.Excludes().Should().BeEquivalentTo("src", "rootfile.cs", @"src\rootfile.cs", @"src\file2.cs");
|
||||
|
||||
configIncludeContentItem2.GetMetadataWithName("Link").Should().NotBeNull();
|
||||
configIncludeContentItem2.GetMetadataWithName("Link").Value.Should().Be("/some/dir/%(FileName)%(Extension)");
|
||||
configIncludeContentItem2.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem2.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
|
||||
configIncludeContentItem3.Includes().Should().BeEquivalentTo(@"src\file1.cs");
|
||||
configIncludeContentItem3.Exclude.Should().Be(@"src\file2.cs");
|
||||
|
||||
configIncludeContentItem3.GetMetadataWithName("Link").Should().BeNull();
|
||||
configIncludeContentItem3.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem3.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_which_have_mappings_overlapping_with_includes_in_root_buildoptions_has_remove()
|
||||
{
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"" : {
|
||||
""copyToOutput"": {
|
||||
""include"": [""src"", ""root""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs"", ""src/file2.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
},
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""mappings"": {
|
||||
""/some/dir/"" : {
|
||||
""include"": [""src""],
|
||||
""exclude"": [""src"", ""rootfile.cs""]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
var contentItems = mockProj.Items.Where(item => item.ItemType == "Content");
|
||||
|
||||
contentItems.Count().Should().Be(4);
|
||||
|
||||
var rootBuildOptionsContentItems = contentItems.Where(i => i.ConditionChain().Count() == 0).ToList();
|
||||
rootBuildOptionsContentItems.Count().Should().Be(2);
|
||||
foreach (var buildOptionContentItem in rootBuildOptionsContentItems)
|
||||
{
|
||||
buildOptionContentItem.GetMetadataWithName("Link").Should().BeNull();
|
||||
buildOptionContentItem.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
}
|
||||
|
||||
var configItems = contentItems.Where(i => i.ConditionChain().Count() == 1);
|
||||
configItems.Should().HaveCount(2);
|
||||
|
||||
var configIncludeContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include.Contains("src"));
|
||||
|
||||
var configRemoveContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& !string.IsNullOrEmpty(item.Remove));
|
||||
|
||||
configIncludeContentItem.Include.Should().Be("src");
|
||||
|
||||
configIncludeContentItem.GetMetadataWithName("Link").Should().NotBeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("Link").Value.Should().Be("/some/dir/%(FileName)%(Extension)");
|
||||
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
|
||||
configRemoveContentItem.Remove.Should().Be("src");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configuration_buildOptions_which_have_mappings_overlapping_with_includes_in_same_configuration_and_root_buildOptions_have_removes_and_Link_metadata_and_encompassed_items_are_merged()
|
||||
{
|
||||
var mockProj = RunConfigurationsAndBuildOptionsRuleOnPj(@"
|
||||
{
|
||||
""buildOptions"" : {
|
||||
""copyToOutput"": {
|
||||
""include"": [""src"", ""root""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file1.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""]
|
||||
}
|
||||
},
|
||||
""configurations"": {
|
||||
""testconfig"": {
|
||||
""buildOptions"": {
|
||||
""copyToOutput"": {
|
||||
""include"": [""src"", ""root""],
|
||||
""exclude"": [""src"", ""rootfile.cs""],
|
||||
""includeFiles"": [""src/file3.cs""],
|
||||
""excludeFiles"": [""src/file2.cs""],
|
||||
""mappings"": {
|
||||
""/some/dir/"" : {
|
||||
""include"": [""src""],
|
||||
""exclude"": [""src"", ""src/rootfile.cs""]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
var contentItems = mockProj.Items.Where(item => item.ItemType == "Content");
|
||||
|
||||
contentItems.Count().Should().Be(5);
|
||||
contentItems.Where(i => i.ConditionChain().Count() == 1).Should().HaveCount(3);
|
||||
|
||||
var rootBuildOptionsContentItems = contentItems.Where(i => i.ConditionChain().Count() == 0).ToList();
|
||||
rootBuildOptionsContentItems.Count().Should().Be(2);
|
||||
foreach (var buildOptionContentItem in rootBuildOptionsContentItems)
|
||||
{
|
||||
buildOptionContentItem.GetMetadataWithName("Link").Should().BeNull();
|
||||
buildOptionContentItem.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
}
|
||||
|
||||
var configIncludeEncompassedItem = contentItems.FirstOrDefault(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include == "root");
|
||||
configIncludeEncompassedItem.Should().BeNull();
|
||||
|
||||
var configIncludeContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include == "src");
|
||||
|
||||
var configIncludeContentItem2 = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& item.Include.Contains(@"src\file3.cs"));
|
||||
|
||||
var configRemoveContentItem = contentItems.First(
|
||||
item => item.ConditionChain().Count() > 0
|
||||
&& !string.IsNullOrEmpty(item.Remove));
|
||||
|
||||
configIncludeContentItem.Include.Should().Be("src");
|
||||
configIncludeContentItem.Excludes().Should().BeEquivalentTo("src", "rootfile.cs", @"src\rootfile.cs", @"src\file2.cs");
|
||||
|
||||
configIncludeContentItem.GetMetadataWithName("Link").Should().NotBeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("Link").Value.Should().Be("/some/dir/%(FileName)%(Extension)");
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
|
||||
configIncludeContentItem2.Includes().Should().BeEquivalentTo(@"src\file3.cs");
|
||||
configIncludeContentItem2.Exclude.Should().Be(@"src\file2.cs");
|
||||
|
||||
configIncludeContentItem2.GetMetadataWithName("Link").Should().BeNull();
|
||||
configIncludeContentItem2.GetMetadataWithName("CopyToOutputDirectory").Should().NotBeNull();
|
||||
configIncludeContentItem2.GetMetadataWithName("CopyToOutputDirectory").Value.Should().Be("PreserveNewest");
|
||||
|
||||
configRemoveContentItem.Removes().Should().BeEquivalentTo("src");
|
||||
}
|
||||
|
||||
private ProjectRootElement RunConfigurationsRuleOnPj(string s, string testDirectory = null)
|
||||
{
|
||||
testDirectory = testDirectory ?? Temp.CreateDirectory().Path;
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
|||
// TODO: Standalone apps [InlineData("TestAppSimple", false)]
|
||||
// https://github.com/dotnet/sdk/issues/73 [InlineData("TestAppWithLibrary/TestApp", false)]
|
||||
[InlineData("TestAppWithRuntimeOptions")]
|
||||
[InlineData("TestAppWithContents")]
|
||||
public void It_migrates_apps(string projectName)
|
||||
{
|
||||
var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
||||
|
@ -204,6 +205,8 @@ namespace Microsoft.DotNet.Migration.Tests
|
|||
|
||||
private string BuildMSBuild(string projectDirectory, string configuration="Debug")
|
||||
{
|
||||
DeleteXproj(projectDirectory);
|
||||
|
||||
var result = new Build3Command()
|
||||
.WithWorkingDirectory(projectDirectory)
|
||||
.ExecuteWithCapturedOutput($"/p:Configuration={configuration}");
|
||||
|
@ -215,6 +218,15 @@ namespace Microsoft.DotNet.Migration.Tests
|
|||
return result.StdOut;
|
||||
}
|
||||
|
||||
private void DeleteXproj(string projectDirectory)
|
||||
{
|
||||
var xprojFiles = Directory.EnumerateFiles(projectDirectory, "*.xproj");
|
||||
foreach (var xprojFile in xprojFiles)
|
||||
{
|
||||
File.Delete(xprojFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void OutputDiagnostics(MigratedBuildComparisonData comparisonData)
|
||||
{
|
||||
OutputDiagnostics(comparisonData.MSBuildBuildOutputs, comparisonData.ProjectJsonBuildOutputs);
|
||||
|
|
Loading…
Reference in a new issue