Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ public LockFile CreateLockFile(LockFile previousLockFile,
.OrderBy(graph => graph.Framework.ToString(), StringComparer.Ordinal)
.ThenBy(graph => graph.RuntimeIdentifier, StringComparer.Ordinal))
{
var librariesWithMonoAndroidWarnings = new HashSet<LibraryIdentity>();

var target = lockFile.Version >= LockFileFormat.AliasedVersion ?
new LockFileTarget
{
Expand All @@ -186,6 +188,8 @@ public LockFile CreateLockFile(LockFile previousLockFile,
&& (target.TargetFramework is FallbackFramework
|| target.TargetFramework is AssetTargetFallbackFramework);

bool checkMonoAndroidDeprecation = MonoAndroidDeprecation.ShouldCheck(project, targetGraph.Framework);

foreach (var graphItem in targetGraph.Flattened.OrderBy(x => x.Key))
{
var library = graphItem.Key;
Expand Down Expand Up @@ -226,7 +230,7 @@ public LockFile CreateLockFile(LockFile previousLockFile,
var package = packageInfo.Package;
var libraryDependency = tfi.Dependencies.FirstOrDefault(e => e.Name.Equals(library.Name, StringComparison.OrdinalIgnoreCase));

(LockFileTargetLibrary targetLibrary, bool usedFallbackFramework) = LockFileUtils.CreateLockFileTargetLibrary(
(LockFileTargetLibrary targetLibrary, bool usedFallbackFramework, NuGetFramework compileAssetFramework, NuGetFramework runtimeAssetFramework) = LockFileUtils.CreateLockFileTargetLibrary(
libraryDependency?.Aliases,
libraries[ValueTuple.Create(library.Name, library.Version)],
package,
Expand Down Expand Up @@ -280,6 +284,29 @@ public LockFile CreateLockFile(LockFile previousLockFile,
librariesWithWarnings.Add(library);
}
}

// Log NU1703 warning if the package uses the deprecated MonoAndroid framework
if (checkMonoAndroidDeprecation
&& !librariesWithMonoAndroidWarnings.Contains(library)
&& (MonoAndroidDeprecation.IsMonoAndroidFramework(compileAssetFramework)
|| MonoAndroidDeprecation.IsMonoAndroidFramework(runtimeAssetFramework)))
{
var message = string.Format(CultureInfo.CurrentCulture,
Strings.Warning_MonoAndroidFrameworkDeprecated,
library.Name,
library.Version);

var logMessage = RestoreLogMessage.CreateWarning(
NuGetLogCode.NU1703,
message,
library.Name,
targetGraph.TargetGraphName);

_logger.Log(logMessage);

// only log the warning once per library
librariesWithMonoAndroidWarnings.Add(library);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class LockFileBuilderCache
private readonly ConcurrentDictionary<CriteriaKey, List<(List<SelectionCriteria>, bool)>> _criteriaSets =
new();

private readonly ConcurrentDictionary<(CriteriaKey, string path, string aliases, LibraryIncludeFlags, int dependencyCount), Lazy<(LockFileTargetLibrary, bool)>> _lockFileTargetLibraryCache =
private readonly ConcurrentDictionary<(CriteriaKey, string path, string aliases, LibraryIncludeFlags, int dependencyCount), Lazy<(LockFileTargetLibrary, bool, NuGetFramework, NuGetFramework)>> _lockFileTargetLibraryCache =
new();

/// <summary>
Expand Down Expand Up @@ -106,7 +106,7 @@ public ContentItemCollection GetContentItems(LockFileLibrary library, LocalPacka
/// <summary>
/// Try to get a LockFileTargetLibrary from the cache.
/// </summary>
internal (LockFileTargetLibrary, bool) GetLockFileTargetLibrary(RestoreTargetGraph graph, NuGetFramework framework, LocalPackageInfo localPackageInfo, string aliases, LibraryIncludeFlags libraryIncludeFlags, List<LibraryDependency> dependencies, Func<(LockFileTargetLibrary, bool)> valueFactory)
internal (LockFileTargetLibrary, bool, NuGetFramework, NuGetFramework) GetLockFileTargetLibrary(RestoreTargetGraph graph, NuGetFramework framework, LocalPackageInfo localPackageInfo, string aliases, LibraryIncludeFlags libraryIncludeFlags, List<LibraryDependency> dependencies, Func<(LockFileTargetLibrary, bool, NuGetFramework, NuGetFramework)> valueFactory)
{
// Comparing RuntimeGraph for equality is very expensive,
// so in case of a request where the RuntimeGraph is not empty we avoid using the cache.
Expand All @@ -117,7 +117,7 @@ public ContentItemCollection GetContentItems(LockFileLibrary library, LocalPacka
var criteriaKey = new CriteriaKey(graph.TargetGraphName, framework);
var packagePath = localPackageInfo.ExpandedPath;
return _lockFileTargetLibraryCache.GetOrAdd((criteriaKey, packagePath, aliases, libraryIncludeFlags, dependencies.Count),
key => new Lazy<(LockFileTargetLibrary, bool)>(valueFactory)).Value;
key => new Lazy<(LockFileTargetLibrary, bool, NuGetFramework, NuGetFramework)>(valueFactory)).Value;
}

private class CriteriaKey : IEquatable<CriteriaKey>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 NuGet.Frameworks;
using NuGet.ProjectModel;

namespace NuGet.Commands
{
/// <summary>
/// Detects when a package uses the deprecated MonoAndroid framework instead of net6.0-android or later.
/// This warning is gated on .NET 11 SDK (SdkAnalysisLevel >= 11.0.100) and targeting net11.0-android or later.
/// </summary>
internal static class MonoAndroidDeprecation
{
/// <summary>
/// Determines whether the MonoAndroid deprecation check should be performed for the given project and target framework.
/// </summary>
/// <param name="project">The package spec containing restore metadata.</param>
/// <param name="framework">The target framework of the current graph.</param>
/// <returns>True if the deprecation check should be performed.</returns>
internal static bool ShouldCheck(PackageSpec project, NuGetFramework framework)
{
if (project.RestoreMetadata == null)
{
return false;
}

// Gate on SDK analysis level >= 11.0.100
if (!SdkAnalysisLevelMinimums.IsEnabled(
project.RestoreMetadata.SdkAnalysisLevel,
project.RestoreMetadata.UsingMicrosoftNETSdk,
SdkAnalysisLevelMinimums.V11_0_100))
{
return false;
}

// Only check for .NETCoreApp frameworks targeting android with version >= 11.0
return StringComparer.OrdinalIgnoreCase.Equals(framework.Framework, FrameworkConstants.FrameworkIdentifiers.NetCoreApp)
&& framework.Version.Major >= 11
&& framework.HasPlatform
&& framework.Platform.Equals("android", StringComparison.OrdinalIgnoreCase);
Comment thread
nkolev92 marked this conversation as resolved.
}

/// <summary>
/// Checks whether the given framework is a MonoAndroid framework.
/// </summary>
/// <param name="framework">The framework to check, or null.</param>
/// <returns>True if the framework uses the MonoAndroid framework identifier.</returns>
internal static bool IsMonoAndroidFramework(NuGetFramework framework)
{
return framework != null
&& StringComparer.OrdinalIgnoreCase.Equals(
framework.Framework,
FrameworkConstants.FrameworkIdentifiers.MonoAndroid);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static LockFileTargetLibrary CreateLockFileTargetLibrary(
RestoreTargetGraph targetGraph,
LibraryIncludeFlags dependencyType)
{
var (lockFileTargetLibrary, _) = CreateLockFileTargetLibrary(
var (lockFileTargetLibrary, _, _, _) = CreateLockFileTargetLibrary(
aliases: null,
library,
package,
Expand All @@ -57,8 +57,8 @@ public static LockFileTargetLibrary CreateLockFileTargetLibrary(
/// <param name="targetFrameworkOverride">The original framework if the asset selection is happening for a fallback framework.</param>
/// <param name="dependencies">The dependencies of this package.</param>
/// <param name="cache">The lock file build cache.</param>
/// <returns>The LockFileTargetLibrary, and whether a fallback framework criteria was used to select it.</returns>
internal static (LockFileTargetLibrary, bool) CreateLockFileTargetLibrary(
/// <returns>The LockFileTargetLibrary, whether a fallback framework criteria was used to select it, the framework selected for compile assets, and the framework selected for runtime assets.</returns>
internal static (LockFileTargetLibrary, bool, NuGetFramework, NuGetFramework) CreateLockFileTargetLibrary(
string aliases,
LockFileLibrary library,
LocalPackageInfo package,
Expand All @@ -75,6 +75,8 @@ internal static (LockFileTargetLibrary, bool) CreateLockFileTargetLibrary(
() =>
{
LockFileTargetLibrary lockFileLib = null;
NuGetFramework compileAssetFramework = null;
NuGetFramework runtimeAssetFramework = null;
// This will throw an appropriate error if the nuspec is missing
var nuspec = package.Nuspec;

Expand All @@ -86,7 +88,7 @@ internal static (LockFileTargetLibrary, bool) CreateLockFileTargetLibrary(

for (var i = 0; i < orderedCriteriaSets.Count; i++)
{
lockFileLib = CreateLockFileTargetLibrary(aliases, library, package, targetGraph.Conventions, dependencyType,
(lockFileLib, compileAssetFramework, runtimeAssetFramework) = CreateLockFileTargetLibrary(aliases, library, package, targetGraph.Conventions, dependencyType,
framework, runtimeIdentifier, contentItems, nuspec, packageTypes, orderedCriteriaSets[i].orderedCriteria);
// Check if compatible assets were found.
// If no compatible assets were found and this is the last check
Expand All @@ -108,7 +110,7 @@ internal static (LockFileTargetLibrary, bool) CreateLockFileTargetLibrary(

lockFileLib.Freeze();

return (lockFileLib, fallbackUsed);
return (lockFileLib, fallbackUsed, compileAssetFramework, runtimeAssetFramework);
});
}

Expand Down Expand Up @@ -165,7 +167,7 @@ private static void ApplyAliases(string aliases, LockFileItem item)
/// <summary>
/// Populate assets for a <see cref="LockFileLibrary"/>.
/// </summary>
internal static LockFileTargetLibrary CreateLockFileTargetLibrary(
internal static (LockFileTargetLibrary lockFileLib, NuGetFramework compileAssetFramework, NuGetFramework runtimeAssetFramework) CreateLockFileTargetLibrary(
string aliases,
LockFileLibrary library,
LocalPackageInfo package,
Expand Down Expand Up @@ -198,13 +200,16 @@ internal static LockFileTargetLibrary CreateLockFileTargetLibrary(
orderedCriteria,
contentItems,
applyAliases,
out NuGetFramework compileFramework,
managedCodeConventions.Patterns.CompileRefAssemblies,
managedCodeConventions.Patterns.CompileLibAssemblies);

// Runtime
lockFileLib.RuntimeAssemblies = GetLockFileItems(
orderedCriteria,
contentItems,
additionalAction: null,
out NuGetFramework runtimeFramework,
managedCodeConventions.Patterns.RuntimeAssemblies);

// Embed
Expand Down Expand Up @@ -242,7 +247,7 @@ internal static LockFileTargetLibrary CreateLockFileTargetLibrary(
// Apply filters from the <references> node in the nuspec
ApplyReferenceFilter(lockFileLib, framework, nuspec);

return lockFileLib;
return (lockFileLib, compileFramework, runtimeFramework);
}

private static void AddMSBuildAssets(
Expand Down Expand Up @@ -659,15 +664,17 @@ private static List<LockFileItem> ConvertToProjectPaths(
}

/// <summary>
/// Create lock file items for the best matching group.
/// Create lock file items for the best matching group, and optionally output the selected framework.
/// </summary>
/// <remarks>Enumerate this once after calling.</remarks>
private static IList<LockFileItem> GetLockFileItems(
List<SelectionCriteria> criteria,
ContentItemCollection items,
Action<LockFileItem> additionalAction,
out NuGetFramework selectedFramework,
params PatternSet[] patterns)
{
selectedFramework = null;
List<LockFileItem> result = null;
// Loop through each criteria taking the first one that matches one or more items.
foreach (var managedCriteria in criteria)
Expand All @@ -678,6 +685,12 @@ private static IList<LockFileItem> GetLockFileItems(

if (group != null)
{
if (group.Properties.TryGetValue(
ManagedCodeConventions.PropertyNames.TargetFrameworkMoniker, out object tfmObj))
{
selectedFramework = tfmObj as NuGetFramework;
}

result = new(group.Items.Count);
foreach (var item in group.Items.NoAllocEnumerate())
{
Expand Down Expand Up @@ -711,7 +724,7 @@ private static IList<LockFileItem> GetLockFileItems(
ContentItemCollection items,
params PatternSet[] patterns)
{
return GetLockFileItems(criteria, items, additionalAction: null, patterns);
return GetLockFileItems(criteria, items, additionalAction: null, out _, patterns);
}

/// <summary>
Expand Down
9 changes: 9 additions & 0 deletions src/NuGet.Core/NuGet.Commands/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/NuGet.Core/NuGet.Commands/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@
<data name="Log_ImportsFallbackWarning" xml:space="preserve">
<value>Package '{0}' was restored using '{1}' instead of the project target framework '{2}'. This package may not be fully compatible with your project.</value>
</data>
<data name="Warning_MonoAndroidFrameworkDeprecated" xml:space="preserve">
<value>Package '{0}' {1} uses the deprecated MonoAndroid framework instead of 'net6.0-android' or later. Consider upgrading to a newer version of this package or contacting the package author.</value>
<comment>{0} - package id
{1} - package version</comment>
</data>
<data name="Log_CycleDetected" xml:space="preserve">
<value>Cycle detected.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ internal static class SdkAnalysisLevelMinimums
/// <summary>
/// Minimum SDK Analysis Level required for:
/// <list type="bullet">
/// <item>warning when packages use the deprecated MonoAndroid framework</item>
/// <item>error when TargetFramework alias contains non-ASCII characters</item>
/// </list>
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/NuGet.Core/NuGet.Commands/xlf/Strings.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,12 @@ NuGet vyžaduje zdroje HTTPS. Další informace najdete na https://aka.ms/nuget-
<target state="translated">{0} neposkytuje inkluzivní dolní mez pro závislost {1}. Místo toho bylo přeloženo: {2}.</target>
<note />
</trans-unit>
<trans-unit id="Warning_MonoAndroidFrameworkDeprecated">
<source>Package '{0}' {1} uses the deprecated MonoAndroid framework instead of 'net6.0-android' or later. Consider upgrading to a newer version of this package or contacting the package author.</source>
<target state="new">Package '{0}' {1} uses the deprecated MonoAndroid framework instead of 'net6.0-android' or later. Consider upgrading to a newer version of this package or contacting the package author.</target>
<note>{0} - package id
{1} - package version</note>
</trans-unit>
<trans-unit id="Warning_PackageWithKnownVulnerability">
<source>Package '{0}' {1} has a known {2} severity vulnerability, {3}</source>
<target state="translated">Balíček „{0}“ {1} má známé {2} ohrožení zabezpečení závažnosti, {3}</target>
Expand Down
6 changes: 6 additions & 0 deletions src/NuGet.Core/NuGet.Commands/xlf/Strings.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,12 @@ NuGet erfordert HTTPS-Quellen. Weitere Informationen finden Sie unter https://ak
<target state="translated">{0} stellt keine inklusive untere Grenze für Abhängigkeiten {1} bereit. {2} wurde stattdessen aufgelöst.</target>
<note />
</trans-unit>
<trans-unit id="Warning_MonoAndroidFrameworkDeprecated">
<source>Package '{0}' {1} uses the deprecated MonoAndroid framework instead of 'net6.0-android' or later. Consider upgrading to a newer version of this package or contacting the package author.</source>
<target state="new">Package '{0}' {1} uses the deprecated MonoAndroid framework instead of 'net6.0-android' or later. Consider upgrading to a newer version of this package or contacting the package author.</target>
<note>{0} - package id
{1} - package version</note>
</trans-unit>
<trans-unit id="Warning_PackageWithKnownVulnerability">
<source>Package '{0}' {1} has a known {2} severity vulnerability, {3}</source>
<target state="translated">Das Paket "{0}" {1} weist eine bekannte {2} Schweregrad-Sicherheitsanfälligkeit auf, {3}.</target>
Expand Down
6 changes: 6 additions & 0 deletions src/NuGet.Core/NuGet.Commands/xlf/Strings.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,12 @@ NuGet requiere orígenes HTTPS. Consulte https://aka.ms/nuget-https-everywhere p
<target state="translated">{0} no proporciona un límite inferior inclusivo para la dependencia {1}. {2} se resolvió en su lugar.</target>
<note />
</trans-unit>
<trans-unit id="Warning_MonoAndroidFrameworkDeprecated">
<source>Package '{0}' {1} uses the deprecated MonoAndroid framework instead of 'net6.0-android' or later. Consider upgrading to a newer version of this package or contacting the package author.</source>
<target state="new">Package '{0}' {1} uses the deprecated MonoAndroid framework instead of 'net6.0-android' or later. Consider upgrading to a newer version of this package or contacting the package author.</target>
<note>{0} - package id
{1} - package version</note>
</trans-unit>
<trans-unit id="Warning_PackageWithKnownVulnerability">
<source>Package '{0}' {1} has a known {2} severity vulnerability, {3}</source>
<target state="translated">El paquete "{0}" {1} tiene una vulnerabilidad de gravedad {2} conocida, {3}</target>
Expand Down
Loading