Skip to content

Commit d6ad245

Browse files
authored
Merge pull request #2276 from dotnet/merges/release/2.1.4xx-to-master
Merge release/2.1.4xx to master
2 parents b4a1f24 + 3d3da88 commit d6ad245

File tree

10 files changed

+353
-165
lines changed

10 files changed

+353
-165
lines changed

build/build.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ function LocateVisualStudio {
251251
}
252252

253253
function Build {
254-
& $BuildDriver $BuildArgs $ToolsetBuildProj /m /nologo /clp:Summary /warnaserror /v:$verbosity /bl:$BuildLog /p:Configuration=$configuration /p:Projects=$solution /p:RepoRoot=$RepoRoot /p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci $properties
254+
& $BuildDriver $BuildArgs $ToolsetBuildProj /m /nologo /clp:Summary /warnaserror /v:$verbosity /bl:$BuildLog /p:Configuration=$configuration /p:Projects=$solution /p:RepoRoot=$RepoRoot /p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:PerformanceTest=$perf /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci $properties
255255

256256
if ($lastExitCode -ne 0) {
257257
throw "Failed to build (exit code '$lastExitCode'). See log: $BuildLog"

build/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ function InstallDotNetSharedFramework {
304304
function Build {
305305
"$build_driver" msbuild $toolset_build_proj /m /nologo /clp:Summary /warnaserror \
306306
/v:$verbosity /bl:$build_log /p:Configuration=$configuration /p:Projects=$projects /p:RepoRoot="$repo_root" \
307-
/p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci \
307+
/p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:PerformanceTest=$perf /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci \
308308
$properties
309309
local lastexitcode=$?
310310

src/Tasks/Common/ConflictResolution/ConflictResolver.cs

Lines changed: 113 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,33 @@
66
using System;
77
using System.Collections.Generic;
88
using System.Globalization;
9+
using System.Linq;
910

1011
namespace Microsoft.NET.Build.Tasks.ConflictResolution
1112
{
13+
internal delegate void ConflictCallback<T>(T winner, T loser);
14+
1215
// The conflict resolver finds conflicting items, and if there are any of them it reports the "losing" item via the foundConflict callback
13-
internal class ConflictResolver<TConflictItem> where TConflictItem : class, IConflictItem
16+
internal class ConflictResolver<TConflictItem> : IDisposable where TConflictItem : class, IConflictItem
1417
{
15-
private Dictionary<string, TConflictItem> winningItemsByKey = new Dictionary<string, TConflictItem>();
16-
private ILog log;
17-
private PackageRank packageRank;
18-
private PackageOverrideResolver<TConflictItem> packageOverrideResolver;
18+
private Dictionary<string, TConflictItem> _winningItemsByKey = new Dictionary<string, TConflictItem>();
19+
private ILog _log;
20+
private PackageRank _packageRank;
21+
private PackageOverrideResolver<TConflictItem> _packageOverrideResolver;
22+
private Dictionary<string, List<TConflictItem>> _unresolvedConflictItems = new Dictionary<string, List<TConflictItem>>(StringComparer.Ordinal);
23+
24+
// Callback for unresolved conflicts, currently just used as a test hook
25+
public Action<TConflictItem> UnresolvedConflictHandler { get; set; }
1926

2027
public ConflictResolver(PackageRank packageRank, PackageOverrideResolver<TConflictItem> packageOverrideResolver, ILog log)
2128
{
22-
this.log = log;
23-
this.packageRank = packageRank;
24-
this.packageOverrideResolver = packageOverrideResolver;
29+
this._log = log;
30+
this._packageRank = packageRank;
31+
this._packageOverrideResolver = packageOverrideResolver;
2532
}
2633

2734
public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TConflictItem, string> getItemKey,
28-
Action<TConflictItem> foundConflict, bool commitWinner = true,
29-
Action<TConflictItem> unresolvedConflict = null)
35+
ConflictCallback<TConflictItem> foundConflict, bool commitWinner = true)
3036
{
3137
if (conflictItems == null)
3238
{
@@ -44,18 +50,31 @@ public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TCon
4450

4551
TConflictItem existingItem;
4652

47-
if (winningItemsByKey.TryGetValue(itemKey, out existingItem))
53+
if (_winningItemsByKey.TryGetValue(itemKey, out existingItem))
4854
{
4955
// a conflict was found, determine the winner.
50-
var winner = ResolveConflict(existingItem, conflictItem);
56+
var winner = ResolveConflict(existingItem, conflictItem, logUnresolvedConflicts: false);
5157

5258
if (winner == null)
5359
{
54-
// no winner, skip it.
55-
// don't add to conflict list and just use the existing item for future conflicts.
60+
// No winner. Keep track of the conflictItem, so that if a subsequent
61+
// item wins for this key, both items (for which there was no winner when
62+
// compared to each other) can be counted as conflicts and removed from
63+
// the corresponding list.
64+
65+
List<TConflictItem> unresolvedConflictsForKey;
66+
if (!_unresolvedConflictItems.TryGetValue(itemKey, out unresolvedConflictsForKey))
67+
{
68+
unresolvedConflictsForKey = new List<TConflictItem>();
69+
_unresolvedConflictItems[itemKey] = unresolvedConflictsForKey;
5670

57-
// Report unresolved conflict (currently just used as a test hook)
58-
unresolvedConflict?.Invoke(conflictItem);
71+
// This is the first time we hit an unresolved conflict for this key, so
72+
// add the existing item to the unresolved conflicts list
73+
unresolvedConflictsForKey.Add(existingItem);
74+
}
75+
76+
// Add the new item to the unresolved conflicts list
77+
unresolvedConflictsForKey.Add(conflictItem);
5978

6079
continue;
6180
}
@@ -66,30 +85,69 @@ public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TCon
6685
// replace existing item
6786
if (commitWinner)
6887
{
69-
winningItemsByKey[itemKey] = conflictItem;
88+
_winningItemsByKey[itemKey] = conflictItem;
7089
}
7190
else
7291
{
73-
winningItemsByKey.Remove(itemKey);
92+
_winningItemsByKey.Remove(itemKey);
7493
}
7594
loser = existingItem;
76-
7795
}
7896

79-
foundConflict(loser);
97+
foundConflict(winner, loser);
98+
99+
// If there were any other items that tied with the loser, report them as conflicts here
100+
List<TConflictItem> previouslyUnresolvedConflicts;
101+
if (_unresolvedConflictItems.TryGetValue(itemKey, out previouslyUnresolvedConflicts))
102+
{
103+
// Skip the first item in the list of items that had unresolved conflicts, as it should
104+
// be the same as the losing item which was just reported.
105+
foreach (var previouslyUnresolvedItem in previouslyUnresolvedConflicts.Skip(1))
106+
{
107+
// Call ResolveConflict with the new winner and item that previously had an unresolved
108+
// conflict, so that the correct message will be logged recording that the winner
109+
// won and why
110+
ResolveConflict(winner, previouslyUnresolvedItem, logUnresolvedConflicts: true);
111+
112+
foundConflict(winner, previouslyUnresolvedItem);
113+
}
114+
_unresolvedConflictItems.Remove(itemKey);
115+
}
80116
}
81117
else if (commitWinner)
82118
{
83-
winningItemsByKey[itemKey] = conflictItem;
119+
_winningItemsByKey[itemKey] = conflictItem;
120+
}
121+
}
122+
}
123+
124+
public void Dispose()
125+
{
126+
// Report unresolved conflict items that didn't end up losing subsequently
127+
foreach (var itemKey in _unresolvedConflictItems.Keys)
128+
{
129+
// Report the first item as an unresolved conflict
130+
var firstItem = _unresolvedConflictItems[itemKey][0];
131+
UnresolvedConflictHandler?.Invoke(firstItem);
132+
133+
// For subsequent items, report them as unresolved conflicts, and log a message
134+
// that they were an unresolved conflict with the first item
135+
foreach (var unresolvedConflictItem in _unresolvedConflictItems[itemKey].Skip(1))
136+
{
137+
UnresolvedConflictHandler?.Invoke(unresolvedConflictItem);
138+
139+
// Call ResolveConflict to generate the right log message about the unresolved conflict
140+
ResolveConflict(firstItem, unresolvedConflictItem, logUnresolvedConflicts: true);
84141
}
142+
85143
}
86144
}
87145

88146
readonly string SENTENCE_SPACING = " ";
89147

90-
private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
148+
private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2, bool logUnresolvedConflicts)
91149
{
92-
var winner = packageOverrideResolver.Resolve(item1, item2);
150+
var winner = _packageOverrideResolver.Resolve(item1, item2);
93151
if (winner != null)
94152
{
95153
return winner;
@@ -111,10 +169,13 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
111169

112170
if (!exists1 || !exists2)
113171
{
114-
string fileMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_DoesntExist,
115-
!exists1 ? item1.DisplayName : item2.DisplayName);
172+
if (logUnresolvedConflicts)
173+
{
174+
string fileMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_DoesntExist,
175+
!exists1 ? item1.DisplayName : item2.DisplayName);
116176

117-
log.LogMessage(fileMessage);
177+
_log.LogMessage(fileMessage);
178+
}
118179
return null;
119180
}
120181

@@ -124,11 +185,14 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
124185
// if only one is missing version stop: something is wrong when we have a conflict between assembly and non-assembly
125186
if (assemblyVersion1 == null ^ assemblyVersion2 == null)
126187
{
127-
var nonAssembly = assemblyVersion1 == null ? item1.DisplayName : item2.DisplayName;
128-
string assemblyMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_NotAnAssembly,
129-
nonAssembly);
130-
131-
log.LogMessage(assemblyMessage);
188+
if (logUnresolvedConflicts)
189+
{
190+
var nonAssembly = assemblyVersion1 == null ? item1.DisplayName : item2.DisplayName;
191+
string assemblyMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_NotAnAssembly,
192+
nonAssembly);
193+
194+
_log.LogMessage(assemblyMessage);
195+
}
132196
return null;
133197
}
134198

