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

Prefer updating only the conditioned packages when updating in VS and dotnet add package #5420

Merged
merged 10 commits into from
Sep 26, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ public async Task<int> ExecuteCommand(PackageReferenceArgs packageReferenceArgs,
}
else
{
// If the user has not specified a framework, then just add it to all frameworks
PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageDependency, updatedPackageSpec.TargetFrameworks.Select(e => e.FrameworkName));
PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageDependency);
}

var updatedDgSpec = dgSpec.WithReplacedSpec(updatedPackageSpec).WithoutRestores();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,6 @@ private async Task<IEnumerable<NuGetProjectAction>> PreviewUpdatePackagesAsync(
nugetActions.AddRange(actions);
}

// project.json based projects are handled here
tasks.Add(Task.Run(async ()
=> await PreviewUpdatePackagesForBuildIntegratedAsync(
packageId,
Expand Down Expand Up @@ -3036,7 +3035,7 @@ internal async Task<IEnumerable<ResolvedAction>> PreviewBuildIntegratedProjectsA
if (updatedPackageSpec.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference)
{
var packageDependency = new PackageDependency(action.PackageIdentity.Id, action.VersionRange ?? new VersionRange(action.PackageIdentity.Version));
PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageDependency, updatedPackageSpec.TargetFrameworks.Select(e => e.FrameworkName));
PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageDependency);
}
else
{
Expand Down
5 changes: 0 additions & 5 deletions src/NuGet.Core/NuGet.ProjectModel/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'bool PackagesLockFileUtilities.IsLockFileStillValid(DependencyGraphSpec dgSpec, PackagesLockFile nuGetLockFile)', validate parameter 'dgSpec' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackagesLockFileUtilities.IsLockFileStillValid(NuGet.ProjectModel.DependencyGraphSpec,NuGet.ProjectModel.PackagesLockFile)~System.Boolean")]
[assembly: SuppressMessage("Build", "CA1822:Member CloneScripts does not access instance data and can be marked as static (Shared in VisualBasic)", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpec.CloneScripts(System.Collections.Generic.IDictionary{System.String,System.Collections.Generic.IEnumerable{System.String}})~System.Collections.Generic.IDictionary{System.String,System.Collections.Generic.IEnumerable{System.String}}")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'TargetFrameworkInformation PackageSpecExtensions.GetTargetFramework(PackageSpec project, NuGetFramework targetFramework)', validate parameter 'project' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecExtensions.GetTargetFramework(NuGet.ProjectModel.PackageSpec,NuGet.Frameworks.NuGetFramework)~NuGet.ProjectModel.TargetFrameworkInformation")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void PackageSpecOperations.AddOrUpdateDependency(PackageSpec spec, PackageDependency dependency)', validate parameter 'spec' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecOperations.AddOrUpdateDependency(NuGet.ProjectModel.PackageSpec,NuGet.Packaging.Core.PackageDependency)")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void PackageSpecOperations.AddOrUpdateDependency(PackageSpec spec, PackageDependency dependency, IEnumerable<NuGetFramework> frameworksToAdd)', validate parameter 'spec' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecOperations.AddOrUpdateDependency(NuGet.ProjectModel.PackageSpec,NuGet.Packaging.Core.PackageDependency,System.Collections.Generic.IEnumerable{NuGet.Frameworks.NuGetFramework})")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void PackageSpecOperations.AddOrUpdateDependency(PackageSpec spec, PackageIdentity identity)', validate parameter 'identity' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecOperations.AddOrUpdateDependency(NuGet.ProjectModel.PackageSpec,NuGet.Packaging.Core.PackageIdentity)")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void PackageSpecOperations.AddOrUpdateDependency(PackageSpec spec, PackageIdentity identity, IEnumerable<NuGetFramework> frameworksToAdd)', validate parameter 'identity' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecOperations.AddOrUpdateDependency(NuGet.ProjectModel.PackageSpec,NuGet.Packaging.Core.PackageIdentity,System.Collections.Generic.IEnumerable{NuGet.Frameworks.NuGetFramework})")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void PackageSpecOperations.RemoveDependency(PackageSpec spec, string packageId)', validate parameter 'spec' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecOperations.RemoveDependency(NuGet.ProjectModel.PackageSpec,System.String)")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'Library PackageSpecReferenceDependencyProvider.GetLibrary(LibraryRange libraryRange, NuGetFramework targetFramework)', validate parameter 'libraryRange' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecReferenceDependencyProvider.GetLibrary(NuGet.LibraryModel.LibraryRange,NuGet.Frameworks.NuGetFramework)~NuGet.LibraryModel.Library")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'NuGetVersion PackageSpecUtility.SpecifySnapshot(string version, string snapshotValue)', validate parameter 'version' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecUtility.SpecifySnapshot(System.String,System.String)~NuGet.Versioning.NuGetVersion")]
[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'int LockFileDependencyComparerWithoutContentHash.GetHashCode(LockFileDependency obj)', validate parameter 'obj' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "<Pending>", Scope = "member", Target = "~M:NuGet.ProjectModel.ProjectLockFile.LockFileDependencyComparerWithoutContentHash.GetHashCode(NuGet.ProjectModel.LockFileDependency)~System.Int32")]
Expand Down
4 changes: 4 additions & 0 deletions src/NuGet.Core/NuGet.ProjectModel/PackageSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ public NuGetVersion Version
[Obsolete]
public PackOptions PackOptions { get; set; }

