Skip to content

Merge release/2.1.4xx to master #2276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9239596
Add test coverage for .NET 4.7.2 and conflict resolution with HttpClient
dsplaisted May 16, 2018
da73802
Add references to platform assemblies that win compile conflict resol…
dsplaisted May 16, 2018
722c34d
Add extra validation to .NET 4.7.1 tests
dsplaisted May 18, 2018
dbcfab9
Test multiple versions of Http package with .NET 4.7.2
dsplaisted May 18, 2018
0315a9f
Don't create duplicate framework assembly references from different N…
dsplaisted May 18, 2018
206af50
When updating NuGet references to use a simple name for the ItemSpec,…
dsplaisted May 18, 2018
86b5e05
In conflict resolution, handle case where two items tie but both lose…
dsplaisted May 18, 2018
1c08228
Apply PR feedback
dsplaisted May 18, 2018
bccb677
Code review feedback
dsplaisted May 19, 2018
babcaba
Fix conflict resolver issues
dsplaisted May 23, 2018
dc7a6ba
Disable tests requiring .NET 4.7.2 if the corresponding reference ass…
dsplaisted May 24, 2018
aa23fe1
Update tests to account for change to test hook
dsplaisted May 24, 2018
7823f3f
Always assume required reference assemblies are installed (when on Wi…
dsplaisted May 24, 2018
14a2b91
Putting back the 'perf' property switch: "/p:PerformanceTest=$perf"
May 24, 2018
4908e1f
Merge pull request #2273 from johnbeisner/FixPerformance
johnbeisner May 24, 2018
07aec81
Apply code review feedback
dsplaisted May 24, 2018
b6fdd49
Merge pull request #2274 from dotnet/merges/release/2.1.3xx-to-releas…
johnbeisner May 24, 2018
3d3da88
Merge pull request #2250 from dsplaisted/2221-platform-references-and…
dsplaisted May 24, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ function LocateVisualStudio {
}

function Build {
& $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
& $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

if ($lastExitCode -ne 0) {
throw "Failed to build (exit code '$lastExitCode'). See log: $BuildLog"
Expand Down
2 changes: 1 addition & 1 deletion build/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ function InstallDotNetSharedFramework {
function Build {
"$build_driver" msbuild $toolset_build_proj /m /nologo /clp:Summary /warnaserror \
/v:$verbosity /bl:$build_log /p:Configuration=$configuration /p:Projects=$projects /p:RepoRoot="$repo_root" \
/p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Deploy=$deploy /p:Test=$test /p:Sign=$sign /p:Pack=$pack /p:CIBuild=$ci \
/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
local lastexitcode=$?

Expand Down
156 changes: 113 additions & 43 deletions src/Tasks/Common/ConflictResolution/ConflictResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,33 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

namespace Microsoft.NET.Build.Tasks.ConflictResolution
{
internal delegate void ConflictCallback<T>(T winner, T loser);

// The conflict resolver finds conflicting items, and if there are any of them it reports the "losing" item via the foundConflict callback
internal class ConflictResolver<TConflictItem> where TConflictItem : class, IConflictItem
internal class ConflictResolver<TConflictItem> : IDisposable where TConflictItem : class, IConflictItem
{
private Dictionary<string, TConflictItem> winningItemsByKey = new Dictionary<string, TConflictItem>();
private ILog log;
private PackageRank packageRank;
private PackageOverrideResolver<TConflictItem> packageOverrideResolver;
private Dictionary<string, TConflictItem> _winningItemsByKey = new Dictionary<string, TConflictItem>();
private ILog _log;
private PackageRank _packageRank;
private PackageOverrideResolver<TConflictItem> _packageOverrideResolver;
private Dictionary<string, List<TConflictItem>> _unresolvedConflictItems = new Dictionary<string, List<TConflictItem>>(StringComparer.Ordinal);

// Callback for unresolved conflicts, currently just used as a test hook
public Action<TConflictItem> UnresolvedConflictHandler { get; set; }

public ConflictResolver(PackageRank packageRank, PackageOverrideResolver<TConflictItem> packageOverrideResolver, ILog log)
{
this.log = log;
this.packageRank = packageRank;
this.packageOverrideResolver = packageOverrideResolver;
this._log = log;
this._packageRank = packageRank;
this._packageOverrideResolver = packageOverrideResolver;
}

public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TConflictItem, string> getItemKey,
Action<TConflictItem> foundConflict, bool commitWinner = true,
Action<TConflictItem> unresolvedConflict = null)
ConflictCallback<TConflictItem> foundConflict, bool commitWinner = true)
{
if (conflictItems == null)
{
Expand All @@ -44,18 +50,31 @@ public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TCon

TConflictItem existingItem;

if (winningItemsByKey.TryGetValue(itemKey, out existingItem))
if (_winningItemsByKey.TryGetValue(itemKey, out existingItem))
{
// a conflict was found, determine the winner.
var winner = ResolveConflict(existingItem, conflictItem);
var winner = ResolveConflict(existingItem, conflictItem, logUnresolvedConflicts: false);

if (winner == null)
{
// no winner, skip it.
// don't add to conflict list and just use the existing item for future conflicts.
// 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;

// Report unresolved conflict (currently just used as a test hook)
unresolvedConflict?.Invoke(conflictItem);
// 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;
}
Expand All @@ -66,30 +85,69 @@ public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TCon
// replace existing item
if (commitWinner)
{
winningItemsByKey[itemKey] = conflictItem;
_winningItemsByKey[itemKey] = conflictItem;
}
else
{
winningItemsByKey.Remove(itemKey);
_winningItemsByKey.Remove(itemKey);
}
loser = existingItem;

}

foundConflict(loser);
foundConflict(winner, loser);

// If there were any other items that tied with the loser, report them as conflicts here
List<TConflictItem> previouslyUnresolvedConflicts;
if (_unresolvedConflictItems.TryGetValue(itemKey, out previouslyUnresolvedConflicts))
{
// Skip the first item in the list of items that had unresolved conflicts, as it should
// be the same as the losing item which was just reported.
foreach (var previouslyUnresolvedItem in previouslyUnresolvedConflicts.Skip(1))
{
// Call ResolveConflict with the new winner and item that previously had an unresolved
// conflict, so that the correct message will be logged recording that the winner
// won and why
ResolveConflict(winner, previouslyUnresolvedItem, logUnresolvedConflicts: true);

foundConflict(winner, previouslyUnresolvedItem);
}
_unresolvedConflictItems.Remove(itemKey);
}
}
else if (commitWinner)
{
winningItemsByKey[itemKey] = conflictItem;
_winningItemsByKey[itemKey] = conflictItem;
}
}
}

public void Dispose()
{
// Report unresolved conflict items that didn't end up losing subsequently
foreach (var itemKey in _unresolvedConflictItems.Keys)
{
// Report the first item as an unresolved conflict
var firstItem = _unresolvedConflictItems[itemKey][0];
UnresolvedConflictHandler?.Invoke(firstItem);

// For subsequent items, report them as unresolved conflicts, and log a message
// that they were an unresolved conflict with the first item
foreach (var unresolvedConflictItem in _unresolvedConflictItems[itemKey].Skip(1))
{
UnresolvedConflictHandler?.Invoke(unresolvedConflictItem);

// Call ResolveConflict to generate the right log message about the unresolved conflict
ResolveConflict(firstItem, unresolvedConflictItem, logUnresolvedConflicts: true);
}

}
}

readonly string SENTENCE_SPACING = " ";

private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2, bool logUnresolvedConflicts)
{
var winner = packageOverrideResolver.Resolve(item1, item2);
var winner = _packageOverrideResolver.Resolve(item1, item2);
if (winner != null)
{
return winner;
Expand All @@ -111,10 +169,13 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)

if (!exists1 || !exists2)
{
string fileMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_DoesntExist,
!exists1 ? item1.DisplayName : item2.DisplayName);
if (logUnresolvedConflicts)
{
string fileMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_DoesntExist,
!exists1 ? item1.DisplayName : item2.DisplayName);

log.LogMessage(fileMessage);
_log.LogMessage(fileMessage);
}
return null;
}

Expand All @@ -124,11 +185,14 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
// if only one is missing version stop: something is wrong when we have a conflict between assembly and non-assembly
if (assemblyVersion1 == null ^ assemblyVersion2 == null)
{
var nonAssembly = assemblyVersion1 == null ? item1.DisplayName : item2.DisplayName;
string assemblyMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_NotAnAssembly,
nonAssembly);

log.LogMessage(assemblyMessage);
if (logUnresolvedConflicts)
{
var nonAssembly = assemblyVersion1 == null ? item1.DisplayName : item2.DisplayName;
string assemblyMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_NotAnAssembly,
nonAssembly);

_log.LogMessage(assemblyMessage);
}
return null;
}

