Skip to content
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

Add support for transitive NoWarn properties from project references #1672

Merged
merged 39 commits into from
Aug 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e3e150f
temp status
Aug 4, 2017
e25192e
working through merging warning properties
Aug 7, 2017
dbb4e78
Adding better quality across and changing tests
Aug 8, 2017
3512c8a
checkpoint for correctly extracting transitive no warn from a basic case
Aug 8, 2017
5bac353
Checkpoint with a functional case (A->B->C->Pkg) and lazy initialization
Aug 9, 2017
7b06260
Adding code to deal with path exclusion logic and fixing test breaks
Aug 9, 2017
32dd874
making TransitiveNoWarnUtils conditional on projectspec and restoreme…
Aug 9, 2017
b41d9d3
Adding scenario tests
Aug 9, 2017
d2d095a
addressing some PR feedback
Aug 14, 2017
aff0915
Addressing warning properties related PR feedback
Aug 21, 2017
fd2954d
Addressing feedback on TransitiveNoWarnUtil
Aug 21, 2017
2bb5484
Adding unit tests for TransitiveNoWarnUtils
Aug 22, 2017
bac6ebd
Adding more unit tests
Aug 22, 2017
206783d
Adding unit tests related to Merging warning properties and dependenc…
Aug 23, 2017
41d1a6d
Adding a test project generator
Aug 23, 2017
d770dd7
Revert "Adding a test project generator"
Aug 24, 2017
96c32f1
Changing to less data per node
Aug 24, 2017
df69083
Adding 1. merging into path 2. fixing seen.add
Aug 24, 2017
fda157f
removing merging into path
Aug 24, 2017
92da3ce
perf improvements working with Justin
Aug 26, 2017
6e32f5d
fixing broken functional tests
Aug 26, 2017
91c45b6
fixing broken unit tests
Aug 26, 2017
cac363e
cleaning up an equals call
Aug 26, 2017
1ab17fc
IsSubSet check
emgarten Aug 26, 2017
8ec53f8
Use null or existing dictionary when possible
emgarten Aug 26, 2017
355759e
Optimize merges to keep the same objects if possible
emgarten Aug 26, 2017
7011324
Removing unused code
emgarten Aug 26, 2017
bae7e09
SubSet check fix
emgarten Aug 26, 2017
f8bfc05
Track only NoWarn codes that have not yet been walked
emgarten Aug 26, 2017
8e1fbbb
Fixing AddToSeen and test break
Aug 28, 2017
05f56da
fixing broken unit test
Aug 28, 2017
7c68020
delaying transitive initialization further
Aug 28, 2017
3af5cee
Adding more functional tests
Aug 28, 2017
9319b37
Addressing PR comments
Aug 28, 2017
38ed522
Excluding Apex test project from run test projects as apex package is…
Aug 28, 2017
dfca74f
adding func test for incompatible project reference
Aug 28, 2017
0fed85f
Adding preference order for properties based on offline discussion
Aug 29, 2017
bfb6c41
Adding few more functional tests
Aug 29, 2017
154fe93
addressing PR feedback
Aug 29, 2017
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
39 changes: 38 additions & 1 deletion build/Shared/EqualityUtility.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -59,6 +59,37 @@ internal static bool SequenceEqualWithNullCheck<T>(
return self.SequenceEqual(other, comparer);
}

/// <summary>
/// Compares two sets for equality, allowing either sequence to be null.
/// If one is null, both have to be null for equality.
/// </summary>
internal static bool SetEqualsWithNullCheck<T>(
this ISet<T> self,
ISet<T> other,
IEqualityComparer<T> comparer = null)
{
bool identityEquals;
if (TryIdentityEquals(self, other, out identityEquals))
{
return identityEquals;
}

// Verify they could be equal by count
if (self.Count != other.Count)
{
return false;
}

if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}

var set = new HashSet<T>(self, comparer);

return set.SetEquals(other);
}

