Adding merging of ProjectItemElement.Update. Before, we only merged Include.
This commit is contained in:
parent
55d5d98332
commit
3bbfcb428b
4 changed files with 346 additions and 87 deletions
|
@ -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} }}";
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
|
|
Loading…
Reference in a new issue