@@ -157,7 +221,7 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
157221
winningVersion,
158222
losingVersion);
159223

160-
log.LogMessage(assemblyMessage);
224+
_log.LogMessage(assemblyMessage);
161225

162226
if (assemblyVersion1 > assemblyVersion2)
163227
{
@@ -176,9 +240,12 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
176240
// if only one is missing version
177241
if (fileVersion1 == null ^ fileVersion2 == null)
178242
{
179-
var nonVersion = fileVersion1 == null ? item1.DisplayName : item2.DisplayName;
180-
string fileVersionMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_FileVersion,
181-
nonVersion);
243+
if (logUnresolvedConflicts)
244+
{
245+
var nonVersion = fileVersion1 == null ? item1.DisplayName : item2.DisplayName;
246+
string fileVersionMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_FileVersion,
247+
nonVersion);
248+
}
182249
return null;
183250
}
184251

@@ -206,7 +273,7 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
206273
winningVersion,
207274
losingVersion);
208275

209-
log.LogMessage(fileVersionMessage);
276+
_log.LogMessage(fileVersionMessage);
210277

211278
if (fileVersion1 > fileVersion2)
212279
{
@@ -219,14 +286,14 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
219286
}
220287
}
221288

222-
var packageRank1 = packageRank.GetPackageRank(item1.PackageId);
223-
var packageRank2 = packageRank.GetPackageRank(item2.PackageId);
289+
var packageRank1 = _packageRank.GetPackageRank(item1.PackageId);
290+
var packageRank2 = _packageRank.GetPackageRank(item2.PackageId);
224291

225292
if (packageRank1 < packageRank2)
226293
{
227294
string packageRankMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ChoosingPreferredPackage,
228295
item1.DisplayName);
229-
log.LogMessage(packageRankMessage);
296+
_log.LogMessage(packageRankMessage);
230297
return item1;
231298
}
232299

@@ -244,21 +311,24 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
244311
{
245312
string platformMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ChoosingPlatformItem,
246313
item1.DisplayName);
247-
log.LogMessage(platformMessage);
314+
_log.LogMessage(platformMessage);
248315
return item1;
249316
}
250317

251318
if (!isPlatform1 && isPlatform2)
252319
{
253320
string platformMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ChoosingPlatformItem,
254321
item2.DisplayName);
255-
log.LogMessage(platformMessage);
322+
_log.LogMessage(platformMessage);
256323
return item2;
257324
}
258325

259-
string message = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ConflictCouldNotDetermineWinner);
326+
if (logUnresolvedConflicts)
327+
{
328+
string message = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ConflictCouldNotDetermineWinner);
260329

261-
log.LogMessage(message);
330+
_log.LogMessage(message);
331+
}
262332
return null;
263333
}
264334
}

0 commit comments

Comments
 (0)