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

Fix unable to update or consolidate packages due to downgrade package error Nu1605 #9224 #3553

Closed
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 @@ -19,6 +19,8 @@
using Microsoft.VisualStudio.Shell.Interop;
using Task = System.Threading.Tasks.Task;
using TelemetryPiiProperty = Microsoft.VisualStudio.Telemetry.TelemetryPiiProperty;
using NuGet.ProjectManagement.Projects;
using NuGet.ProjectModel;

namespace NuGet.PackageManagement.UI
{
Expand Down Expand Up @@ -837,7 +839,36 @@ private async Task<IReadOnlyList<ResolvedAction>> GetActionsAsync(
Debug.Assert(userAction.PackageId != null, "Package id can never be null in a User action");
if (userAction.Action == NuGetProjectActionType.Install)
{
foreach (var target in targets)
// find out build integrated projects so that we can arrange them in reverse dependency order
var buildIntegratedProjectsToUpdate = targets.OfType<BuildIntegratedNuGetProject>().ToList();

// order won't matter for other type of projects so just add rest of the projects in result
var sortedTargetProjectsToUpdate = targets.Except(buildIntegratedProjectsToUpdate).ToList();

if (buildIntegratedProjectsToUpdate.Count > 0)
{
var logger = new ProjectContextLogger(projectContext);
var referenceContext = new DependencyGraphCacheContext(logger, _packageManager.Settings);

var projectUniqueNamesForBuildIntToUpdate
= buildIntegratedProjectsToUpdate.ToDictionary((project) => project.MSBuildProjectPath);

var dgFile = await DependencyGraphRestoreUtility.GetSolutionRestoreSpec(_packageManager.SolutionManager, referenceContext);
var allSortedProjects = DependencyGraphSpec.SortPackagesByDependencyOrder(dgFile.Projects);

foreach (var projectUniqueName in allSortedProjects.Select(e => e.RestoreMetadata.ProjectUniqueName))
{
BuildIntegratedNuGetProject project;
if (projectUniqueNamesForBuildIntToUpdate.TryGetValue(projectUniqueName, out project))
{
sortedTargetProjectsToUpdate.Add(project);
}
}
}

_packageManager.UpdatedPackageSpecsCache = new Dictionary<string, PackageSpec>(StringComparer.OrdinalIgnoreCase);

foreach (var target in sortedTargetProjectsToUpdate)
{
var actions = await _packageManager.PreviewInstallPackageAsync(
target,
Expand All @@ -847,6 +878,22 @@ private async Task<IReadOnlyList<ResolvedAction>> GetActionsAsync(
uiService.ActiveSources,
null,
token);

var buildIntegratedProject = target as BuildIntegratedNuGetProject;

if (buildIntegratedProject != null)
{
foreach(var action in actions)
{
var packageSpec = (action as BuildIntegratedProjectAction).RestoreResult?.LockFile?.PackageSpec;

if (packageSpec != null)
{
_packageManager.UpdatedPackageSpecsCache[buildIntegratedProject.MSBuildProjectPath] = packageSpec;
}
}
}

results.AddRange(actions.Select(a => new ResolvedAction(target, a)));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,17 @@ public override async Task<IReadOnlyList<PackageSpec>> GetPackageSpecsAsync(Depe

foreach (var originalProject in originalProjects)
{
var project = originalProject.Clone();
PackageSpec project;

if(context.PackageSpecCache.TryGetValue(
originalProject.RestoreMetadata.ProjectUniqueName, out project))
{
project = project.Clone();
}
else
{
project = originalProject.Clone();
}

// Read restore settings from ISettings if it doesn't exist in the project
// NOTE: Very important that the original project is used in the arguments, because cloning sorts the sources and compromises how the sources will be evaluated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,4 @@
[assembly: SuppressMessage("Build", "CA1063:Provide an overridable implementation of Dispose(bool) on 'PackagePreFetcherResult' or mark the type as sealed. A call to Dispose(false) should only clean up native resources. A call to Dispose(true) should clean up both managed and native resources.", Justification = "<Pending>", Scope = "type", Target = "~T:NuGet.PackageManagement.PackagePreFetcherResult")]
[assembly: SuppressMessage("Build", "CA2237:Add [Serializable] to PackageReferenceRollbackException as this type implements ISerializable", Justification = "<Pending>", Scope = "type", Target = "~T:NuGet.PackageManagement.PackageReferenceRollbackException")]
[assembly: SuppressMessage("Build", "CA1067:Type NuGet.ProjectManagement.FileTransformExtensions should override Equals because it implements IEquatable<T>", Justification = "<Pending>", Scope = "type", Target = "~T:NuGet.ProjectManagement.FileTransformExtensions")]
[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "<Pending>", Scope = "member", Target = "~P:NuGet.PackageManagement.NuGetPackageManager.UpdatedPackageSpecsCache")]
17 changes: 14 additions & 3 deletions src/NuGet.Core/NuGet.PackageManagement/NuGetPackageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ public class NuGetPackageManager

private ISourceRepositoryProvider SourceRepositoryProvider { get; }

private ISolutionManager SolutionManager { get; }

private Configuration.ISettings Settings { get; }
public Configuration.ISettings Settings { get; }

private IDictionary<string, bool> _buildIntegratedProjectsUpdateDict;

private DependencyGraphSpec _buildIntegratedProjectsCache;

private RestoreCommandProvidersCache _restoreProviderCache;

public ISolutionManager SolutionManager { get; }

public IDeleteOnRestartManager DeleteOnRestartManager { get; }

public FolderNuGetProject PackagesFolderNuGetProject { get; set; }
Expand All @@ -56,6 +56,8 @@ public class NuGetPackageManager

public IInstallationCompatibility InstallationCompatibility { get; set; }

public Dictionary<string, PackageSpec> UpdatedPackageSpecsCache { get; set; }

/// <summary>
/// Event to be raised when batch processing of install/ uninstall packages starts at a project level
/// </summary>
Expand Down Expand Up @@ -2515,6 +2517,15 @@ public async Task<BuildIntegratedProjectAction> PreviewBuildIntegratedProjectAct
var logger = new ProjectContextLogger(nuGetProjectContext);
var dependencyGraphContext = new DependencyGraphCacheContext(logger, Settings);

// get values previous evaluated PackageSpec which could be newer due to being child of current project.
if (UpdatedPackageSpecsCache!=null)
{
foreach(var cacheKey in UpdatedPackageSpecsCache.Keys)
{
dependencyGraphContext.PackageSpecCache.Add(cacheKey, UpdatedPackageSpecsCache[cacheKey]);
}
}

// Get Package Spec as json object
var originalPackageSpec = await DependencyGraphRestoreUtility.GetProjectSpec(buildIntegratedProject, dependencyGraphContext);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
NuGet.PackageManagement.NuGetPackageManager.Settings.get -> NuGet.Configuration.ISettings
NuGet.PackageManagement.NuGetPackageManager.SolutionManager.get -> NuGet.PackageManagement.ISolutionManager
NuGet.PackageManagement.NuGetPackageManager.UpdatedPackageSpecsCache.get -> System.Collections.Generic.Dictionary<string, NuGet.ProjectModel.PackageSpec>
NuGet.PackageManagement.NuGetPackageManager.UpdatedPackageSpecsCache.set -> void
NuGet.ProjectManagement.MessageLevelExtensions
static NuGet.ProjectManagement.MessageLevelExtensions.ToLogLevel(this NuGet.ProjectManagement.MessageLevel messageLevel) -> NuGet.Common.LogLevel