internal static bool DictionaryEquals<TKey, TValue>(
IDictionary<TKey, TValue> self,
IDictionary<TKey, TValue> other,
Expand All @@ -74,6 +105,12 @@ internal static bool DictionaryEquals<TKey, TValue>(
return identityEquals;
}

// Verify they could be equal by count
if (self.Count != other.Count)
{
return false;
}

if (!self.Keys.OrderedEquals(
other.Keys,
s => s,
Expand Down
29 changes: 28 additions & 1 deletion build/Shared/SharedExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,36 @@ public static List<T> AsList<T>(this IEnumerable<T> enumerable)
return new List<T>(enumerable);
}

/// <summary>
/// Return the ISet as a HashSet of T, copying if required. Optimized for common case where it is a HashSet of T.
/// Avoid mutating the return value.
/// </summary>
public static HashSet<T> AsHashSet<T>(this ISet<T> enumerable, IEqualityComparer<T> comparer = null)
{
if (enumerable == null)
{
return null;
}

var set = enumerable as HashSet<T>;
if (set != null)
{
return set;
}
else
{
if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}

return new HashSet<T>(enumerable, comparer);
}
}

public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach (T item in enumeration)
foreach (var item in enumeration)
{
action(item);
}
Expand Down
3 changes: 2 additions & 1 deletion build/common.project.props
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@
<!-- All projects in the repository -->
<ItemGroup Condition=" '$(IsXPlat)' != 'true' ">
<SolutionProjects Include="$(RepositoryRootDirectory)test\*\*\*.csproj"
Exclude="$(RepositoryRootDirectory)test\EndToEnd\*\*.csproj"
Exclude="$(RepositoryRootDirectory)test\EndToEnd\*\*.csproj;
$(RepositoryRootDirectory)test\NuGet.Tests.Apex\*\*.csproj"
Condition=" '$(ExcludeTestProjects)' != 'true' " />

<SolutionProjects Include="$(RepositoryRootDirectory)src\*\*\*.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public async Task<int> ExecuteCommand(PackageReferenceArgs packageReferenceArgs,
}
// Ignore the graphs with RID
else if (compatibleFrameworks.Count ==
restorePreviewResult.Result.CompatibilityCheckResults.Where(r => r.Graph.RuntimeIdentifier == null).Count())
restorePreviewResult.Result.CompatibilityCheckResults.Where(r => string.IsNullOrEmpty(r.Graph.RuntimeIdentifier)).Count())
{
// Package is compatible with all the project TFMs
// Add an unconditional package reference to the project
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using NuGet.Common;
using NuGet.Frameworks;
using NuGet.ProjectModel;
using NuGet.Shared;

namespace NuGet.Commands
{

/// <summary>
/// Contains Package specific properties for Warnings.
/// </summary>
public class PackageSpecificWarningProperties
public class PackageSpecificWarningProperties : IEquatable <PackageSpecificWarningProperties>
{

/// <summary>
/// Contains Package specific No warn properties.
/// NuGetLogCode -> LibraryId -> Set of Frameworks.
/// </summary>
private IDictionary<NuGetLogCode, IDictionary<string, ISet<NuGetFramework>>> Properties;
public IDictionary<NuGetLogCode, IDictionary<string, ISet<NuGetFramework>>> Properties { get; private set; }

/// <summary>
/// Extracts PackageSpecific WarningProperties from a PackageSpec
Expand All @@ -36,21 +38,48 @@ public static PackageSpecificWarningProperties CreatePackageSpecificWarningPrope
{
foreach (var framework in packageSpec.TargetFrameworks)
{
warningProperties.AddRange(dependency.NoWarn, dependency.Name, framework.FrameworkName);
warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework.FrameworkName);
}
}

foreach (var framework in packageSpec.TargetFrameworks)
{
foreach (var dependency in framework.Dependencies)
{
warningProperties.AddRange(dependency.NoWarn, dependency.Name, framework.FrameworkName);
warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework.FrameworkName);
}
}

return warningProperties;
}

/// <summary>
/// Extracts PackageSpecific WarningProperties from a PackageSpec for a specific NuGetFramework
/// </summary>
/// <param name="packageSpec">PackageSpec containing the Dependencies with WarningProperties</param>
/// <param name="framework">NuGetFramework for which the properties should be assessed.</param>
/// <returns>PackageSpecific WarningProperties extracted from a PackageSpec for a specific NuGetFramework</returns>
public static PackageSpecificWarningProperties CreatePackageSpecificWarningProperties(PackageSpec packageSpec,
NuGetFramework framework)
{
// NuGetLogCode -> LibraryId -> Set of Frameworks.
var warningProperties = new PackageSpecificWarningProperties();

foreach (var dependency in packageSpec.Dependencies)
{
warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework);
}

var targetFrameworkInformation = packageSpec.GetTargetFramework(framework);

foreach (var dependency in targetFrameworkInformation.Dependencies)
{
warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework);
}

return warningProperties;
}

/// <summary>
/// Adds a NuGetLogCode into the NoWarn Set for the specified library Id and target graph.
/// </summary>
Expand Down Expand Up @@ -85,14 +114,28 @@ public void Add(NuGetLogCode code, string libraryId, NuGetFramework framework)
/// <param name="codes">IEnumerable of NuGetLogCode for which no warning should be thrown.</param>
/// <param name="libraryId">Library for which no warning should be thrown.</param>
/// <param name="framework">Target graph for which no warning should be thrown.</param>
public void AddRange(IEnumerable<NuGetLogCode> codes, string libraryId, NuGetFramework framework)
public void AddRangeOfCodes(IEnumerable<NuGetLogCode> codes, string libraryId, NuGetFramework framework)
{
foreach (var code in codes)
{
Add(code, libraryId, framework);
}
}

/// <summary>
/// Adds a list of NuGetLogCode into the NoWarn Set for the specified library Id and target graph.
/// </summary>
/// <param name="code">NuGetLogCode for which no warning should be thrown.</param>
/// <param name="libraryId">Library for which no warning should be thrown.</param>
/// <param name="frameworks">IEnumerable of Target graph for which no warning should be thrown.</param>
public void AddRangeOfFrameworks(NuGetLogCode code, string libraryId, IEnumerable<NuGetFramework> frameworks)
{
foreach (var framework in frameworks)
{
Add(code, libraryId, framework);
}
}

/// <summary>
/// Checks if a NugetLogCode is part of the NoWarn list for the specified library Id and target graph.
/// </summary>
Expand All @@ -107,5 +150,34 @@ public bool Contains(NuGetLogCode code, string libraryId, NuGetFramework framewo
libraryIdsAndFrameworks.TryGetValue(libraryId, out var frameworkSet) &&
frameworkSet.Contains(framework);
}

public override int GetHashCode()
{
// return a constant hash for all objects since the contents of Properties are mutable
return 1;
}

public override bool Equals(object obj)
{
return Equals(obj as PackageSpecificWarningProperties);
}

public bool Equals(PackageSpecificWarningProperties other)
{
if (other == null)
{
return false;
}

if (ReferenceEquals(this, other))
{
return true;
}

return EqualityUtility.DictionaryEquals(
Properties,
other.Properties,
(sv1, ov1) => EqualityUtility.DictionaryEquals(sv1, ov1, (sv2, ov2) => EqualityUtility.SetEqualsWithNullCheck(sv2, ov2)));
}
}
}
Loading