-
Notifications
You must be signed in to change notification settings - Fork 693
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
Changes from 23 commits
e3e150f
e25192e
dbb4e78
3512c8a
5bac353
7b06260
32dd874
b41d9d3
d2d095a
aff0915
fd2954d
2bb5484
bac6ebd
206783d
41d1a6d
d770dd7
96c32f1
df69083
fda157f
92da3ce
6e32f5d
91c45b6
cac363e
1ab17fc
8ec53f8
355759e
7011324
bae7e09
f8bfc05
8e1fbbb
05f56da
7c68020
3af5cee
9319b37
38ed522
dfca74f
0fed85f
bfb6c41
154fe93
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
|
@@ -36,21 +38,50 @@ 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 | ||
.TargetFrameworks | ||
.First(tfi => tfi.FrameworkName == framework); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use packageSpec.GetTargetFramework, it should have this optimization already, and it will ensure that if a comparer is needed that we already have it |
||
|
||
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> | ||
|
@@ -85,14 +116,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> | ||
|
@@ -107,5 +152,38 @@ public bool Contains(NuGetLogCode code, string libraryId, NuGetFramework framewo | |
libraryIdsAndFrameworks.TryGetValue(libraryId, out var frameworkSet) && | ||
frameworkSet.Contains(framework); | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
var hashCode = new HashCodeCombiner(); | ||
|
||
// Add a constant hash for all objects | ||
hashCode.AddObject(1); | ||
|
||
return hashCode.CombinedHash; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just return 1 if this isn't changing? |
||
} | ||
|
||
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.SetEqualWithNullCheck(sv2, ov2))); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
// 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.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using NuGet.Common; | ||
using NuGet.ProjectModel; | ||
using NuGet.Shared; | ||
|
||
namespace NuGet.Commands | ||
{ | ||
|
@@ -14,12 +17,66 @@ public class RestoreCollectorLogger : LoggerBase, ICollectorLogger | |
private readonly ILogger _innerLogger; | ||
private readonly ConcurrentQueue<IRestoreLogMessage> _errors; | ||
private readonly bool _hideWarningsAndErrors; | ||
private IEnumerable<RestoreTargetGraph> _restoreTargetGraphs; | ||
private PackageSpec _projectSpec; | ||
private WarningPropertiesCollection _transitiveWarningPropertiesCollection; | ||
|
||
public string ProjectPath => _projectSpec?.RestoreMetadata?.ProjectPath; | ||
|
||
public IEnumerable<IRestoreLogMessage> Errors => _errors.ToArray(); | ||
|
||
public WarningPropertiesCollection WarningPropertiesCollection { get; set; } | ||
|
||
public string ProjectPath { get; set; } | ||
public WarningPropertiesCollection ProjectWarningPropertiesCollection { get; set; } | ||
|
||
public WarningPropertiesCollection TransitiveWarningPropertiesCollection | ||
{ | ||
get | ||
{ | ||
if (_transitiveWarningPropertiesCollection == null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🥇 |
||
{ | ||
// Populate TransitiveWarningPropertiesCollection only if it is null and we have RestoreTargetGraphs. | ||
// This will happen at most once and only if we have the project spec with restore metadata. | ||
if (_restoreTargetGraphs != null && | ||
_restoreTargetGraphs.Any() && | ||
_projectSpec != null && | ||
_projectSpec.RestoreMetadata != null) | ||
{ | ||
TransitiveWarningPropertiesCollection = TransitiveNoWarnUtils.CreateTransitiveWarningPropertiesCollection( | ||
_restoreTargetGraphs, | ||
_projectSpec); | ||
} | ||
} | ||
|
||
return _transitiveWarningPropertiesCollection; | ||
} | ||
|
||
set => _transitiveWarningPropertiesCollection = value; | ||
} | ||
|
||
/// <summary> | ||
/// Stores a reference to PackageSpec for the project from the restore request. | ||
/// This are used to generate the warning properties for the project. | ||
/// </summary> | ||
/// <param name="projectSpec">PackageSpec to be stored for reference.</param> | ||
public void ApplyRestoreInputs(PackageSpec projectSpec) | ||
{ | ||
_projectSpec = projectSpec; | ||
|
||
ProjectWarningPropertiesCollection = new WarningPropertiesCollection( | ||
projectSpec.RestoreMetadata?.ProjectWideWarningProperties, | ||
PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(projectSpec), | ||
projectSpec.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly() | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Stores a reference to RestoreTargetGraphs from the restore output. | ||
/// These graphs are used to generate the transitive warning properties. | ||
/// </summary> | ||
/// <param name="restoreTargetGraphs">RestoreTargetGraphs to be stored for reference.</param> | ||
public void ApplyRestoreOutput(IEnumerable<RestoreTargetGraph> restoreTargetGraphs) | ||
{ | ||
_restoreTargetGraphs = restoreTargetGraphs; | ||
} | ||
|
||
/// <summary> | ||
/// Initializes an instance of the <see cref="RestoreCollectorLogger"/>, while still | ||
|
@@ -70,8 +127,8 @@ public RestoreCollectorLogger(ILogger innerLogger) | |
|
||
public void Log(IRestoreLogMessage message) | ||
{ | ||
// This will be true only when the Message is a Warning and should be suppressed. | ||
if (WarningPropertiesCollection == null || !WarningPropertiesCollection.ApplyWarningProperties(message)) | ||
// This will be true if the message is not or warning or it is not suppressed. | ||
if (!IsWarningSuppressed(message)) | ||
{ | ||
if (string.IsNullOrEmpty(message.FilePath)) | ||
{ | ||
|
@@ -92,9 +149,8 @@ public void Log(IRestoreLogMessage message) | |
|
||
public Task LogAsync(IRestoreLogMessage message) | ||
{ | ||
|
||
// This will be true only when the Message is a Warning and should be suppressed. | ||
if (WarningPropertiesCollection == null || !WarningPropertiesCollection.ApplyWarningProperties(message)) | ||
// This will be true if the message is not or warning or it is not suppressed. | ||
if (!IsWarningSuppressed(message)) | ||
{ | ||
if (string.IsNullOrEmpty(message.FilePath)) | ||
{ | ||
|
@@ -139,7 +195,26 @@ protected bool DisplayMessage(IRestoreLogMessage message) | |
else | ||
{ | ||
return (message.Level >= VerbosityLevel); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// This method checks if at least one of the warning properties collections is not null and it suppresses the warning. | ||
/// </summary> | ||
/// <param name="message">IRestoreLogMessage to be logged.</param> | ||
/// <returns>bool indicating if the message should be suppressed.</returns> | ||
private bool IsWarningSuppressed(IRestoreLogMessage message) | ||
{ | ||
|
||
if (ProjectWarningPropertiesCollection != null && ProjectWarningPropertiesCollection.ApplyWarningProperties(message)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: |
||
{ | ||
return true; | ||
} | ||
else | ||
{ | ||
// Use transitive warning properties only if the project does not suppress the warning. | ||
return TransitiveWarningPropertiesCollection != null && TransitiveWarningPropertiesCollection.ApplyWarningProperties(message); | ||
} | ||
} | ||
|
||
private static IRestoreLogMessage ToRestoreLogMessage(ILogMessage message) | ||
|
@@ -154,4 +229,4 @@ private static IRestoreLogMessage ToRestoreLogMessage(ILogMessage message) | |
return restoreLogMessage; | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make equals plural to match the other methods