Expand Down Expand Up @@ -157,7 +221,7 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
winningVersion,
losingVersion);

log.LogMessage(assemblyMessage);
_log.LogMessage(assemblyMessage);

if (assemblyVersion1 > assemblyVersion2)
{
Expand All @@ -176,9 +240,12 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
// if only one is missing version
if (fileVersion1 == null ^ fileVersion2 == null)
{
var nonVersion = fileVersion1 == null ? item1.DisplayName : item2.DisplayName;
string fileVersionMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_FileVersion,
nonVersion);
if (logUnresolvedConflicts)
{
var nonVersion = fileVersion1 == null ? item1.DisplayName : item2.DisplayName;
string fileVersionMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.CouldNotDetermineWinner_FileVersion,
nonVersion);
}
return null;
}

Expand Down Expand Up @@ -206,7 +273,7 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
winningVersion,
losingVersion);

log.LogMessage(fileVersionMessage);
_log.LogMessage(fileVersionMessage);

if (fileVersion1 > fileVersion2)
{
Expand All @@ -219,14 +286,14 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
}
}

var packageRank1 = packageRank.GetPackageRank(item1.PackageId);
var packageRank2 = packageRank.GetPackageRank(item2.PackageId);
var packageRank1 = _packageRank.GetPackageRank(item1.PackageId);
var packageRank2 = _packageRank.GetPackageRank(item2.PackageId);

if (packageRank1 < packageRank2)
{
string packageRankMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ChoosingPreferredPackage,
item1.DisplayName);
log.LogMessage(packageRankMessage);
_log.LogMessage(packageRankMessage);
return item1;
}

Expand All @@ -244,21 +311,24 @@ private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
{
string platformMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ChoosingPlatformItem,
item1.DisplayName);
log.LogMessage(platformMessage);
_log.LogMessage(platformMessage);
return item1;
}

if (!isPlatform1 && isPlatform2)
{
string platformMessage = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ChoosingPlatformItem,
item2.DisplayName);
log.LogMessage(platformMessage);
_log.LogMessage(platformMessage);
return item2;
}

string message = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ConflictCouldNotDetermineWinner);
if (logUnresolvedConflicts)
{
string message = conflictMessage + SENTENCE_SPACING + string.Format(CultureInfo.CurrentCulture, Strings.ConflictCouldNotDetermineWinner);

log.LogMessage(message);
_log.LogMessage(message);
}
return null;
}
}
Expand Down
Loading