From dd07581fe33a2eb6857cd4afff216785a1a741fe Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 4 Dec 2017 21:16:45 -0600 Subject: [PATCH 1/6] Speed up ResolvePackageFileConflicts by avoiding reading files for AssemblyVersion. Allow for packages to override other packages by default. --- .../Common/ConflictResolution/ConflictItem.cs | 33 ++- .../ConflictResolution/ConflictResolver.cs | 10 +- .../ConflictResolution/MetadataNames.cs | 1 + .../ResolvePackageFileConflicts.cs | 18 +- ...ET.DefaultPackageConflictOverrides.targets | 233 +++++++++++++++++ .../src/ConflictResolution/PackageOverride.cs | 64 +++++ .../PackageOverrideResolver.cs | 89 +++++++ ...icrosoft.NET.Build.Extensions.Tasks.csproj | 3 + ...uild.Extensions.ConflictResolution.targets | 3 + .../GivenAConflictResolver.cs | 7 +- .../Microsoft.NET.Build.Tasks.csproj | 5 +- .../Microsoft.NET.ConflictResolution.targets | 234 +++++++++++++++++- 12 files changed, 684 insertions(+), 16 deletions(-) create mode 100644 src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets create mode 100644 src/Tasks/Common/src/ConflictResolution/PackageOverride.cs create mode 100644 src/Tasks/Common/src/ConflictResolution/PackageOverrideResolver.cs diff --git a/src/Tasks/Common/ConflictResolution/ConflictItem.cs b/src/Tasks/Common/ConflictResolution/ConflictItem.cs index 0484c7aaa411..e2488a5be9e5 100644 --- a/src/Tasks/Common/ConflictResolution/ConflictItem.cs +++ b/src/Tasks/Common/ConflictResolution/ConflictItem.cs @@ -24,6 +24,11 @@ internal interface IConflictItem Version FileVersion { get; } string PackageId { get; } string DisplayName { get; } + + // NOTE: Technically this should be NuGetVersion because System.Version doesn't work with symver. + // However, the only scenarios we need to support this property for in conflict resolution is stable versions + // of System packages. PackageVersion will be null if System.Version can't parse the version (i.e. if is pre-release) + Version PackageVersion { get; } } // Wraps an ITask item and adds lazy evaluated properties used by Conflict resolution. @@ -103,7 +108,7 @@ public string FileName { if (_fileName == null) { - _fileName = OriginalItem == null ? String.Empty : OriginalItem.GetMetadata(MetadataNames.FileName) + OriginalItem.GetMetadata(MetadataNames.Extension); + _fileName = OriginalItem == null ? String.Empty : Path.GetFileName(OriginalItem.ItemSpec); } return _fileName; } @@ -165,7 +170,31 @@ public string PackageId } private set { _packageId = value; } } - + + private bool _hasPackageVersion; + private Version _packageVersion; + public Version PackageVersion + { + get + { + if (!_hasPackageVersion) + { + _packageVersion = null; + + var packageVersionString = OriginalItem?.GetMetadata(nameof(MetadataNames.NuGetPackageVersion)) ?? String.Empty; + + if (packageVersionString.Length != 0) + { + Version.TryParse(packageVersionString, out _packageVersion); + } + + // PackageVersion may be null but don't try to recalculate it + _hasPackageVersion = true; + } + + return _packageVersion; + } + } private string _sourcePath; public string SourcePath diff --git a/src/Tasks/Common/ConflictResolution/ConflictResolver.cs b/src/Tasks/Common/ConflictResolution/ConflictResolver.cs index fcf8f8ea0be3..cae075fe3a90 100644 --- a/src/Tasks/Common/ConflictResolution/ConflictResolver.cs +++ b/src/Tasks/Common/ConflictResolution/ConflictResolver.cs @@ -15,11 +15,13 @@ internal class ConflictResolver where TConflictItem : class, ICon private Dictionary winningItemsByKey = new Dictionary(); private ILog log; private PackageRank packageRank; + private PackageOverrideResolver packageOverrideResolver; - public ConflictResolver(PackageRank packageRank, ILog log) + public ConflictResolver(PackageRank packageRank, PackageOverrideResolver packageOverrideResolver, ILog log) { this.log = log; this.packageRank = packageRank; + this.packageOverrideResolver = packageOverrideResolver; } public void ResolveConflicts(IEnumerable conflictItems, Func getItemKey, @@ -87,6 +89,12 @@ public ConflictResolver(PackageRank packageRank, ILog log) private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2) { + var winner = packageOverrideResolver.Resolve(item1, item2); + if (winner != null) + { + return winner; + } + string conflictMessage = string.Format(CultureInfo.CurrentCulture, Strings.EncounteredConflict, item1.DisplayName, item2.DisplayName); diff --git a/src/Tasks/Common/ConflictResolution/MetadataNames.cs b/src/Tasks/Common/ConflictResolution/MetadataNames.cs index 989fa009591d..685db1047ab5 100644 --- a/src/Tasks/Common/ConflictResolution/MetadataNames.cs +++ b/src/Tasks/Common/ConflictResolution/MetadataNames.cs @@ -12,6 +12,7 @@ static class MetadataNames public const string FileName = "FileName"; public const string HintPath = "HintPath"; public const string NuGetPackageId = "NuGetPackageId"; + public const string NuGetPackageVersion = "NuGetPackageVersion"; public const string Path = "Path"; public const string Private = "Private"; public const string TargetPath = "TargetPath"; diff --git a/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs b/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs index 99f462662d2e..a862914bbd46 100644 --- a/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs +++ b/src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs @@ -31,6 +31,17 @@ public class ResolvePackageFileConflicts : TaskBase /// public string[] PreferredPackages { get; set; } + /// + /// A collection of items that contain information of which packages get overriden + /// by which packages before doing any other conflict resolution. + /// + /// + /// This is an optimizaiton so AssemblyVersions, FileVersions, etc. don't need to be read + /// in the default cases where platform packages (Microsoft.NETCore.App) should override specific packages + /// (System.Console v4.3.0). + /// + public ITaskItem[] PackageOverrides { get; set; } + [Output] public ITaskItem[] ReferencesWithoutConflicts { get; set; } @@ -44,6 +55,7 @@ protected override void ExecuteCore() { var log = new MSBuildLog(Log); var packageRanks = new PackageRank(PreferredPackages); + var packageOverrides = new PackageOverrideResolver(PackageOverrides); // Treat assemblies from FrameworkList.xml as platform assemblies that also get considered at compile time IEnumerable compilePlatformItems = null; @@ -60,7 +72,7 @@ protected override void ExecuteCore() // resolve conflicts at compile time var referenceItems = GetConflictTaskItems(References, ConflictItemType.Reference).ToArray(); - var compileConflictScope = new ConflictResolver(packageRanks, log); + var compileConflictScope = new ConflictResolver(packageRanks, packageOverrides, log); compileConflictScope.ResolveConflicts(referenceItems, ci => ItemUtilities.GetReferenceFileName(ci.OriginalItem), @@ -74,7 +86,7 @@ protected override void ExecuteCore() } // resolve conflicts that class in output - var runtimeConflictScope = new ConflictResolver(packageRanks, log); + var runtimeConflictScope = new ConflictResolver(packageRanks, packageOverrides, log); runtimeConflictScope.ResolveConflicts(referenceItems, ci => ItemUtilities.GetReferenceTargetPath(ci.OriginalItem), @@ -95,7 +107,7 @@ protected override void ExecuteCore() // resolve conflicts with platform (eg: shared framework) items // we only commit the platform items since its not a conflict if other items share the same filename. - var platformConflictScope = new ConflictResolver(packageRanks, log); + var platformConflictScope = new ConflictResolver(packageRanks, packageOverrides, log); var platformItems = PlatformManifests?.SelectMany(pm => PlatformManifestReader.LoadConflictItems(pm.ItemSpec, log)) ?? Enumerable.Empty(); if (compilePlatformItems != null) diff --git a/src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets b/src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets new file mode 100644 index 000000000000..a1704e17017b --- /dev/null +++ b/src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets @@ -0,0 +1,233 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + + + Microsoft.CSharp|4.4.0; + Microsoft.Win32.Primitives|4.3.0; + Microsoft.Win32.Registry|4.4.0; + runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple|4.3.0; + runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + System.AppContext|4.3.0; + System.Collections|4.3.0; + System.Collections.Concurrent|4.3.0; + System.Collections.Immutable|1.4.0; + System.Collections.NonGeneric|4.3.0; + System.Collections.Specialized|4.3.0; + System.ComponentModel|4.3.0; + System.ComponentModel.EventBasedAsync|4.3.0; + System.ComponentModel.Primitives|4.3.0; + System.ComponentModel.TypeConverter|4.3.0; + System.Console|4.3.0; + System.Data.Common|4.3.0; + System.Diagnostics.Contracts|4.3.0; + System.Diagnostics.Debug|4.3.0; + System.Diagnostics.FileVersionInfo|4.3.0; + System.Diagnostics.Process|4.3.0; + System.Diagnostics.StackTrace|4.3.0; + System.Diagnostics.TextWriterTraceListener|4.3.0; + System.Diagnostics.Tools|4.3.0; + System.Diagnostics.TraceSource|4.3.0; + System.Diagnostics.Tracing|4.3.0; + System.Dynamic.Runtime|4.3.0; + System.Globalization|4.3.0; + System.Globalization.Extensions|4.3.0; + System.IO|4.3.0; + System.IO.Compression|4.3.0; + System.IO.Compression.ZipFile|4.3.0; + System.IO.FileSystem|4.3.0; + System.IO.FileSystem.AccessControl|4.4.0; + System.IO.FileSystem.DriveInfo|4.3.0; + System.IO.FileSystem.Primitives|4.3.0; + System.IO.FileSystem.Watcher|4.3.0; + System.IO.IsolatedStorage|4.3.0; + System.IO.MemoryMappedFiles|4.3.0; + System.IO.Pipes|4.3.0; + System.IO.UnmanagedMemoryStream|4.3.0; + System.Linq|4.3.0; + System.Linq.Expressions|4.3.0; + System.Linq.Queryable|4.3.0; + System.Net.Http|4.3.0; + System.Net.NameResolution|4.3.0; + System.Net.Primitives|4.3.0; + System.Net.Requests|4.3.0; + System.Net.Security|4.3.0; + System.Net.Sockets|4.3.0; + System.Net.WebHeaderCollection|4.3.0; + System.ObjectModel|4.3.0; + System.Private.DataContractSerialization|4.3.0; + System.Reflection|4.3.0; + System.Reflection.Emit|4.3.0; + System.Reflection.Emit.ILGeneration|4.3.0; + System.Reflection.Emit.Lightweight|4.3.0; + System.Reflection.Extensions|4.3.0; + System.Reflection.Metadata|1.5.0; + System.Reflection.Primitives|4.3.0; + System.Reflection.TypeExtensions|4.3.0; + System.Resources.ResourceManager|4.3.0; + System.Runtime|4.3.0; + System.Runtime.Extensions|4.3.0; + System.Runtime.Handles|4.3.0; + System.Runtime.InteropServices|4.3.0; + System.Runtime.InteropServices.RuntimeInformation|4.3.0; + System.Runtime.Loader|4.3.0; + System.Runtime.Numerics|4.3.0; + System.Runtime.Serialization.Formatters|4.3.0; + System.Runtime.Serialization.Json|4.3.0; + System.Runtime.Serialization.Primitives|4.3.0; + System.Security.AccessControl|4.4.0; + System.Security.Claims|4.3.0; + System.Security.Cryptography.Algorithms|4.3.0; + System.Security.Cryptography.Cng|4.4.0; + System.Security.Cryptography.Csp|4.3.0; + System.Security.Cryptography.Encoding|4.3.0; + System.Security.Cryptography.OpenSsl|4.4.0; + System.Security.Cryptography.Primitives|4.3.0; + System.Security.Cryptography.X509Certificates|4.3.0; + System.Security.Cryptography.Xml|4.4.0; + System.Security.Principal|4.3.0; + System.Security.Principal.Windows|4.4.0; + System.Text.Encoding|4.3.0; + System.Text.Encoding.Extensions|4.3.0; + System.Text.RegularExpressions|4.3.0; + System.Threading|4.3.0; + System.Threading.Overlapped|4.3.0; + System.Threading.Tasks|4.3.0; + System.Threading.Tasks.Extensions|4.3.0; + System.Threading.Tasks.Parallel|4.3.0; + System.Threading.Thread|4.3.0; + System.Threading.ThreadPool|4.3.0; + System.Threading.Timer|4.3.0; + System.ValueTuple|4.3.0; + System.Xml.ReaderWriter|4.3.0; + System.Xml.XDocument|4.3.0; + System.Xml.XmlDocument|4.3.0; + System.Xml.XmlSerializer|4.3.0; + System.Xml.XPath|4.3.0; + System.Xml.XPath.XDocument|4.3.0; + + + + + Microsoft.Win32.Primitives|4.3.0; + System.AppContext|4.3.0; + System.Collections|4.3.0; + System.Collections.Concurrent|4.3.0; + System.Collections.Immutable|1.4.0; + System.Collections.NonGeneric|4.3.0; + System.Collections.Specialized|4.3.0; + System.ComponentModel|4.3.0; + System.ComponentModel.EventBasedAsync|4.3.0; + System.ComponentModel.Primitives|4.3.0; + System.ComponentModel.TypeConverter|4.3.0; + System.Console|4.3.0; + System.Data.Common|4.3.0; + System.Diagnostics.Contracts|4.3.0; + System.Diagnostics.Debug|4.3.0; + System.Diagnostics.FileVersionInfo|4.3.0; + System.Diagnostics.Process|4.3.0; + System.Diagnostics.StackTrace|4.3.0; + System.Diagnostics.TextWriterTraceListener|4.3.0; + System.Diagnostics.Tools|4.3.0; + System.Diagnostics.TraceSource|4.3.0; + System.Diagnostics.Tracing|4.3.0; + System.Dynamic.Runtime|4.3.0; + System.Globalization|4.3.0; + System.Globalization.Extensions|4.3.0; + System.IO|4.3.0; + System.IO.Compression|4.3.0; + System.IO.Compression.ZipFile|4.3.0; + System.IO.FileSystem|4.3.0; + System.IO.FileSystem.DriveInfo|4.3.0; + System.IO.FileSystem.Primitives|4.3.0; + System.IO.FileSystem.Watcher|4.3.0; + System.IO.IsolatedStorage|4.3.0; + System.IO.MemoryMappedFiles|4.3.0; + System.IO.Pipes|4.3.0; + System.IO.UnmanagedMemoryStream|4.3.0; + System.Linq|4.3.0; + System.Linq.Expressions|4.3.0; + System.Linq.Queryable|4.3.0; + System.Net.Http|4.3.0; + System.Net.NameResolution|4.3.0; + System.Net.Primitives|4.3.0; + System.Net.Requests|4.3.0; + System.Net.Security|4.3.0; + System.Net.Sockets|4.3.0; + System.Net.WebHeaderCollection|4.3.0; + System.ObjectModel|4.3.0; + System.Private.DataContractSerialization|4.3.0; + System.Reflection|4.3.0; + System.Reflection.Emit|4.3.0; + System.Reflection.Emit.ILGeneration|4.3.0; + System.Reflection.Emit.Lightweight|4.3.0; + System.Reflection.Extensions|4.3.0; + System.Reflection.Primitives|4.3.0; + System.Reflection.TypeExtensions|4.3.0; + System.Resources.ResourceManager|4.3.0; + System.Runtime|4.3.0; + System.Runtime.Extensions|4.3.0; + System.Runtime.Handles|4.3.0; + System.Runtime.InteropServices|4.3.0; + System.Runtime.InteropServices.RuntimeInformation|4.3.0; + System.Runtime.Loader|4.3.0; + System.Runtime.Numerics|4.3.0; + System.Runtime.Serialization.Formatters|4.3.0; + System.Runtime.Serialization.Json|4.3.0; + System.Runtime.Serialization.Primitives|4.3.0; + System.Security.AccessControl|4.4.0; + System.Security.Claims|4.3.0; + System.Security.Cryptography.Algorithms|4.3.0; + System.Security.Cryptography.Csp|4.3.0; + System.Security.Cryptography.Encoding|4.3.0; + System.Security.Cryptography.Primitives|4.3.0; + System.Security.Cryptography.X509Certificates|4.3.0; + System.Security.Cryptography.Xml|4.4.0; + System.Security.Principal|4.3.0; + System.Security.Principal.Windows|4.4.0; + System.Text.Encoding|4.3.0; + System.Text.Encoding.Extensions|4.3.0; + System.Text.RegularExpressions|4.3.0; + System.Threading|4.3.0; + System.Threading.Overlapped|4.3.0; + System.Threading.Tasks|4.3.0; + System.Threading.Tasks.Extensions|4.3.0; + System.Threading.Tasks.Parallel|4.3.0; + System.Threading.Thread|4.3.0; + System.Threading.ThreadPool|4.3.0; + System.Threading.Timer|4.3.0; + System.ValueTuple|4.3.0; + System.Xml.ReaderWriter|4.3.0; + System.Xml.XDocument|4.3.0; + System.Xml.XmlDocument|4.3.0; + System.Xml.XmlSerializer|4.3.0; + System.Xml.XPath|4.3.0; + System.Xml.XPath.XDocument|4.3.0; + + + + diff --git a/src/Tasks/Common/src/ConflictResolution/PackageOverride.cs b/src/Tasks/Common/src/ConflictResolution/PackageOverride.cs new file mode 100644 index 000000000000..08738c81e885 --- /dev/null +++ b/src/Tasks/Common/src/ConflictResolution/PackageOverride.cs @@ -0,0 +1,64 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Build.Framework; + +namespace Microsoft.NET.Build.Tasks.ConflictResolution +{ + /// + /// A PackageOverride contains information about a package that overrides + /// a set of packages up to a certain version. + /// + /// + /// For example, Microsoft.NETCore.App overrides System.Console up to version 4.3.0, + /// System.IO up to version version 4.3.0, etc. + /// + internal class PackageOverride + { + public string PackageName { get; } + public Dictionary OverridenPackages { get; } + + private PackageOverride(string packageName, IEnumerable> overridenPackages) + { + PackageName = packageName; + + OverridenPackages = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (Tuple package in overridenPackages) + { + OverridenPackages[package.Item1] = package.Item2; + } + } + + public static PackageOverride Create(ITaskItem packageOverrideItem) + { + string packageName = packageOverrideItem.ItemSpec; + IEnumerable> overridenPackages = CreateOverridenPackages(packageOverrideItem.GetMetadata("OverridenPackages")); + + return new PackageOverride(packageName, overridenPackages); + } + + private static IEnumerable> CreateOverridenPackages(string overridenPackagesString) + { + if (!string.IsNullOrEmpty(overridenPackagesString)) + { + overridenPackagesString = overridenPackagesString.Trim(); + string[] overridenPackagesAndVersions = overridenPackagesString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + foreach (string overridenPackagesAndVersion in overridenPackagesAndVersions) + { + string trimmedOverridenPackagesAndVersion = overridenPackagesAndVersion.Trim(); + int separatorIndex = trimmedOverridenPackagesAndVersion.IndexOf('|'); + if (separatorIndex != -1) + { + if (Version.TryParse(trimmedOverridenPackagesAndVersion.Substring(separatorIndex + 1), out Version version)) + { + yield return Tuple.Create(trimmedOverridenPackagesAndVersion.Substring(0, separatorIndex), version); + } + } + } + } + } + } +} diff --git a/src/Tasks/Common/src/ConflictResolution/PackageOverrideResolver.cs b/src/Tasks/Common/src/ConflictResolution/PackageOverrideResolver.cs new file mode 100644 index 000000000000..964f1ce13a5b --- /dev/null +++ b/src/Tasks/Common/src/ConflictResolution/PackageOverrideResolver.cs @@ -0,0 +1,89 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Microsoft.Build.Framework; + +namespace Microsoft.NET.Build.Tasks.ConflictResolution +{ + /// + /// Resolves conflicts between items by allowing specific packages to override + /// all items coming from a set of packages up to a certain version of each package. + /// + internal class PackageOverrideResolver where TConflictItem : class, IConflictItem + { + private Dictionary _packageOverrides; + + public PackageOverrideResolver(ITaskItem[] packageOverrideItems) + { + if (packageOverrideItems?.Length > 0) + { + _packageOverrides = new Dictionary(packageOverrideItems.Length, StringComparer.OrdinalIgnoreCase); + + foreach (ITaskItem packageOverrideItem in packageOverrideItems) + { + PackageOverride packageOverride = PackageOverride.Create(packageOverrideItem); + + if (_packageOverrides.TryGetValue(packageOverride.PackageName, out PackageOverride existing)) + { + MergePackageOverrides(packageOverride, existing); + } + else + { + _packageOverrides[packageOverride.PackageName] = packageOverride; + } + } + } + } + + /// + /// Merges newPackageOverride into existingPackageOverride by adding all the new overriden packages + /// and taking the highest version when they both contain the same overriden package. + /// + private static void MergePackageOverrides(PackageOverride newPackageOverride, PackageOverride existingPackageOverride) + { + foreach (KeyValuePair newOverride in newPackageOverride.OverridenPackages) + { + if (existingPackageOverride.OverridenPackages.TryGetValue(newOverride.Key, out Version existingOverrideVersion)) + { + if (existingOverrideVersion < newOverride.Value) + { + existingPackageOverride.OverridenPackages[newOverride.Key] = newOverride.Value; + } + } + else + { + existingPackageOverride.OverridenPackages[newOverride.Key] = newOverride.Value; + } + } + } + + public TConflictItem Resolve(TConflictItem item1, TConflictItem item2) + { + if (_packageOverrides != null) + { + PackageOverride packageOverride; + Version version; + if (item1.PackageId != null + && _packageOverrides.TryGetValue(item1.PackageId, out packageOverride) + && packageOverride.OverridenPackages.TryGetValue(item2.PackageId, out version) + && item2.PackageVersion != null + && item2.PackageVersion <= version) + { + return item1; + } + else if (item2.PackageId != null + && _packageOverrides.TryGetValue(item2.PackageId, out packageOverride) + && packageOverride.OverridenPackages.TryGetValue(item1.PackageId, out version) + && item1.PackageVersion != null + && item1.PackageVersion <= version) + { + return item2; + } + } + + return null; + } + } +} diff --git a/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj b/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj index cd5a728780b6..9e179faf972a 100644 --- a/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj +++ b/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj @@ -73,6 +73,9 @@ + + msbuildExtensions\Microsoft\Microsoft.NET.Build.Extensions\%(FileName)%(Extension) + diff --git a/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/msbuildExtensions/Microsoft/Microsoft.NET.Build.Extensions/Microsoft.NET.Build.Extensions.ConflictResolution.targets b/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/msbuildExtensions/Microsoft/Microsoft.NET.Build.Extensions/Microsoft.NET.Build.Extensions.ConflictResolution.targets index 75f324e73e71..dc94dff39a76 100644 --- a/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/msbuildExtensions/Microsoft/Microsoft.NET.Build.Extensions/Microsoft.NET.Build.Extensions.ConflictResolution.targets +++ b/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/msbuildExtensions/Microsoft/Microsoft.NET.Build.Extensions/Microsoft.NET.Build.Extensions.ConflictResolution.targets @@ -23,6 +23,8 @@ Copyright (c) .NET Foundation. All rights reserved. <_HandlePackageFileConflictsBefore>ResolveAssemblyReferences + + diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs index 8ce0ba48d7be..2bd4cf31a0f4 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs @@ -341,7 +341,9 @@ void UnresolvedConflictHandler(MockConflictItem item) .OrderBy(id => id) .ToArray(); - var resolver = new ConflictResolver(new PackageRank(packagesForRank), new MockLog()); + PackageOverrideResolver packageOverrides = new PackageOverrideResolver(new ITaskItem[] { }); + + var resolver = new ConflictResolver(new PackageRank(packagesForRank), packageOverrides, new MockLog()); resolver.ResolveConflicts(itemsToCommit, GetItemKey, ConflictHandler, unresolvedConflict: UnresolvedConflictHandler); @@ -375,6 +377,7 @@ public MockConflictItem(string name = "System.Ben") FileName = name + ".dll"; FileVersion = new Version("1.0.0.0"); PackageId = name; + PackageVersion = new Version("1.0.0"); DisplayName = name; } public string Key { get; set; } @@ -391,6 +394,8 @@ public MockConflictItem(string name = "System.Ben") public string PackageId { get; set; } + public Version PackageVersion { get; set; } + public string DisplayName { get; set; } } diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj index 0f56b13f7ada..6deee44d305a 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj +++ b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj @@ -76,7 +76,10 @@ - + + build\%(FileName)%(Extension) + + diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets index 9ab8fe7e5581..6254a8f7fd78 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets @@ -16,8 +16,9 @@ Copyright (c) .NET Foundation. All rights reserved. $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + - @@ -53,14 +54,231 @@ Copyright (c) .NET Foundation. All rights reserved. %(PackageName) %(PackageVersion) - + + + + + + Microsoft.CSharp|4.4.0; + Microsoft.Win32.Primitives|4.3.0; + Microsoft.Win32.Registry|4.4.0; + runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple|4.3.0; + runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; + System.AppContext|4.3.0; + System.Collections|4.3.0; + System.Collections.Concurrent|4.3.0; + System.Collections.Immutable|1.4.0; + System.Collections.NonGeneric|4.3.0; + System.Collections.Specialized|4.3.0; + System.ComponentModel|4.3.0; + System.ComponentModel.EventBasedAsync|4.3.0; + System.ComponentModel.Primitives|4.3.0; + System.ComponentModel.TypeConverter|4.3.0; + System.Console|4.3.0; + System.Data.Common|4.3.0; + System.Diagnostics.Contracts|4.3.0; + System.Diagnostics.Debug|4.3.0; + System.Diagnostics.FileVersionInfo|4.3.0; + System.Diagnostics.Process|4.3.0; + System.Diagnostics.StackTrace|4.3.0; + System.Diagnostics.TextWriterTraceListener|4.3.0; + System.Diagnostics.Tools|4.3.0; + System.Diagnostics.TraceSource|4.3.0; + System.Diagnostics.Tracing|4.3.0; + System.Dynamic.Runtime|4.3.0; + System.Globalization|4.3.0; + System.Globalization.Extensions|4.3.0; + System.IO|4.3.0; + System.IO.Compression|4.3.0; + System.IO.Compression.ZipFile|4.3.0; + System.IO.FileSystem|4.3.0; + System.IO.FileSystem.AccessControl|4.4.0; + System.IO.FileSystem.DriveInfo|4.3.0; + System.IO.FileSystem.Primitives|4.3.0; + System.IO.FileSystem.Watcher|4.3.0; + System.IO.IsolatedStorage|4.3.0; + System.IO.MemoryMappedFiles|4.3.0; + System.IO.Pipes|4.3.0; + System.IO.UnmanagedMemoryStream|4.3.0; + System.Linq|4.3.0; + System.Linq.Expressions|4.3.0; + System.Linq.Queryable|4.3.0; + System.Net.Http|4.3.0; + System.Net.NameResolution|4.3.0; + System.Net.Primitives|4.3.0; + System.Net.Requests|4.3.0; + System.Net.Security|4.3.0; + System.Net.Sockets|4.3.0; + System.Net.WebHeaderCollection|4.3.0; + System.ObjectModel|4.3.0; + System.Private.DataContractSerialization|4.3.0; + System.Reflection|4.3.0; + System.Reflection.Emit|4.3.0; + System.Reflection.Emit.ILGeneration|4.3.0; + System.Reflection.Emit.Lightweight|4.3.0; + System.Reflection.Extensions|4.3.0; + System.Reflection.Metadata|1.5.0; + System.Reflection.Primitives|4.3.0; + System.Reflection.TypeExtensions|4.3.0; + System.Resources.ResourceManager|4.3.0; + System.Runtime|4.3.0; + System.Runtime.Extensions|4.3.0; + System.Runtime.Handles|4.3.0; + System.Runtime.InteropServices|4.3.0; + System.Runtime.InteropServices.RuntimeInformation|4.3.0; + System.Runtime.Loader|4.3.0; + System.Runtime.Numerics|4.3.0; + System.Runtime.Serialization.Formatters|4.3.0; + System.Runtime.Serialization.Json|4.3.0; + System.Runtime.Serialization.Primitives|4.3.0; + System.Security.AccessControl|4.4.0; + System.Security.Claims|4.3.0; + System.Security.Cryptography.Algorithms|4.3.0; + System.Security.Cryptography.Cng|4.4.0; + System.Security.Cryptography.Csp|4.3.0; + System.Security.Cryptography.Encoding|4.3.0; + System.Security.Cryptography.OpenSsl|4.4.0; + System.Security.Cryptography.Primitives|4.3.0; + System.Security.Cryptography.X509Certificates|4.3.0; + System.Security.Cryptography.Xml|4.4.0; + System.Security.Principal|4.3.0; + System.Security.Principal.Windows|4.4.0; + System.Text.Encoding|4.3.0; + System.Text.Encoding.Extensions|4.3.0; + System.Text.RegularExpressions|4.3.0; + System.Threading|4.3.0; + System.Threading.Overlapped|4.3.0; + System.Threading.Tasks|4.3.0; + System.Threading.Tasks.Extensions|4.3.0; + System.Threading.Tasks.Parallel|4.3.0; + System.Threading.Thread|4.3.0; + System.Threading.ThreadPool|4.3.0; + System.Threading.Timer|4.3.0; + System.ValueTuple|4.3.0; + System.Xml.ReaderWriter|4.3.0; + System.Xml.XDocument|4.3.0; + System.Xml.XmlDocument|4.3.0; + System.Xml.XmlSerializer|4.3.0; + System.Xml.XPath|4.3.0; + System.Xml.XPath.XDocument|4.3.0; + + + + + Microsoft.Win32.Primitives|4.3.0; + System.AppContext|4.3.0; + System.Collections|4.3.0; + System.Collections.Concurrent|4.3.0; + System.Collections.Immutable|1.4.0; + System.Collections.NonGeneric|4.3.0; + System.Collections.Specialized|4.3.0; + System.ComponentModel|4.3.0; + System.ComponentModel.EventBasedAsync|4.3.0; + System.ComponentModel.Primitives|4.3.0; + System.ComponentModel.TypeConverter|4.3.0; + System.Console|4.3.0; + System.Data.Common|4.3.0; + System.Diagnostics.Contracts|4.3.0; + System.Diagnostics.Debug|4.3.0; + System.Diagnostics.FileVersionInfo|4.3.0; + System.Diagnostics.Process|4.3.0; + System.Diagnostics.StackTrace|4.3.0; + System.Diagnostics.TextWriterTraceListener|4.3.0; + System.Diagnostics.Tools|4.3.0; + System.Diagnostics.TraceSource|4.3.0; + System.Diagnostics.Tracing|4.3.0; + System.Dynamic.Runtime|4.3.0; + System.Globalization|4.3.0; + System.Globalization.Extensions|4.3.0; + System.IO|4.3.0; + System.IO.Compression|4.3.0; + System.IO.Compression.ZipFile|4.3.0; + System.IO.FileSystem|4.3.0; + System.IO.FileSystem.DriveInfo|4.3.0; + System.IO.FileSystem.Primitives|4.3.0; + System.IO.FileSystem.Watcher|4.3.0; + System.IO.IsolatedStorage|4.3.0; + System.IO.MemoryMappedFiles|4.3.0; + System.IO.Pipes|4.3.0; + System.IO.UnmanagedMemoryStream|4.3.0; + System.Linq|4.3.0; + System.Linq.Expressions|4.3.0; + System.Linq.Queryable|4.3.0; + System.Net.Http|4.3.0; + System.Net.NameResolution|4.3.0; + System.Net.Primitives|4.3.0; + System.Net.Requests|4.3.0; + System.Net.Security|4.3.0; + System.Net.Sockets|4.3.0; + System.Net.WebHeaderCollection|4.3.0; + System.ObjectModel|4.3.0; + System.Private.DataContractSerialization|4.3.0; + System.Reflection|4.3.0; + System.Reflection.Emit|4.3.0; + System.Reflection.Emit.ILGeneration|4.3.0; + System.Reflection.Emit.Lightweight|4.3.0; + System.Reflection.Extensions|4.3.0; + System.Reflection.Primitives|4.3.0; + System.Reflection.TypeExtensions|4.3.0; + System.Resources.ResourceManager|4.3.0; + System.Runtime|4.3.0; + System.Runtime.Extensions|4.3.0; + System.Runtime.Handles|4.3.0; + System.Runtime.InteropServices|4.3.0; + System.Runtime.InteropServices.RuntimeInformation|4.3.0; + System.Runtime.Loader|4.3.0; + System.Runtime.Numerics|4.3.0; + System.Runtime.Serialization.Formatters|4.3.0; + System.Runtime.Serialization.Json|4.3.0; + System.Runtime.Serialization.Primitives|4.3.0; + System.Security.AccessControl|4.4.0; + System.Security.Claims|4.3.0; + System.Security.Cryptography.Algorithms|4.3.0; + System.Security.Cryptography.Csp|4.3.0; + System.Security.Cryptography.Encoding|4.3.0; + System.Security.Cryptography.Primitives|4.3.0; + System.Security.Cryptography.X509Certificates|4.3.0; + System.Security.Cryptography.Xml|4.4.0; + System.Security.Principal|4.3.0; + System.Security.Principal.Windows|4.4.0; + System.Text.Encoding|4.3.0; + System.Text.Encoding.Extensions|4.3.0; + System.Text.RegularExpressions|4.3.0; + System.Threading|4.3.0; + System.Threading.Overlapped|4.3.0; + System.Threading.Tasks|4.3.0; + System.Threading.Tasks.Extensions|4.3.0; + System.Threading.Tasks.Parallel|4.3.0; + System.Threading.Thread|4.3.0; + System.Threading.ThreadPool|4.3.0; + System.Threading.Timer|4.3.0; + System.ValueTuple|4.3.0; + System.Xml.ReaderWriter|4.3.0; + System.Xml.XDocument|4.3.0; + System.Xml.XmlDocument|4.3.0; + System.Xml.XmlSerializer|4.3.0; + System.Xml.XPath|4.3.0; + System.Xml.XPath.XDocument|4.3.0; + + + + ReferenceCopyLocalPaths="@(ReferenceCopyLocalPaths)" + OtherRuntimeItems="@(_LockFileAssemblies)" + PlatformManifests="@(PackageConflictPlatformManifests)" + TargetFrameworkDirectories="$(TargetFrameworkDirectory)" + PackageOverrides="@(PackageConflictOverrides)" + PreferredPackages="$(PackageConflictPreferredPackages)"> @@ -92,4 +310,4 @@ Copyright (c) .NET Foundation. All rights reserved. - \ No newline at end of file + From 8e818fdcd0829b2e02602a2c4eb271b2a0fb283f Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Fri, 8 Dec 2017 14:28:00 -0600 Subject: [PATCH 2/6] Move new ConflictResolution files to the new directory. --- src/Tasks/Common/{src => }/ConflictResolution/PackageOverride.cs | 0 .../{src => }/ConflictResolution/PackageOverrideResolver.cs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Tasks/Common/{src => }/ConflictResolution/PackageOverride.cs (100%) rename src/Tasks/Common/{src => }/ConflictResolution/PackageOverrideResolver.cs (100%) diff --git a/src/Tasks/Common/src/ConflictResolution/PackageOverride.cs b/src/Tasks/Common/ConflictResolution/PackageOverride.cs similarity index 100% rename from src/Tasks/Common/src/ConflictResolution/PackageOverride.cs rename to src/Tasks/Common/ConflictResolution/PackageOverride.cs diff --git a/src/Tasks/Common/src/ConflictResolution/PackageOverrideResolver.cs b/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs similarity index 100% rename from src/Tasks/Common/src/ConflictResolution/PackageOverrideResolver.cs rename to src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs From ed7cf099265b3546bdcbb131fb1ac363b9208722 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Fri, 8 Dec 2017 14:50:10 -0600 Subject: [PATCH 3/6] Lazy load the package override dictionary so when there are no conflicts, we don't need to build it. --- .../PackageOverrideResolver.cs | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs b/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs index 964f1ce13a5b..e8e5d547a12e 100644 --- a/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs +++ b/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs @@ -13,28 +13,45 @@ namespace Microsoft.NET.Build.Tasks.ConflictResolution /// internal class PackageOverrideResolver where TConflictItem : class, IConflictItem { - private Dictionary _packageOverrides; + private ITaskItem[] _packageOverrideItems; + private Lazy> _packageOverrides; public PackageOverrideResolver(ITaskItem[] packageOverrideItems) { - if (packageOverrideItems?.Length > 0) + _packageOverrideItems = packageOverrideItems; + _packageOverrides = new Lazy>(() => BuildPackageOverrides()); + } + + private Dictionary PackageOverrides => _packageOverrides.Value; + + private Dictionary BuildPackageOverrides() + { + Dictionary result; + + if (_packageOverrideItems?.Length > 0) { - _packageOverrides = new Dictionary(packageOverrideItems.Length, StringComparer.OrdinalIgnoreCase); + result = new Dictionary(_packageOverrideItems.Length, StringComparer.OrdinalIgnoreCase); - foreach (ITaskItem packageOverrideItem in packageOverrideItems) + foreach (ITaskItem packageOverrideItem in _packageOverrideItems) { PackageOverride packageOverride = PackageOverride.Create(packageOverrideItem); - if (_packageOverrides.TryGetValue(packageOverride.PackageName, out PackageOverride existing)) + if (result.TryGetValue(packageOverride.PackageName, out PackageOverride existing)) { MergePackageOverrides(packageOverride, existing); } else { - _packageOverrides[packageOverride.PackageName] = packageOverride; + result[packageOverride.PackageName] = packageOverride; } } } + else + { + result = null; + } + + return result; } /// @@ -61,12 +78,12 @@ private static void MergePackageOverrides(PackageOverride newPackageOverride, Pa public TConflictItem Resolve(TConflictItem item1, TConflictItem item2) { - if (_packageOverrides != null) + if (PackageOverrides != null) { PackageOverride packageOverride; Version version; if (item1.PackageId != null - && _packageOverrides.TryGetValue(item1.PackageId, out packageOverride) + && PackageOverrides.TryGetValue(item1.PackageId, out packageOverride) && packageOverride.OverridenPackages.TryGetValue(item2.PackageId, out version) && item2.PackageVersion != null && item2.PackageVersion <= version) @@ -74,7 +91,7 @@ public TConflictItem Resolve(TConflictItem item1, TConflictItem item2) return item1; } else if (item2.PackageId != null - && _packageOverrides.TryGetValue(item2.PackageId, out packageOverride) + && PackageOverrides.TryGetValue(item2.PackageId, out packageOverride) && packageOverride.OverridenPackages.TryGetValue(item1.PackageId, out version) && item1.PackageVersion != null && item1.PackageVersion <= version) From 2b0580999b39e468e55e044db5ed98ee012f2b16 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Fri, 8 Dec 2017 14:51:03 -0600 Subject: [PATCH 4/6] Remove unnecessary copy of PackageConflictOverrides. --- .../Microsoft.NET.ConflictResolution.targets | 216 ------------------ 1 file changed, 216 deletions(-) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets index 6254a8f7fd78..fcbbcc8e3b14 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.ConflictResolution.targets @@ -56,222 +56,6 @@ Copyright (c) .NET Foundation. All rights reserved. - - - - Microsoft.CSharp|4.4.0; - Microsoft.Win32.Primitives|4.3.0; - Microsoft.Win32.Registry|4.4.0; - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple|4.3.0; - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; - System.AppContext|4.3.0; - System.Collections|4.3.0; - System.Collections.Concurrent|4.3.0; - System.Collections.Immutable|1.4.0; - System.Collections.NonGeneric|4.3.0; - System.Collections.Specialized|4.3.0; - System.ComponentModel|4.3.0; - System.ComponentModel.EventBasedAsync|4.3.0; - System.ComponentModel.Primitives|4.3.0; - System.ComponentModel.TypeConverter|4.3.0; - System.Console|4.3.0; - System.Data.Common|4.3.0; - System.Diagnostics.Contracts|4.3.0; - System.Diagnostics.Debug|4.3.0; - System.Diagnostics.FileVersionInfo|4.3.0; - System.Diagnostics.Process|4.3.0; - System.Diagnostics.StackTrace|4.3.0; - System.Diagnostics.TextWriterTraceListener|4.3.0; - System.Diagnostics.Tools|4.3.0; - System.Diagnostics.TraceSource|4.3.0; - System.Diagnostics.Tracing|4.3.0; - System.Dynamic.Runtime|4.3.0; - System.Globalization|4.3.0; - System.Globalization.Extensions|4.3.0; - System.IO|4.3.0; - System.IO.Compression|4.3.0; - System.IO.Compression.ZipFile|4.3.0; - System.IO.FileSystem|4.3.0; - System.IO.FileSystem.AccessControl|4.4.0; - System.IO.FileSystem.DriveInfo|4.3.0; - System.IO.FileSystem.Primitives|4.3.0; - System.IO.FileSystem.Watcher|4.3.0; - System.IO.IsolatedStorage|4.3.0; - System.IO.MemoryMappedFiles|4.3.0; - System.IO.Pipes|4.3.0; - System.IO.UnmanagedMemoryStream|4.3.0; - System.Linq|4.3.0; - System.Linq.Expressions|4.3.0; - System.Linq.Queryable|4.3.0; - System.Net.Http|4.3.0; - System.Net.NameResolution|4.3.0; - System.Net.Primitives|4.3.0; - System.Net.Requests|4.3.0; - System.Net.Security|4.3.0; - System.Net.Sockets|4.3.0; - System.Net.WebHeaderCollection|4.3.0; - System.ObjectModel|4.3.0; - System.Private.DataContractSerialization|4.3.0; - System.Reflection|4.3.0; - System.Reflection.Emit|4.3.0; - System.Reflection.Emit.ILGeneration|4.3.0; - System.Reflection.Emit.Lightweight|4.3.0; - System.Reflection.Extensions|4.3.0; - System.Reflection.Metadata|1.5.0; - System.Reflection.Primitives|4.3.0; - System.Reflection.TypeExtensions|4.3.0; - System.Resources.ResourceManager|4.3.0; - System.Runtime|4.3.0; - System.Runtime.Extensions|4.3.0; - System.Runtime.Handles|4.3.0; - System.Runtime.InteropServices|4.3.0; - System.Runtime.InteropServices.RuntimeInformation|4.3.0; - System.Runtime.Loader|4.3.0; - System.Runtime.Numerics|4.3.0; - System.Runtime.Serialization.Formatters|4.3.0; - System.Runtime.Serialization.Json|4.3.0; - System.Runtime.Serialization.Primitives|4.3.0; - System.Security.AccessControl|4.4.0; - System.Security.Claims|4.3.0; - System.Security.Cryptography.Algorithms|4.3.0; - System.Security.Cryptography.Cng|4.4.0; - System.Security.Cryptography.Csp|4.3.0; - System.Security.Cryptography.Encoding|4.3.0; - System.Security.Cryptography.OpenSsl|4.4.0; - System.Security.Cryptography.Primitives|4.3.0; - System.Security.Cryptography.X509Certificates|4.3.0; - System.Security.Cryptography.Xml|4.4.0; - System.Security.Principal|4.3.0; - System.Security.Principal.Windows|4.4.0; - System.Text.Encoding|4.3.0; - System.Text.Encoding.Extensions|4.3.0; - System.Text.RegularExpressions|4.3.0; - System.Threading|4.3.0; - System.Threading.Overlapped|4.3.0; - System.Threading.Tasks|4.3.0; - System.Threading.Tasks.Extensions|4.3.0; - System.Threading.Tasks.Parallel|4.3.0; - System.Threading.Thread|4.3.0; - System.Threading.ThreadPool|4.3.0; - System.Threading.Timer|4.3.0; - System.ValueTuple|4.3.0; - System.Xml.ReaderWriter|4.3.0; - System.Xml.XDocument|4.3.0; - System.Xml.XmlDocument|4.3.0; - System.Xml.XmlSerializer|4.3.0; - System.Xml.XPath|4.3.0; - System.Xml.XPath.XDocument|4.3.0; - - - - - Microsoft.Win32.Primitives|4.3.0; - System.AppContext|4.3.0; - System.Collections|4.3.0; - System.Collections.Concurrent|4.3.0; - System.Collections.Immutable|1.4.0; - System.Collections.NonGeneric|4.3.0; - System.Collections.Specialized|4.3.0; - System.ComponentModel|4.3.0; - System.ComponentModel.EventBasedAsync|4.3.0; - System.ComponentModel.Primitives|4.3.0; - System.ComponentModel.TypeConverter|4.3.0; - System.Console|4.3.0; - System.Data.Common|4.3.0; - System.Diagnostics.Contracts|4.3.0; - System.Diagnostics.Debug|4.3.0; - System.Diagnostics.FileVersionInfo|4.3.0; - System.Diagnostics.Process|4.3.0; - System.Diagnostics.StackTrace|4.3.0; - System.Diagnostics.TextWriterTraceListener|4.3.0; - System.Diagnostics.Tools|4.3.0; - System.Diagnostics.TraceSource|4.3.0; - System.Diagnostics.Tracing|4.3.0; - System.Dynamic.Runtime|4.3.0; - System.Globalization|4.3.0; - System.Globalization.Extensions|4.3.0; - System.IO|4.3.0; - System.IO.Compression|4.3.0; - System.IO.Compression.ZipFile|4.3.0; - System.IO.FileSystem|4.3.0; - System.IO.FileSystem.DriveInfo|4.3.0; - System.IO.FileSystem.Primitives|4.3.0; - System.IO.FileSystem.Watcher|4.3.0; - System.IO.IsolatedStorage|4.3.0; - System.IO.MemoryMappedFiles|4.3.0; - System.IO.Pipes|4.3.0; - System.IO.UnmanagedMemoryStream|4.3.0; - System.Linq|4.3.0; - System.Linq.Expressions|4.3.0; - System.Linq.Queryable|4.3.0; - System.Net.Http|4.3.0; - System.Net.NameResolution|4.3.0; - System.Net.Primitives|4.3.0; - System.Net.Requests|4.3.0; - System.Net.Security|4.3.0; - System.Net.Sockets|4.3.0; - System.Net.WebHeaderCollection|4.3.0; - System.ObjectModel|4.3.0; - System.Private.DataContractSerialization|4.3.0; - System.Reflection|4.3.0; - System.Reflection.Emit|4.3.0; - System.Reflection.Emit.ILGeneration|4.3.0; - System.Reflection.Emit.Lightweight|4.3.0; - System.Reflection.Extensions|4.3.0; - System.Reflection.Primitives|4.3.0; - System.Reflection.TypeExtensions|4.3.0; - System.Resources.ResourceManager|4.3.0; - System.Runtime|4.3.0; - System.Runtime.Extensions|4.3.0; - System.Runtime.Handles|4.3.0; - System.Runtime.InteropServices|4.3.0; - System.Runtime.InteropServices.RuntimeInformation|4.3.0; - System.Runtime.Loader|4.3.0; - System.Runtime.Numerics|4.3.0; - System.Runtime.Serialization.Formatters|4.3.0; - System.Runtime.Serialization.Json|4.3.0; - System.Runtime.Serialization.Primitives|4.3.0; - System.Security.AccessControl|4.4.0; - System.Security.Claims|4.3.0; - System.Security.Cryptography.Algorithms|4.3.0; - System.Security.Cryptography.Csp|4.3.0; - System.Security.Cryptography.Encoding|4.3.0; - System.Security.Cryptography.Primitives|4.3.0; - System.Security.Cryptography.X509Certificates|4.3.0; - System.Security.Cryptography.Xml|4.4.0; - System.Security.Principal|4.3.0; - System.Security.Principal.Windows|4.4.0; - System.Text.Encoding|4.3.0; - System.Text.Encoding.Extensions|4.3.0; - System.Text.RegularExpressions|4.3.0; - System.Threading|4.3.0; - System.Threading.Overlapped|4.3.0; - System.Threading.Tasks|4.3.0; - System.Threading.Tasks.Extensions|4.3.0; - System.Threading.Tasks.Parallel|4.3.0; - System.Threading.Thread|4.3.0; - System.Threading.ThreadPool|4.3.0; - System.Threading.Timer|4.3.0; - System.ValueTuple|4.3.0; - System.Xml.ReaderWriter|4.3.0; - System.Xml.XDocument|4.3.0; - System.Xml.XmlDocument|4.3.0; - System.Xml.XmlSerializer|4.3.0; - System.Xml.XPath|4.3.0; - System.Xml.XPath.XDocument|4.3.0; - - - - Date: Sat, 9 Dec 2017 17:30:12 -0600 Subject: [PATCH 5/6] Add unit tests for PackageOverrideResolver. --- .../ConflictResolution/PackageOverride.cs | 4 +- .../PackageOverrideResolver.cs | 2 +- src/Tasks/Common/MetadataKeys.cs | 3 + .../GivenAConflictResolver.cs | 107 +++++++++++------- .../GivenAPackageOverrideResolver.cs | 52 +++++++++ .../Mocks/MockConflictItem.cs | 41 +++++++ 6 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPackageOverrideResolver.cs create mode 100644 src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/Mocks/MockConflictItem.cs diff --git a/src/Tasks/Common/ConflictResolution/PackageOverride.cs b/src/Tasks/Common/ConflictResolution/PackageOverride.cs index 08738c81e885..2356aecc507b 100644 --- a/src/Tasks/Common/ConflictResolution/PackageOverride.cs +++ b/src/Tasks/Common/ConflictResolution/PackageOverride.cs @@ -35,9 +35,9 @@ private PackageOverride(string packageName, IEnumerable> public static PackageOverride Create(ITaskItem packageOverrideItem) { string packageName = packageOverrideItem.ItemSpec; - IEnumerable> overridenPackages = CreateOverridenPackages(packageOverrideItem.GetMetadata("OverridenPackages")); + string overridenPackagesString = packageOverrideItem.GetMetadata(MetadataKeys.OverridenPackages); - return new PackageOverride(packageName, overridenPackages); + return new PackageOverride(packageName, CreateOverridenPackages(overridenPackagesString)); } private static IEnumerable> CreateOverridenPackages(string overridenPackagesString) diff --git a/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs b/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs index e8e5d547a12e..1c3d7aac8a85 100644 --- a/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs +++ b/src/Tasks/Common/ConflictResolution/PackageOverrideResolver.cs @@ -22,7 +22,7 @@ public PackageOverrideResolver(ITaskItem[] packageOverrideItems) _packageOverrides = new Lazy>(() => BuildPackageOverrides()); } - private Dictionary PackageOverrides => _packageOverrides.Value; + public Dictionary PackageOverrides => _packageOverrides.Value; private Dictionary BuildPackageOverrides() { diff --git a/src/Tasks/Common/MetadataKeys.cs b/src/Tasks/Common/MetadataKeys.cs index 9b16c29090b9..ff2582ae8743 100644 --- a/src/Tasks/Common/MetadataKeys.cs +++ b/src/Tasks/Common/MetadataKeys.cs @@ -50,5 +50,8 @@ internal static class MetadataKeys // Publish Target Manifest public const string RuntimeStoreManifestNames = "RuntimeStoreManifestNames"; + + // Conflict Resolution + public const string OverridenPackages = "OverridenPackages"; } } diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs index 2bd4cf31a0f4..1365ba767ae8 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAConflictResolver.cs @@ -3,13 +3,12 @@ using System; using System.Collections.Generic; -using System.Text; +using System.Linq; using FluentAssertions; using Microsoft.Build.Framework; -using Microsoft.Extensions.DependencyModel; -using Xunit; using Microsoft.NET.Build.Tasks.ConflictResolution; -using System.Linq; +using Microsoft.NET.Build.Tasks.UnitTests.Mocks; +using Xunit; namespace Microsoft.NET.Build.Tasks.UnitTests { @@ -315,12 +314,73 @@ public void WhenCommitWinnerIsFalseConflictsWithDifferentKeysAreReported() result.UnresolvedConflicts.Should().BeEmpty(); } + [Fact] + public void WhenPackageOverridesAreSpecifiedTheyAreUsed() + { + var systemItem1 = new MockConflictItem("System.Ben") { PackageId = "System.Ben", PackageVersion = new Version("4.3.0") }; + var systemItem2 = new MockConflictItem("System.Immo") { PackageId = "System.Immo", PackageVersion = new Version("4.2.0") }; + var systemItem3 = new MockConflictItem("System.Dave") { PackageId = "System.Dave", PackageVersion = new Version("4.1.0") }; + + var platformItem1 = new MockConflictItem("System.Ben") { PackageId = "Platform", PackageVersion = new Version("2.0.0") }; + var platformItem2 = new MockConflictItem("System.Immo") { PackageId = "Platform", PackageVersion = new Version("2.0.0") }; + var platformItem3 = new MockConflictItem("System.Dave") { PackageId = "Platform", PackageVersion = new Version("2.0.0") }; + + var result = GetConflicts( + new[] { systemItem1, systemItem2, systemItem3, platformItem1, platformItem2, platformItem3 }, + Array.Empty(), + new[] { + new MockTaskItem("Platform", new Dictionary + { + { MetadataKeys.OverridenPackages, "System.Ben|4.3.0;System.Immo|4.3.0;System.Dave|4.3.0" }, + }) + }); + + result.Conflicts.Should().Equal(systemItem1, systemItem2, systemItem3); + result.UnresolvedConflicts.Should().BeEmpty(); + } + + [Fact] + public void WhenAHigherPackageIsUsedPackageOverrideLoses() + { + var platformItem1 = new MockConflictItem("System.Ben") { PackageId = "Platform", PackageVersion = new Version("2.0.0") }; + var platformItem2 = new MockConflictItem("System.Immo") { PackageId = "Platform", PackageVersion = new Version("2.0.0") }; + var platformItem3 = new MockConflictItem("System.Dave") { PackageId = "Platform", PackageVersion = new Version("2.0.0") }; + + var systemItem1 = new MockConflictItem("System.Ben") { PackageId = "System.Ben", PackageVersion = new Version("4.3.0") }; + var systemItem2 = new MockConflictItem("System.Immo") { PackageId = "System.Immo", PackageVersion = new Version("4.2.0") }; + // System.Dave has a higher PackageVersion than the PackageOverride + var systemItem3 = new MockConflictItem("System.Dave") + { + PackageId = "System.Dave", + PackageVersion = new Version("4.4.0"), + AssemblyVersion = new Version(platformItem3.AssemblyVersion.Major + 1, 0) + }; + + var result = GetConflicts( + new[] { systemItem1, systemItem2, systemItem3, platformItem1, platformItem2, platformItem3 }, + Array.Empty(), + new[] { + new MockTaskItem("Platform", new Dictionary + { + { MetadataKeys.OverridenPackages, "System.Ben|4.3.0;System.Immo|4.3.0;System.Dave|4.3.0" }, + }) + }); + + result.Conflicts.Should().Equal(systemItem1, systemItem2, platformItem3); + result.UnresolvedConflicts.Should().BeEmpty(); + } + static ConflictResults GetConflicts(params MockConflictItem[] items) { return GetConflicts(items, Array.Empty()); } - static ConflictResults GetConflicts(MockConflictItem [] itemsToCommit, params MockConflictItem [] itemsNotToCommit) + static ConflictResults GetConflicts(MockConflictItem[] itemsToCommit, params MockConflictItem[] itemsNotToCommit) + { + return GetConflicts(itemsToCommit, itemsNotToCommit, Array.Empty()); + } + + static ConflictResults GetConflicts(MockConflictItem[] itemsToCommit, MockConflictItem[] itemsNotToCommit, ITaskItem[] packageOverrides) { ConflictResults ret = new ConflictResults(); @@ -341,9 +401,9 @@ void UnresolvedConflictHandler(MockConflictItem item) .OrderBy(id => id) .ToArray(); - PackageOverrideResolver packageOverrides = new PackageOverrideResolver(new ITaskItem[] { }); + var overrideResolver = new PackageOverrideResolver(packageOverrides); - var resolver = new ConflictResolver(new PackageRank(packagesForRank), packageOverrides, new MockLog()); + var resolver = new ConflictResolver(new PackageRank(packagesForRank), overrideResolver, new MockLog()); resolver.ResolveConflicts(itemsToCommit, GetItemKey, ConflictHandler, unresolvedConflict: UnresolvedConflictHandler); @@ -366,39 +426,6 @@ class ConflictResults public List UnresolvedConflicts { get; set; } = new List(); } - class MockConflictItem : IConflictItem - { - public MockConflictItem(string name = "System.Ben") - { - Key = name + ".dll"; - AssemblyVersion = new Version("1.0.0.0"); - ItemType = ConflictItemType.Reference; - Exists = true; - FileName = name + ".dll"; - FileVersion = new Version("1.0.0.0"); - PackageId = name; - PackageVersion = new Version("1.0.0"); - DisplayName = name; - } - public string Key { get; set; } - - public Version AssemblyVersion { get; set; } - - public ConflictItemType ItemType { get; set; } - - public bool Exists { get; set; } - - public string FileName { get; set; } - - public Version FileVersion { get; set; } - - public string PackageId { get; set; } - - public Version PackageVersion { get; set; } - - public string DisplayName { get; set; } - } - class MockLog : ILog { public void LogError(string message, params object[] messageArgs) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPackageOverrideResolver.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPackageOverrideResolver.cs new file mode 100644 index 000000000000..7e1b1a1620cb --- /dev/null +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPackageOverrideResolver.cs @@ -0,0 +1,52 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Microsoft.Build.Framework; +using Microsoft.NET.Build.Tasks.ConflictResolution; +using Microsoft.NET.Build.Tasks.UnitTests.Mocks; +using Xunit; + +namespace Microsoft.NET.Build.Tasks.UnitTests +{ + public class GivenAPackageOverrideResolver + { + [Fact] + public void ItMergesPackageOverridesUsingHighestVersion() + { + ITaskItem[] packageOverrides = new[] + { + new MockTaskItem("Platform", new Dictionary + { + { MetadataKeys.OverridenPackages, "System.Ben|4.2.0;System.Immo|4.2.0;System.Livar|4.3.0;System.Dave|4.2.0" } + }), + new MockTaskItem("Platform", new Dictionary + { + { MetadataKeys.OverridenPackages, "System.Ben|4.2.0;System.Immo|4.3.0;System.Livar|4.2.0;System.Nick|4.2.0" } + }) + }; + + var resolver = new PackageOverrideResolver(packageOverrides); + + Assert.Single(resolver.PackageOverrides); + + PackageOverride packageOverride = resolver.PackageOverrides["Platform"]; + Assert.Equal(5, packageOverride.OverridenPackages.Count); + Assert.Equal(new Version(4, 2, 0), packageOverride.OverridenPackages["System.Ben"]); + Assert.Equal(new Version(4, 3, 0), packageOverride.OverridenPackages["System.Immo"]); + Assert.Equal(new Version(4, 3, 0), packageOverride.OverridenPackages["System.Livar"]); + Assert.Equal(new Version(4, 2, 0), packageOverride.OverridenPackages["System.Dave"]); + Assert.Equal(new Version(4, 2, 0), packageOverride.OverridenPackages["System.Nick"]); + } + + [Fact] + public void ItHandlesNullITaskItemArray() + { + var resolver = new PackageOverrideResolver(null); + + Assert.Null(resolver.PackageOverrides); + Assert.Null(resolver.Resolve(new MockConflictItem(), new MockConflictItem())); + } + } +} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/Mocks/MockConflictItem.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/Mocks/MockConflictItem.cs new file mode 100644 index 000000000000..e1d21a791a87 --- /dev/null +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/Mocks/MockConflictItem.cs @@ -0,0 +1,41 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Microsoft.NET.Build.Tasks.ConflictResolution; + +namespace Microsoft.NET.Build.Tasks.UnitTests.Mocks +{ + class MockConflictItem : IConflictItem + { + public MockConflictItem(string name = "System.Ben") + { + Key = name + ".dll"; + AssemblyVersion = new Version("1.0.0.0"); + ItemType = ConflictItemType.Reference; + Exists = true; + FileName = name + ".dll"; + FileVersion = new Version("1.0.0.0"); + PackageId = name; + PackageVersion = new Version("1.0.0"); + DisplayName = name; + } + public string Key { get; set; } + + public Version AssemblyVersion { get; set; } + + public ConflictItemType ItemType { get; set; } + + public bool Exists { get; set; } + + public string FileName { get; set; } + + public Version FileVersion { get; set; } + + public string PackageId { get; set; } + + public Version PackageVersion { get; set; } + + public string DisplayName { get; set; } + } +} From f6a3f8827e97da22c3e9a38ebb84ce92ccd7fd41 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 13 Dec 2017 17:50:08 -0600 Subject: [PATCH 6/6] PR Feedback - fix typo - Add functional test to ensure the conflict resolution optimizations results in the same References. - Adding that test found 3 more packages to add to the default list of package overrides. --- .../Common/ConflictResolution/ConflictItem.cs | 2 +- ...ET.DefaultPackageConflictOverrides.targets | 4 + .../GivenThatWeWantToResolveConflicts.cs | 106 ++++++++++++++++++ .../Commands/GetValuesCommand.cs | 46 ++++---- 4 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToResolveConflicts.cs diff --git a/src/Tasks/Common/ConflictResolution/ConflictItem.cs b/src/Tasks/Common/ConflictResolution/ConflictItem.cs index e2488a5be9e5..c3d05cad024e 100644 --- a/src/Tasks/Common/ConflictResolution/ConflictItem.cs +++ b/src/Tasks/Common/ConflictResolution/ConflictItem.cs @@ -25,7 +25,7 @@ internal interface IConflictItem string PackageId { get; } string DisplayName { get; } - // NOTE: Technically this should be NuGetVersion because System.Version doesn't work with symver. + // NOTE: Technically this should be NuGetVersion because System.Version doesn't work with semver. // However, the only scenarios we need to support this property for in conflict resolution is stable versions // of System packages. PackageVersion will be null if System.Version can't parse the version (i.e. if is pre-release) Version PackageVersion { get; } diff --git a/src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets b/src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets index a1704e17017b..10c52e0c1bd9 100644 --- a/src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets +++ b/src/Tasks/Common/build/Microsoft.NET.DefaultPackageConflictOverrides.targets @@ -33,6 +33,7 @@ Copyright (c) .NET Foundation. All rights reserved. runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0; System.AppContext|4.3.0; + System.Buffers|4.4.0; System.Collections|4.3.0; System.Collections.Concurrent|4.3.0; System.Collections.Immutable|1.4.0; @@ -46,6 +47,7 @@ Copyright (c) .NET Foundation. All rights reserved. System.Data.Common|4.3.0; System.Diagnostics.Contracts|4.3.0; System.Diagnostics.Debug|4.3.0; + System.Diagnostics.DiagnosticSource|4.4.0; System.Diagnostics.FileVersionInfo|4.3.0; System.Diagnostics.Process|4.3.0; System.Diagnostics.StackTrace|4.3.0; @@ -55,6 +57,7 @@ Copyright (c) .NET Foundation. All rights reserved. System.Diagnostics.Tracing|4.3.0; System.Dynamic.Runtime|4.3.0; System.Globalization|4.3.0; + System.Globalization.Calendars|4.3.0; System.Globalization.Extensions|4.3.0; System.IO|4.3.0; System.IO.Compression|4.3.0; @@ -157,6 +160,7 @@ Copyright (c) .NET Foundation. All rights reserved. System.Diagnostics.Tracing|4.3.0; System.Dynamic.Runtime|4.3.0; System.Globalization|4.3.0; + System.Globalization.Calendars|4.3.0; System.Globalization.Extensions|4.3.0; System.IO|4.3.0; System.IO.Compression|4.3.0; diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToResolveConflicts.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToResolveConflicts.cs new file mode 100644 index 000000000000..5eeda7d62c7f --- /dev/null +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToResolveConflicts.cs @@ -0,0 +1,106 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using FluentAssertions; +using Microsoft.NET.TestFramework; +using Microsoft.NET.TestFramework.Assertions; +using Microsoft.NET.TestFramework.Commands; +using Microsoft.NET.TestFramework.ProjectConstruction; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.NET.Build.Tests +{ + public class GivenThatWeWantToResolveConflicts : SdkTest + { + public GivenThatWeWantToResolveConflicts(ITestOutputHelper log) : base(log) + { + } + + [Theory] + [InlineData("netcoreapp2.0")] + [InlineData("netstandard2.0")] + public void The_same_references_are_used_with_or_without_DisableDefaultPackageConflictOverrides(string targetFramework) + { + var defaultProject = new TestProject() + { + Name = "DefaultProject", + TargetFrameworks = targetFramework, + IsSdkProject = true + }; + AddConflictReferences(defaultProject); + GetReferences( + defaultProject, + expectConflicts: false, + references: out List defaultReferences, + referenceCopyLocalPaths: out List defaultReferenceCopyLocalPaths); + + var disableProject = new TestProject() + { + Name = "DisableProject", + TargetFrameworks = targetFramework, + IsSdkProject = true + }; + disableProject.AdditionalProperties.Add("DisableDefaultPackageConflictOverrides", "true"); + AddConflictReferences(disableProject); + GetReferences( + disableProject, + expectConflicts: true, + references: out List disableReferences, + referenceCopyLocalPaths: out List disableReferenceCopyLocalPaths); + + Assert.Equal(defaultReferences, disableReferences); + Assert.Equal(defaultReferenceCopyLocalPaths, disableReferenceCopyLocalPaths); + } + + private void AddConflictReferences(TestProject testProject) + { + foreach (var dependency in ConflictResolutionAssets.ConflictResolutionDependencies) + { + testProject.PackageReferences.Add(new TestPackageReference(dependency.Item1, dependency.Item2)); + } + } + + private void GetReferences(TestProject testProject, bool expectConflicts, out List references, out List referenceCopyLocalPaths) + { + string targetFramework = testProject.TargetFrameworks; + TestAsset tempTestAsset = _testAssetsManager.CreateTestProject(testProject) + .Restore(Log, testProject.Name); + + string projectFolder = Path.Combine(tempTestAsset.TestRoot, testProject.Name); + + var getReferenceCommand = new GetValuesCommand( + Log, + projectFolder, + targetFramework, + "Reference", + GetValuesCommand.ValueType.Item); + getReferenceCommand.DependsOnTargets = "Build"; + var result = getReferenceCommand.Execute("/v:normal").Should().Pass(); + if (expectConflicts) + { + result.And.HaveStdOutMatching("Encountered conflict", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + } + else + { + result.And.NotHaveStdOutMatching("Encountered conflict", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + } + + references = getReferenceCommand.GetValues(); + + var getReferenceCopyLocalPathsCommand = new GetValuesCommand( + Log, + projectFolder, + targetFramework, + "ReferenceCopyLocalPaths", + GetValuesCommand.ValueType.Item); + getReferenceCopyLocalPathsCommand.DependsOnTargets = "Build"; + getReferenceCopyLocalPathsCommand.Execute().Should().Pass(); + + referenceCopyLocalPaths = getReferenceCopyLocalPathsCommand.GetValues(); + } + } +} diff --git a/src/Tests/Microsoft.NET.TestFramework/Commands/GetValuesCommand.cs b/src/Tests/Microsoft.NET.TestFramework/Commands/GetValuesCommand.cs index e354ad9065d8..6646ccfa85cc 100644 --- a/src/Tests/Microsoft.NET.TestFramework/Commands/GetValuesCommand.cs +++ b/src/Tests/Microsoft.NET.TestFramework/Commands/GetValuesCommand.cs @@ -102,33 +102,39 @@ public List GetValues() public List<(string value, Dictionary metadata)> GetValuesWithMetadata() { - var ret = new List<(string value, Dictionary metadata)>(); - string outputFilename = $"{_valueName}Values.txt"; var outputDirectory = GetOutputDirectory(_targetFramework, Configuration ?? "Debug"); + string fullFileName = Path.Combine(outputDirectory.FullName, outputFilename); - return File.ReadAllLines(Path.Combine(outputDirectory.FullName, outputFilename)) - .Where(line => !string.IsNullOrWhiteSpace(line)) - .Select(line => - { - if (!MetadataNames.Any()) - { - return (value: line, metadata: new Dictionary()); - } - else + if (File.Exists(fullFileName)) + { + return File.ReadAllLines(fullFileName) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Select(line => { - var fields = line.Split('\t'); - - var dict = new Dictionary(); - for (int i=0; i()); } + else + { + var fields = line.Split('\t'); + + var dict = new Dictionary(); + for (int i = 0; i < MetadataNames.Count; i++) + { + dict[MetadataNames[i]] = fields[i + 1]; + } - return (value: fields[0], metadata: dict); - } - }) - .ToList(); + return (value: fields[0], metadata: dict); + } + }) + .ToList(); + } + else + { + return new List<(string value, Dictionary metadata)>(); + } } } }