/// <summary>
/// List of dependencies that apply to all frameworks.
/// <see cref="ProjectStyle.PackageReference"/> based projects must not use this list and instead use the one in the <see cref="TargetFrameworks"/> property which is a list of the <see cref="TargetFrameworkInformation"/> type.
/// </summary>
public IList<LibraryDependency> Dependencies { get; set; }

public IList<TargetFrameworkInformation> TargetFrameworks { get; private set; }
Expand Down
61 changes: 60 additions & 1 deletion src/NuGet.Core/NuGet.ProjectModel/PackageSpecOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,21 @@ namespace NuGet.ProjectModel
{
public static class PackageSpecOperations
{
/// <summary>
/// Add or Update the dependencies in the spec. If the package exists in any of the dependencies list, only those will be updated.
/// If the package does not exist in any of dependencies lists,
/// if the <see cref="PackageSpec.RestoreMetadata.ProjectStyle" /> is <see cref="ProjectStyle.PackageReference"/>
/// then the <see cref="TargetFrameworkInformation"/> will be updated,
/// otherwise, the generic dependencies will be updated.
/// </summary>
/// <param name="spec">PackageSpec to update. Cannot be <see langword="null"/></param>
/// <param name="dependency">Dependency to add. Cannot be <see langword="null"/> </param>
/// <exception cref="ArgumentNullException"> If <paramref name="spec"/> or <paramref name="dependency"/> is <see langword="null"/> </exception>
public static void AddOrUpdateDependency(PackageSpec spec, PackageDependency dependency)
{
if (spec == null) throw new ArgumentNullException(nameof(spec));
if (dependency == null) throw new ArgumentNullException(nameof(dependency));

var existing = GetExistingDependencies(spec, dependency.Id);

var range = dependency.VersionRange;
Expand All @@ -26,12 +39,35 @@ public static void AddOrUpdateDependency(PackageSpec spec, PackageDependency dep

if (!existing.Any())
{
AddDependency(spec.Dependencies, dependency.Id, range, spec.RestoreMetadata?.CentralPackageVersionsEnabled ?? false);
if (spec.RestoreMetadata?.ProjectStyle == ProjectStyle.PackageReference) // PackageReference does not use the `Dependencies` list in the PackageSpec.
{
foreach (var dependenciesList in spec.TargetFrameworks.Select(e => e.Dependencies))
{
AddDependency(dependenciesList, dependency.Id, range, spec.RestoreMetadata?.CentralPackageVersionsEnabled ?? false);
}
}
else
{
AddDependency(spec.Dependencies, dependency.Id, range, spec.RestoreMetadata?.CentralPackageVersionsEnabled ?? false);
}
}
}

/// <summary>
/// Add or Update the dependencies in the spec. If the package exists in any of the dependencies list, only those will be updated.
/// If the package does not exist in any of dependencies lists,
/// if the <see cref="PackageSpec.RestoreMetadata.ProjectStyle" /> is <see cref="ProjectStyle.PackageReference"/>
/// then the <see cref="TargetFrameworkInformation"/> will be updated,
/// otherwise, the generic dependencies will be updated.
/// </summary>
/// <param name="spec">PackageSpec to update. Cannot be <see langword="null"/></param>
/// <param name="identity">Dependency to add. Cannot be <see langword="null"/> </param>
/// <exception cref="ArgumentNullException"> If <paramref name="spec"/> or <paramref name="identity"/> is <see langword="null"/> </exception>
public static void AddOrUpdateDependency(PackageSpec spec, PackageIdentity identity)
{
if (spec == null) throw new ArgumentNullException(nameof(spec));
if (identity == null) throw new ArgumentNullException(nameof(identity));

AddOrUpdateDependency(spec, new PackageDependency(identity.Id, new VersionRange(identity.Version)));
}

Expand All @@ -40,11 +76,21 @@ public static bool HasPackage(PackageSpec spec, string packageId)
return GetExistingDependencies(spec, packageId).Any();
}

/// <summary>
/// Add or Update the dependencies in the spec. Only the frameworks specified will be considered.
/// </summary>
/// <param name="spec">PackageSpec to update. Cannot be <see langword="null"/></param>
/// <param name="dependency">Dependency to add. Cannot be <see langword="null"/> </param>
/// <param name="frameworksToAdd">The frameworks to be considered. If <see langword="null"/>, then all frameworks will be considered. </param>
/// <exception cref="ArgumentNullException"> If <paramref name="spec"/> or <paramref name="dependency"/> is <see langword="null"/> </exception>
public static void AddOrUpdateDependency(
PackageSpec spec,
PackageDependency dependency,
IEnumerable<NuGetFramework> frameworksToAdd)
{
if (spec == null) throw new ArgumentNullException(nameof(spec));
if (dependency == null) throw new ArgumentNullException(nameof(dependency));

var lists = GetDependencyLists(
spec,
includeGenericDependencies: false,
Expand All @@ -61,18 +107,31 @@ public static void AddOrUpdateDependency(
}
}

/// <summary>
/// Add or Update the dependencies in the spec. Only the frameworks specified will be considered.
/// </summary>
/// <param name="spec">PackageSpec to update. Cannot be <see langword="null"/></param>
/// <param name="identity">Dependency to add. Cannot be <see langword="null"/> </param>
/// <param name="frameworksToAdd">The frameworks to be considered. If <see langword="null"/>, then all frameworks will be considered. </param>
/// <exception cref="ArgumentNullException"> If <paramref name="spec"/> or <paramref name="identity"/> is <see langword="null"/> </exception>
public static void AddOrUpdateDependency(
PackageSpec spec,
PackageIdentity identity,
IEnumerable<NuGetFramework> frameworksToAdd)
{
if (spec == null) throw new ArgumentNullException(nameof(spec));
if (identity == null) throw new ArgumentNullException(nameof(identity));

AddOrUpdateDependency(spec, new PackageDependency(identity.Id, new VersionRange(identity.Version)), frameworksToAdd);
}

public static void RemoveDependency(
PackageSpec spec,
string packageId)
{
if (spec == null) throw new ArgumentNullException(nameof(spec));
if (packageId == null) throw new ArgumentNullException(nameof(packageId));

var lists = GetDependencyLists(
spec,
includeGenericDependencies: true,
Expand Down
Loading