Adding merging of ProjectItemElement.Update. Before, we only merged Include.

This commit is contained in:
Livar Cunha 2017-02-22 20:02:57 -08:00
parent 55d5d98332
commit 3bbfcb428b
4 changed files with 346 additions and 87 deletions

View file

@ -71,6 +71,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration
public const string IncludesNotEquivalent = "{0}.{1} includes not equivalent.";
public const string UpdatesNotEquivalent = "{0}.{1} updates not equivalent.";
public const string ExcludesNotEquivalent = "{0}.{1} excludes not equivalent.";
public const string RemovesNotEquivalent = "{0}.{1} removes not equivalent.";
@ -109,6 +111,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration
public const string ItemTransformApplicatorEncompassedIncludes = "{0}: encompassed includes {1}";
public const string ItemTransformApplicatorEncompassedUpdates = "{0}: encompassed updates {1}";
public const string ItemTransformApplicatorRemovingItem = "{0}: Removing Item {{ ItemType: {1}, Condition: {2}, Include: {3}, Exclude: {4} }}";
public const string ItemTransformApplicatorIgnoringItem = "{0}: Ignoring Item {{ ItemType: {1}, Condition: {2}, Include: {3}, Exclude: {4} }}";

View file

@ -14,7 +14,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration
public static IEnumerable<string> GetEncompassedIncludes(this ProjectItemElement item,
ProjectItemElement otherItem, TextWriter trace = null)
{
if (otherItem.IsEquivalentToExceptIncludeAndExclude(item, trace) &&
if (otherItem.IsEquivalentToExceptIncludeUpdateAndExclude(item, trace) &&
new HashSet<string>(otherItem.Excludes()).IsSubsetOf(new HashSet<string>(item.Excludes())))
{
return otherItem.IntersectIncludes(item);
@ -23,6 +23,18 @@ namespace Microsoft.DotNet.ProjectJsonMigration
return Enumerable.Empty<string>();
}
public static IEnumerable<string> GetEncompassedUpdates(this ProjectItemElement item,
ProjectItemElement otherItem, TextWriter trace = null)
{
if (otherItem.IsEquivalentToExceptIncludeUpdateAndExclude(item, trace) &&
new HashSet<string>(otherItem.Excludes()).IsSubsetOf(new HashSet<string>(item.Excludes())))
{
return otherItem.IntersectUpdates(item);
}
return Enumerable.Empty<string>();
}
public static bool IsEquivalentTo(this ProjectItemElement item, ProjectItemElement otherItem, TextWriter trace = null)
{
// Different includes
@ -32,6 +44,12 @@ namespace Microsoft.DotNet.ProjectJsonMigration
return false;
}
if (item.IntersectUpdates(otherItem).Count() != item.Updates().Count())
{
trace?.WriteLine(String.Format(LocalizableStrings.UpdatesNotEquivalent, nameof(MSBuildExtensions), nameof(IsEquivalentTo)));
return false;
}
// Different Excludes
if (item.IntersectExcludes(otherItem).Count() != item.Excludes().Count())
{
@ -39,10 +57,10 @@ namespace Microsoft.DotNet.ProjectJsonMigration
return false;
}
return item.IsEquivalentToExceptIncludeAndExclude(otherItem, trace);
return item.IsEquivalentToExceptIncludeUpdateAndExclude(otherItem, trace);
}
public static bool IsEquivalentToExceptIncludeAndExclude(this ProjectItemElement item, ProjectItemElement otherItem, TextWriter trace = null)
public static bool IsEquivalentToExceptIncludeUpdateAndExclude(this ProjectItemElement item, ProjectItemElement otherItem, TextWriter trace = null)
{
// Different remove
if (item.Remove != otherItem.Remove)
@ -119,6 +137,12 @@ namespace Microsoft.DotNet.ProjectJsonMigration
return SplitSemicolonDelimitedValues(item.Include);
}
public static IEnumerable<string> Updates(
this ProjectItemElement item)
{
return SplitSemicolonDelimitedValues(item.Update);
}
public static IEnumerable<string> Excludes(
this ProjectItemElement item)
{
@ -141,6 +165,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration
return item.Includes().Intersect(otherItem.Includes());
}
public static IEnumerable<string> IntersectUpdates(this ProjectItemElement item, ProjectItemElement otherItem)
{
return item.Updates().Intersect(otherItem.Updates());
}
public static IEnumerable<string> IntersectExcludes(this ProjectItemElement item, ProjectItemElement otherItem)
{
return item.Excludes().Intersect(otherItem.Excludes());
@ -151,6 +180,11 @@ namespace Microsoft.DotNet.ProjectJsonMigration
item.Include = string.Join(";", item.Includes().Except(includesToRemove));
}
public static void RemoveUpdates(this ProjectItemElement item, IEnumerable<string> updatesToRemove)
{
item.Update = string.Join(";", item.Updates().Except(updatesToRemove));
}
public static void UnionIncludes(this ProjectItemElement item, IEnumerable<string> includesToAdd)
{
item.Include = string.Join(";", item.Includes().Union(includesToAdd));

View file

@ -19,12 +19,18 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
{
if (typeof(T) != typeof(ProjectItemElement))
{
throw new ArgumentException(String.Format(LocalizableStrings.ExpectedElementToBeOfTypeNotTypeError, nameof(ProjectItemElement), typeof(T)));
throw new ArgumentException(String.Format(
LocalizableStrings.ExpectedElementToBeOfTypeNotTypeError,
nameof(ProjectItemElement),
typeof(T)));
}
if (typeof(U) != typeof(ProjectItemGroupElement))
{
throw new ArgumentException(String.Format(LocalizableStrings.ExpectedElementToBeOfTypeNotTypeError, nameof(ProjectItemGroupElement), typeof(U)));
throw new ArgumentException(String.Format(
LocalizableStrings.ExpectedElementToBeOfTypeNotTypeError,
nameof(ProjectItemGroupElement),
typeof(U)));
}
if (element == null)
@ -40,8 +46,18 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
var item = element as ProjectItemElement;
var destinationItemGroup = destinationElement as ProjectItemGroupElement;
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorHeader, nameof(ItemTransformApplicator), item.ItemType, item.Condition, item.Include, item.Exclude, item.Update));
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorItemGroup, nameof(ItemTransformApplicator), destinationItemGroup.Condition));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorHeader,
nameof(ItemTransformApplicator),
item.ItemType,
item.Condition,
item.Include,
item.Exclude,
item.Update));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorItemGroup,
nameof(ItemTransformApplicator),
destinationItemGroup.Condition));
if (mergeExisting)
{
@ -49,7 +65,9 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
item = MergeWithExistingItemsWithSameCondition(item, destinationItemGroup);
if (item == null)
{
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformAppliatorItemCompletelyMerged, nameof(ItemTransformApplicator)));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformAppliatorItemCompletelyMerged,
nameof(ItemTransformApplicator)));
return;
}
@ -57,14 +75,18 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
item = MergeWithExistingItemsWithNoCondition(item, destinationItemGroup);
if (item == null)
{
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformAppliatorItemCompletelyMerged, nameof(ItemTransformApplicator)));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformAppliatorItemCompletelyMerged,
nameof(ItemTransformApplicator)));
return;
}
item = MergeWithExistingItemsWithACondition(item, destinationItemGroup);
if (item == null)
{
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformAppliatorItemCompletelyMerged, nameof(ItemTransformApplicator)));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformAppliatorItemCompletelyMerged,
nameof(ItemTransformApplicator)));
return;
}
}
@ -88,13 +110,22 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
var outputItem = itemGroup.ContainingProject.CreateItemElement("___TEMP___");
outputItem.CopyFrom(item);
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorAddItemHeader, nameof(ItemTransformApplicator), outputItem.ItemType, outputItem.Condition, outputItem.Include, outputItem.Exclude, outputItem.Update));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorAddItemHeader,
nameof(ItemTransformApplicator),
outputItem.ItemType,
outputItem.Condition,
outputItem.Include,
outputItem.Exclude,
outputItem.Update));
itemGroup.AppendChild(outputItem);
outputItem.AddMetadata(item.Metadata, MigrationTrace.Instance);
}
private ProjectItemElement MergeWithExistingItemsWithACondition(ProjectItemElement item, ProjectItemGroupElement destinationItemGroup)
private ProjectItemElement MergeWithExistingItemsWithACondition(
ProjectItemElement item,
ProjectItemGroupElement destinationItemGroup)
{
// This logic only applies to conditionless items
if (item.ConditionChain().Any() || destinationItemGroup.ConditionChain().Any())
@ -105,63 +136,156 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
var existingItemsWithACondition =
FindExistingItemsWithACondition(item, destinationItemGroup.ContainingProject, destinationItemGroup);
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorMergingItemWithExistingItems, nameof(ItemTransformApplicator), existingItemsWithACondition.Count()));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorMergingItemWithExistingItems,
nameof(ItemTransformApplicator),
existingItemsWithACondition.Count()));
foreach (var existingItem in existingItemsWithACondition)
{
// If this item is encompassing items in a condition, remove the encompassed includes from the existing item
var encompassedIncludes = item.GetEncompassedIncludes(existingItem, MigrationTrace.Instance);
if (encompassedIncludes.Any())
if (!string.IsNullOrEmpty(item.Include))
{
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorEncompassedIncludes, nameof(ItemTransformApplicator), string.Join(", ", encompassedIncludes)));
existingItem.RemoveIncludes(encompassedIncludes);
MergeOnIncludesWithExistingItemsWithACondition(item, existingItem, destinationItemGroup);
}
// continue if the existing item is now empty
if (!existingItem.Includes().Any())
if (!string.IsNullOrEmpty(item.Update))
{
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorRemovingItem, nameof(ItemTransformApplicator), existingItem.ItemType, existingItem.Condition, existingItem.Include, existingItem.Exclude));
existingItem.Parent.RemoveChild(existingItem);
continue;
}
// If we haven't continued, the existing item may have includes
// that need to be removed before being redefined, to avoid duplicate includes
// Create or merge with existing remove
var remainingIntersectedIncludes = existingItem.IntersectIncludes(item);
if (remainingIntersectedIncludes.Any())
{
var existingRemoveItem = destinationItemGroup.Items
.Where(i =>
string.IsNullOrEmpty(i.Include)
&& string.IsNullOrEmpty(i.Exclude)
&& !string.IsNullOrEmpty(i.Remove))
.FirstOrDefault();
if (existingRemoveItem != null)
{
var removes = new HashSet<string>(existingRemoveItem.Remove.Split(';'));
foreach (var include in remainingIntersectedIncludes)
{
removes.Add(include);
}
existingRemoveItem.Remove = string.Join(";", removes);
}
else
{
var clearPreviousItem = _projectElementGenerator.CreateItemElement(item.ItemType);
clearPreviousItem.Remove = string.Join(";", remainingIntersectedIncludes);
AddItemToItemGroup(clearPreviousItem, existingItem.Parent as ProjectItemGroupElement);
}
MergeOnUpdatesWithExistingItemsWithACondition(item, existingItem, destinationItemGroup);
}
}
return item;
}
private ProjectItemElement MergeWithExistingItemsWithNoCondition(ProjectItemElement item, ProjectItemGroupElement destinationItemGroup)
private void MergeOnIncludesWithExistingItemsWithACondition(
ProjectItemElement item,
ProjectItemElement existingItem,
ProjectItemGroupElement destinationItemGroup)
{
// If this item is encompassing items in a condition, remove the encompassed includes from the existing item
var encompassedIncludes = item.GetEncompassedIncludes(existingItem, MigrationTrace.Instance);
if (encompassedIncludes.Any())
{
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorEncompassedIncludes,
nameof(ItemTransformApplicator),
string.Join(", ", encompassedIncludes)));
existingItem.RemoveIncludes(encompassedIncludes);
}
// continue if the existing item is now empty
if (!existingItem.Includes().Any())
{
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorRemovingItem,
nameof(ItemTransformApplicator),
existingItem.ItemType,
existingItem.Condition,
existingItem.Include,
existingItem.Exclude));
existingItem.Parent.RemoveChild(existingItem);
return;
}
// If we haven't continued, the existing item may have includes
// that need to be removed before being redefined, to avoid duplicate includes
// Create or merge with existing remove
var remainingIntersectedIncludes = existingItem.IntersectIncludes(item);
if (remainingIntersectedIncludes.Any())
{
var existingRemoveItem = destinationItemGroup.Items
.Where(i =>
string.IsNullOrEmpty(i.Include)
&& string.IsNullOrEmpty(i.Exclude)
&& !string.IsNullOrEmpty(i.Remove))
.FirstOrDefault();
if (existingRemoveItem != null)
{
var removes = new HashSet<string>(existingRemoveItem.Remove.Split(';'));
foreach (var include in remainingIntersectedIncludes)
{
removes.Add(include);
}
existingRemoveItem.Remove = string.Join(";", removes);
}
else
{
var clearPreviousItem = _projectElementGenerator.CreateItemElement(item.ItemType);
clearPreviousItem.Remove = string.Join(";", remainingIntersectedIncludes);
AddItemToItemGroup(clearPreviousItem, existingItem.Parent as ProjectItemGroupElement);
}
}
}
private void MergeOnUpdatesWithExistingItemsWithACondition(
ProjectItemElement item,
ProjectItemElement existingItem,
ProjectItemGroupElement destinationItemGroup)
{
// If this item is encompassing items in a condition, remove the encompassed updates from the existing item
var encompassedUpdates = item.GetEncompassedUpdates(existingItem, MigrationTrace.Instance);
if (encompassedUpdates.Any())
{
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorEncompassedUpdates,
nameof(ItemTransformApplicator),
string.Join(", ", encompassedUpdates)));
existingItem.RemoveIncludes(encompassedUpdates);
}
// continue if the existing item is now empty
if (!existingItem.Updates().Any())
{
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorRemovingItem,
nameof(ItemTransformApplicator),
existingItem.ItemType,
existingItem.Condition,
existingItem.Update,
existingItem.Exclude));
existingItem.Parent.RemoveChild(existingItem);
return;
}
// If we haven't continued, the existing item may have updates
// that need to be removed before being redefined, to avoid duplicate updates
// Create or merge with existing remove
var remainingIntersectedUpdates = existingItem.IntersectUpdates(item);
if (remainingIntersectedUpdates.Any())
{
var existingRemoveItem = destinationItemGroup.Items
.Where(i =>
string.IsNullOrEmpty(i.Update)
&& string.IsNullOrEmpty(i.Exclude)
&& !string.IsNullOrEmpty(i.Remove))
.FirstOrDefault();
if (existingRemoveItem != null)
{
var removes = new HashSet<string>(existingRemoveItem.Remove.Split(';'));
foreach (var update in remainingIntersectedUpdates)
{
removes.Add(update);
}
existingRemoveItem.Remove = string.Join(";", removes);
}
else
{
var clearPreviousItem = _projectElementGenerator.CreateItemElement(item.ItemType);
clearPreviousItem.Remove = string.Join(";", remainingIntersectedUpdates);
AddItemToItemGroup(clearPreviousItem, existingItem.Parent as ProjectItemGroupElement);
}
}
}
private ProjectItemElement MergeWithExistingItemsWithNoCondition(
ProjectItemElement item,
ProjectItemGroupElement destinationItemGroup)
{
// This logic only applies to items being placed into a condition
if (!item.ConditionChain().Any() && !destinationItemGroup.ConditionChain().Any())
@ -172,22 +296,67 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
var existingItemsWithNoCondition =
FindExistingItemsWithNoCondition(item, destinationItemGroup.ContainingProject, destinationItemGroup);
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorMergingItemWithExistingItems, nameof(ItemTransformApplicator), existingItemsWithNoCondition.Count()));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorMergingItemWithExistingItems,
nameof(ItemTransformApplicator),
existingItemsWithNoCondition.Count()));
// Handle the item being placed inside of a condition, when it is overlapping with a conditionless item
// If it is not definining new metadata or excludes, the conditioned item can be merged with the
// conditionless item
foreach (var existingItem in existingItemsWithNoCondition)
if (!string.IsNullOrEmpty(item.Include))
{
var encompassedIncludes = existingItem.GetEncompassedIncludes(item, MigrationTrace.Instance);
if (encompassedIncludes.Any())
// Handle the item being placed inside of a condition, when it is overlapping with a conditionless item
// If it is not definining new metadata or excludes, the conditioned item can be merged with the
// conditionless item
foreach (var existingItem in existingItemsWithNoCondition)
{
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorEncompassedIncludes, nameof(ItemTransformApplicator), string.Join(", ", encompassedIncludes)));
item.RemoveIncludes(encompassedIncludes);
if (!item.Includes().Any())
var encompassedIncludes = existingItem.GetEncompassedIncludes(item, MigrationTrace.Instance);
if (encompassedIncludes.Any())
{
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorIgnoringItem, nameof(ItemTransformApplicator), existingItem.ItemType, existingItem.Condition, existingItem.Include, existingItem.Exclude));
return null;
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorEncompassedIncludes,
nameof(ItemTransformApplicator),
string.Join(", ", encompassedIncludes)));
item.RemoveIncludes(encompassedIncludes);
if (!item.Includes().Any())
{
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorIgnoringItem,
nameof(ItemTransformApplicator),
existingItem.ItemType,
existingItem.Condition,
existingItem.Include,
existingItem.Exclude));
return null;
}
}
}
}
if (!string.IsNullOrEmpty(item.Update))
{
// Handle the item being placed inside of a condition, when it is overlapping with a conditionless item
// If it is not definining new metadata or excludes, the conditioned item can be merged with the
// conditionless item
foreach (var existingItem in existingItemsWithNoCondition)
{
var encompassedUpdates = existingItem.GetEncompassedUpdates(item, MigrationTrace.Instance);
if (encompassedUpdates.Any())
{
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorEncompassedUpdates,
nameof(ItemTransformApplicator),
string.Join(", ", encompassedUpdates)));
item.RemoveUpdates(encompassedUpdates);
if (!item.Updates().Any())
{
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorIgnoringItem,
nameof(ItemTransformApplicator),
existingItem.ItemType,
existingItem.Condition,
existingItem.Update,
existingItem.Exclude));
return null;
}
}
}
}
@ -200,18 +369,20 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
var existingRemoveItem = destinationItemGroup.Items
.Where(i =>
string.IsNullOrEmpty(i.Include)
&& string.IsNullOrEmpty(i.Update)
&& string.IsNullOrEmpty(i.Exclude)
&& !string.IsNullOrEmpty(i.Remove))
.FirstOrDefault();
var itemsToRemove = string.IsNullOrEmpty(item.Include) ? item.Update : item.Include;
if (existingRemoveItem != null)
{
existingRemoveItem.Remove += ";" + item.Include;
existingRemoveItem.Remove += ";" + itemsToRemove;
}
else
{
var clearPreviousItem = _projectElementGenerator.CreateItemElement(item.ItemType);
clearPreviousItem.Remove = item.Include;
clearPreviousItem.Remove = itemsToRemove;
AddItemToItemGroup(clearPreviousItem, destinationItemGroup);
}
@ -220,12 +391,19 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
return item;
}
private ProjectItemElement MergeWithExistingItemsWithSameCondition(ProjectItemElement item, ProjectItemGroupElement destinationItemGroup)
private ProjectItemElement MergeWithExistingItemsWithSameCondition(
ProjectItemElement item,
ProjectItemGroupElement destinationItemGroup)
{
var existingItemsWithSameCondition =
FindExistingItemsWithSameCondition(item, destinationItemGroup.ContainingProject, destinationItemGroup);
var existingItemsWithSameCondition = FindExistingItemsWithSameCondition(
item,
destinationItemGroup.ContainingProject,
destinationItemGroup);
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorMergingItemWithExistingItemsSameChain, nameof(TransformApplicator), existingItemsWithSameCondition.Count()));
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorMergingItemWithExistingItemsSameChain,
nameof(TransformApplicator),
existingItemsWithSameCondition.Count()));
foreach (var existingItem in existingItemsWithSameCondition)
{
@ -238,7 +416,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
existingItem.Parent.RemoveChild(existingItem);
}
MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.ItemTransformApplicatorAddingMergedItem,
MigrationTrace.Instance.WriteLine(String.Format(
LocalizableStrings.ItemTransformApplicatorAddingMergedItem,
nameof(TransformApplicator),
mergeResult.MergedItem.ItemType,
mergeResult.MergedItem.Condition,
@ -250,6 +429,21 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
return item;
}
private MergeResult MergeItems(ProjectItemElement item, ProjectItemElement existingItem)
{
if (!string.IsNullOrEmpty(item.Include))
{
return MergeItemsOnIncludes(item, existingItem);
}
if (!string.IsNullOrEmpty(item.Update))
{
return MergeItemsOnUpdates(item, existingItem);
}
throw new InvalidOperationException(LocalizableStrings.CannotMergeItemsWithoutCommonIncludeError);
}
/// <summary>
/// Merges two items on their common sets of includes.
/// The output is 3 items, the 2 input items and the merged items. If the common
@ -262,18 +456,13 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
///
/// This function will mutate the Include property of the 2 input items, removing the common subset.
/// </summary>
private MergeResult MergeItems(ProjectItemElement item, ProjectItemElement existingItem)
private MergeResult MergeItemsOnIncludes(ProjectItemElement item, ProjectItemElement existingItem)
{
if (!string.Equals(item.ItemType, existingItem.ItemType, StringComparison.Ordinal))
{
throw new InvalidOperationException(LocalizableStrings.CannotMergeItemsOfDifferentTypesError);
}
if (!item.IntersectIncludes(existingItem).Any())
{
throw new InvalidOperationException(LocalizableStrings.CannotMergeItemsWithoutCommonIncludeError);
}
var commonIncludes = item.IntersectIncludes(existingItem).ToList();
var mergedItem = _projectElementGenerator.AddItem(item.ItemType, string.Join(";", commonIncludes));
@ -295,6 +484,36 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
return mergeResult;
}
private MergeResult MergeItemsOnUpdates(ProjectItemElement item, ProjectItemElement existingItem)
{
if (!string.Equals(item.ItemType, existingItem.ItemType, StringComparison.Ordinal))
{
throw new InvalidOperationException(LocalizableStrings.CannotMergeItemsOfDifferentTypesError);
}
var commonUpdates = item.IntersectUpdates(existingItem).ToList();
var mergedItem = _projectElementGenerator.AddItem(item.ItemType, "placeholder");
mergedItem.Include = string.Empty;
mergedItem.Update = string.Join(";", commonUpdates);
mergedItem.UnionExcludes(existingItem.Excludes());
mergedItem.UnionExcludes(item.Excludes());
mergedItem.AddMetadata(MergeMetadata(existingItem.Metadata, item.Metadata), MigrationTrace.Instance);
item.RemoveUpdates(commonUpdates);
existingItem.RemoveUpdates(commonUpdates);
var mergeResult = new MergeResult
{
InputItem = string.IsNullOrEmpty(item.Update) ? null : item,
ExistingItem = string.IsNullOrEmpty(existingItem.Update) ? null : existingItem,
MergedItem = mergedItem
};
return mergeResult;
}
private ICollection<ProjectMetadataElement> MergeMetadata(
ICollection<ProjectMetadataElement> existingMetadataElements,
ICollection<ProjectMetadataElement> newMetadataElements)
@ -335,7 +554,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
.Where(i => i.Condition == item.Condition)
.Where(i => i.Parent.ConditionChainsAreEquivalent(destinationContainer))
.Where(i => i.ItemType == item.ItemType)
.Where(i => i.IntersectIncludes(item).Any());
.Where(i => i.IntersectIncludes(item).Any() ||
i.IntersectUpdates(item).Any());
}
private IEnumerable<ProjectItemElement> FindExistingItemsWithNoCondition(
@ -346,7 +566,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
return project.Items
.Where(i => !i.ConditionChain().Any())
.Where(i => i.ItemType == item.ItemType)
.Where(i => i.IntersectIncludes(item).Any());
.Where(i => i.IntersectIncludes(item).Any() ||
i.IntersectUpdates(item).Any());
}
private IEnumerable<ProjectItemElement> FindExistingItemsWithACondition(
@ -357,7 +578,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Transforms
return project.Items
.Where(i => i.ConditionChain().Any())
.Where(i => i.ItemType == item.ItemType)
.Where(i => i.IntersectIncludes(item).Any());
.Where(i => i.IntersectIncludes(item).Any() ||
i.IntersectUpdates(item).Any());
}
private class MergeResult

View file

@ -189,7 +189,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
}",
testDirectory: testDirectory);
mockProj.Items.Count(i => i.ItemType.Equals("Content", StringComparison.Ordinal)).Should().Be(4);
mockProj.Items.Count(i => i.ItemType.Equals("Content", StringComparison.Ordinal)).Should().Be(3);
// From ProjectReader #L725 (Both are empty)
var defaultIncludePatterns = Enumerable.Empty<string>();
@ -198,11 +198,10 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests
foreach (var item in mockProj.Items.Where(i => i.ItemType.Equals("Content", StringComparison.Ordinal)))
{
var metadata = string.Join(",", item.Metadata.Select(m => m.Name));
Console.WriteLine($"LICAVALC: Update: {item.Update}, Include: {item.Include}, Metadata: {metadata}");
if (item.Update.Contains(@"root\**\*"))
{
item.Update.Should().Be(@"root\**\*;src\**\*;rootfile.cs");
item.Update.Should().Be(@"root\**\*");
item.Exclude.Should().BeEmpty();
}
else if (item.Update.Contains(@"src\file1.cs"))