Skip to content

Commit

Permalink
Merge pull request chocolatey#3435 from AdmiringWorm/3433-Improve-how…
Browse files Browse the repository at this point in the history
…-dependencies-are-looked-up-when-an-exact-version-or-version-with-upper-limit-is-defined

(chocolatey#3433) Optimize queries used when resolving dependencies of exact versions
  • Loading branch information
gep13 authored May 3, 2024
2 parents da12214 + 00f8e1a commit 193b98a
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 34 deletions.
113 changes: 80 additions & 33 deletions src/chocolatey/infrastructure.app/nuget/NugetCommon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,21 +371,36 @@ public static async Task GetPackageDependencies(PackageIdentity package,
ISet<PackageDependency> dependencyCache,
ChocolateyConfiguration configuration)
{
if (availablePackages.Contains(package))
foreach (var resource in resources)
{
return;
}
var dependencyInfoResource = resource.DependencyInfoResource;

var dependencyInfoResources = resources.DependencyInfoResources();
if (dependencyInfoResource is null)
{
// We can't lookup any dependencies using this resource.
continue;
}

foreach (var dependencyInfoResource in dependencyInfoResources)
{
SourcePackageDependencyInfo dependencyInfo = null;
var dependencyInfo = availablePackages.FirstOrDefault(p => string.Equals(p.Id, package.Id, StringComparison.OrdinalIgnoreCase) && p.Version == package.Version && p.Source == resource.Source);

try
{
dependencyInfo = await dependencyInfoResource.ResolvePackage(
package, framework, cacheContext, logger, CancellationToken.None);
if (dependencyInfo is null && !package.HasVersion)
{
var latestPackage = NugetList.FindPackage(package.Id, configuration, logger, cacheContext, new[] { resource });

dependencyInfo = availablePackages.FirstOrDefault(p => string.Equals(p.Id, latestPackage.Identity.Id, StringComparison.OrdinalIgnoreCase) && p.Version == latestPackage.Identity.Version && p.Source == resource.Source);

if (dependencyInfo is null)
{
dependencyInfo = await dependencyInfoResource.ResolvePackage(latestPackage.Identity, framework, cacheContext, logger, CancellationToken.None);
}
}
else if (dependencyInfo is null)
{
dependencyInfo = await dependencyInfoResource.ResolvePackage(
package, framework, cacheContext, logger, CancellationToken.None);
}
}
catch (AggregateException ex) when (!(ex.InnerException is null))
{
Expand All @@ -402,21 +417,12 @@ public static async Task GetPackageDependencies(PackageIdentity package,
}

availablePackages.Add(dependencyInfo);
foreach (var dependency in dependencyInfo.Dependencies)
{
if (dependencyCache.Contains(dependency))
{
continue;
}

dependencyCache.Add(dependency);
await GetPackageDependencies(
dependency.Id, framework, cacheContext, logger, resources, availablePackages, dependencyCache, configuration);
}
await HandleDependencies(framework, cacheContext, logger, resources, availablePackages, dependencyCache, configuration, dependencyInfo.Dependencies);
}
}

public static async Task GetPackageDependencies(string packageId,
[Obsolete("Use overload requiring a VersionRange being specified. Will be removed in v3.0.0")]
public static Task GetPackageDependencies(string packageId,
NuGetFramework framework,
SourceCacheContext cacheContext,
ILogger logger,
Expand All @@ -425,6 +431,24 @@ public static async Task GetPackageDependencies(string packageId,
ISet<PackageDependency> dependencyCache,
ChocolateyConfiguration configuration)
{
return GetPackageDependencies(packageId, framework, cacheContext, logger, resources, availablePackages, dependencyCache, configuration, VersionRange.All);
}

public static async Task GetPackageDependencies(string packageId,
NuGetFramework framework,
SourceCacheContext cacheContext,
ILogger logger,
IEnumerable<NuGetEndpointResources> resources,
ISet<SourcePackageDependencyInfo> availablePackages,
ISet<PackageDependency> dependencyCache,
ChocolateyConfiguration configuration,
VersionRange versionRange)
{
if (versionRange is null)
{
throw new ArgumentNullException(nameof(versionRange));
}

//if (availablePackages.Contains(packageID)) return;

var dependencyInfoResources = resources.DependencyInfoResources();
Expand Down Expand Up @@ -452,20 +476,13 @@ public static async Task GetPackageDependencies(string packageId,
continue;
}

availablePackages.AddRange(dependencyInfos);
foreach (var dependency in dependencyInfos.SelectMany(p => p.Dependencies))
{
if (dependencyCache.Contains(dependency))
{
continue;
}
availablePackages.AddRange(dependencyInfos.Except(availablePackages));
// We call ToList here, otherwise we have the risk of the packages list being
// modified before we are done with the iteration
dependencyInfos = dependencyInfos.Where(di => versionRange.Satisfies(di.Version)).ToList();

dependencyCache.Add(dependency);

// Recursion is fun, kids
await GetPackageDependencies(
dependency.Id, framework, cacheContext, logger, resources, availablePackages, dependencyCache, configuration);
}
await HandleDependencies(framework, cacheContext, logger, resources, availablePackages, dependencyCache, configuration, dependencyInfos.SelectMany(di => di.Dependencies));
}
}

Expand All @@ -487,5 +504,35 @@ public static async Task GetPackageParents(string packageId,
}
}
}

private static async Task HandleDependencies(
NuGetFramework framework,
SourceCacheContext cacheContext,
ILogger logger,
IEnumerable<NuGetEndpointResources> resources,
ISet<SourcePackageDependencyInfo> availablePackages,
ISet<PackageDependency> dependencyCache, ChocolateyConfiguration configuration,
IEnumerable<PackageDependency> dependencies)
{
foreach (var dependency in dependencies)
{
if (dependencyCache.Contains(dependency))
{
continue;
}

dependencyCache.Add(dependency);

if (dependency.VersionRange.HasLowerAndUpperBounds && dependency.VersionRange.MaxVersion == dependency.VersionRange.MinVersion)
{
await GetPackageDependencies(new PackageIdentity(dependency.Id.ToLower(), dependency.VersionRange.MaxVersion), framework, cacheContext, logger, resources, availablePackages, dependencyCache, configuration);
}
else
{
await GetPackageDependencies(
dependency.Id.ToLower(), framework, cacheContext, logger, resources, availablePackages, dependencyCache, configuration, dependency.VersionRange);
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/chocolatey/infrastructure.app/nuget/NugetList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ public static IPackageSearchMetadata FindPackage(
string packageName,
ChocolateyConfiguration config,
ILogger nugetLogger,
ChocolateySourceCacheContext cacheContext,
SourceCacheContext cacheContext,
IEnumerable<NuGetEndpointResources> resources,
NuGetVersion version = null)
{
Expand Down
16 changes: 16 additions & 0 deletions src/chocolatey/infrastructure.app/services/NugetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,10 @@ Version was specified as '{0}'. It is possible that version
continue;
}

var oldPrerelease = config.Prerelease;
config.Prerelease = config.Prerelease || availablePackage.Identity.Version.IsPrerelease;
NugetCommon.GetPackageDependencies(availablePackage.Identity, NuGetFramework.AnyFramework, sourceCacheContext, _nugetLogger, remoteEndpoints, sourcePackageDependencyInfos, new HashSet<PackageDependency>(), config).GetAwaiter().GetResult();
config.Prerelease = oldPrerelease;

if (installedPackage != null && (installedPackage.PackageMetadata.Version == availablePackage.Identity.Version) && config.Force)
{
Expand Down Expand Up @@ -764,6 +767,7 @@ Version was specified as '{0}'. It is possible that version
this.Log().Error(ChocolateyLoggers.Important, logMessage);

foreach (var pkgMetadata in packagesToInstall)

{
var errorResult = packageResultsToReturn.GetOrAdd(pkgMetadata.Identity.Id, new PackageResult(pkgMetadata, pathResolver.GetInstallPath(pkgMetadata.Identity)));
errorResult.Messages.Add(new ResultMessage(ResultType.Error, logMessage));
Expand Down Expand Up @@ -1281,7 +1285,10 @@ public virtual ConcurrentDictionary<string, PackageResult> Upgrade(ChocolateyCon
{
localPackageListValid = false;

var oldPrerelease = config.Prerelease;
config.Prerelease = config.Prerelease || availablePackage.Identity.Version.IsPrerelease;
NugetCommon.GetPackageDependencies(availablePackage.Identity, NuGetFramework.AnyFramework, sourceCacheContext, _nugetLogger, remoteEndpoints, sourcePackageDependencyInfos, sourceDependencyCache, config).GetAwaiter().GetResult();
config.Prerelease = oldPrerelease;

packagesToUninstall.Add(installedPackage);

Expand Down Expand Up @@ -1323,7 +1330,10 @@ public virtual ConcurrentDictionary<string, PackageResult> Upgrade(ChocolateyCon

if (requestedPackageDependency != null)
{
oldPrerelease = config.Prerelease;
config.Prerelease = config.Prerelease || availablePackage.Identity.Version.IsPrerelease;
NugetCommon.GetPackageDependencies(requestedPackageDependency.Identity, NuGetFramework.AnyFramework, sourceCacheContext, _nugetLogger, remoteEndpoints, sourcePackageDependencyInfos, sourceDependencyCache, config).GetAwaiter().GetResult();
config.Prerelease = oldPrerelease;
}
}

Expand All @@ -1336,7 +1346,10 @@ public virtual ConcurrentDictionary<string, PackageResult> Upgrade(ChocolateyCon

if (availablePackageDependency != null)
{
oldPrerelease = config.Prerelease;
config.Prerelease = config.Prerelease || availablePackage.Identity.Version.IsPrerelease;
NugetCommon.GetPackageDependencies(availablePackageDependency.Identity, NuGetFramework.AnyFramework, sourceCacheContext, _nugetLogger, remoteEndpoints, sourcePackageDependencyInfos, sourceDependencyCache, config).GetAwaiter().GetResult();
config.Prerelease = oldPrerelease;
}
else
{
Expand Down Expand Up @@ -1456,7 +1469,10 @@ public virtual ConcurrentDictionary<string, PackageResult> Upgrade(ChocolateyCon
{
foreach (var packageVersion in NugetList.FindAllPackageVersions(parentPackage.Id, config, _nugetLogger, sourceCacheContext, remoteEndpoints))
{
oldPrerelease = config.Prerelease;
config.Prerelease = config.Prerelease || availablePackage.Identity.Version.IsPrerelease;
NugetCommon.GetPackageDependencies(packageVersion.Identity, NuGetFramework.AnyFramework, sourceCacheContext, _nugetLogger, remoteEndpoints, sourcePackageDependencyInfos, sourceDependencyCache, config).GetAwaiter().GetResult();
config.Prerelease = oldPrerelease;
}
}

Expand Down

0 comments on commit 193b98a

Please sign in to comment.