in src/Tasks/Common/ConflictResolution/ConflictResolver.cs [34:148]
public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TConflictItem, string> getItemKey,
ConflictCallback<TConflictItem> foundConflict, bool commitWinner = true)
{
if (conflictItems == null)
{
return;
}
foreach (var conflictItem in conflictItems)
{
var itemKey = getItemKey(conflictItem);
if (String.IsNullOrEmpty(itemKey))
{
continue;
}
TConflictItem existingItem;
if (_winningItemsByKey.TryGetValue(itemKey, out existingItem))
{
// a conflict was found, determine the winner.
var winner = ResolveConflict(existingItem, conflictItem, logUnresolvedConflicts: false);
if (winner == null)
{
// No winner. Keep track of the conflictItem, so that if a subsequent
// item wins for this key, both items (for which there was no winner when
// compared to each other) can be counted as conflicts and removed from
// the corresponding list.
List<TConflictItem> unresolvedConflictsForKey;
if (!_unresolvedConflictItems.TryGetValue(itemKey, out unresolvedConflictsForKey))
{
unresolvedConflictsForKey = new List<TConflictItem>();
_unresolvedConflictItems[itemKey] = unresolvedConflictsForKey;
// This is the first time we hit an unresolved conflict for this key, so
// add the existing item to the unresolved conflicts list
unresolvedConflictsForKey.Add(existingItem);
}
// Add the new item to the unresolved conflicts list
unresolvedConflictsForKey.Add(conflictItem);
continue;
}
TConflictItem loser = conflictItem;
if (!ReferenceEquals(winner, existingItem))
{
// replace existing item
if (commitWinner)
{
_winningItemsByKey[itemKey] = conflictItem;
}
else
{
_winningItemsByKey.Remove(itemKey);
}
loser = existingItem;
}
foundConflict(winner, loser);
// If there were any other items that tied with the loser, report them as conflicts here
// if they lose against the new winner. Otherwise, keep them in the unresolved conflict
// list.
List<TConflictItem> previouslyUnresolvedConflicts;
if(_unresolvedConflictItems.TryGetValue(itemKey, out previouslyUnresolvedConflicts) &&
previouslyUnresolvedConflicts.Contains(loser))
{
List<TConflictItem> newUnresolvedConflicts = new List<TConflictItem>();
foreach (var previouslyUnresolvedItem in previouslyUnresolvedConflicts)
{
// Don't re-report the item that just lost and was already reported
if (object.ReferenceEquals(previouslyUnresolvedItem, loser))
{
continue;
}
// Call ResolveConflict with the new winner and item that previously had an unresolved
// conflict, so that if the previously unresolved conflict loses, the correct message
// will be logged recording that the winner won and why. If the conflict can't be
// resolved, then keep the previously unresolved conflict in the list of unresolved
// conflicts.
var newWinner = ResolveConflict(winner, previouslyUnresolvedItem, logUnresolvedConflicts: true);
if (newWinner == winner)
{
foundConflict(winner, previouslyUnresolvedItem);
}
else if (newWinner == null)
{
if (newUnresolvedConflicts.Count == 0)
{
newUnresolvedConflicts.Add(winner);
}
newUnresolvedConflicts.Add(previouslyUnresolvedItem);
}
}
_unresolvedConflictItems.Remove(itemKey);
if (newUnresolvedConflicts.Count > 0)
{
_unresolvedConflictItems[itemKey] = newUnresolvedConflicts;
}
}
}
else if (commitWinner)
{
_winningItemsByKey[itemKey] = conflictItem;
}
}
}