Skip to content

Commit

Permalink
Using default nuget download and cache
Browse files Browse the repository at this point in the history
  • Loading branch information
tom-englert committed Sep 15, 2023
1 parent 519c2a8 commit 275f6a4
Showing 1 changed file with 71 additions and 46 deletions.
117 changes: 71 additions & 46 deletions src/LicenseGenerator/Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.ProjectModel;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;

using TomsToolbox.Essentials;
Expand Down Expand Up @@ -91,6 +91,12 @@ private async Task<ICollection<PackageArchiveReader>> LoadPackages()
{
var settings = Settings.LoadDefaultSettings(_solutionDirectory);
var globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder(settings);
var packageSourceProvider = new PackageSourceProvider(settings);
var sourceRepositoryProvider = new SourceRepositoryProvider(packageSourceProvider, Repository.Provider.GetCoreV3());
var repositories = sourceRepositoryProvider.GetRepositories().ToArray();

using var cacheContext = new SourceCacheContext();
var downloadContext = new PackageDownloadContext(cacheContext);

var resolvedPackages = new Dictionary<string, PackageArchiveReader>(StringComparer.OrdinalIgnoreCase);

Expand All @@ -102,7 +108,7 @@ private async Task<ICollection<PackageArchiveReader>> LoadPackages()
{
foreach (var packageIdentity in GetPackageIdentities(frameworkSpecificProject))
{
await LoadPackage(frameworkSpecificProject, packageIdentity, resolvedPackages, globalPackagesFolder);
await LoadPackage(frameworkSpecificProject, packageIdentity, repositories, downloadContext, resolvedPackages, globalPackagesFolder);
}
}
}
Expand Down Expand Up @@ -179,70 +185,89 @@ private static NuGetFramework ToPlatformVersionIndependent(NuGetFramework framew
?? NuGetFrameworkUtility.GetNearest(items, ToPlatformVersionIndependent(framework), item => ToPlatformVersionIndependent(item.TargetFramework));
}

private async Task LoadPackage(FrameworkSpecificProject project, PackageIdentity packageIdentity, IDictionary<string, PackageArchiveReader> resolvedPackages, string globalPackagesFolder)
private async Task LoadPackage(FrameworkSpecificProject project, PackageIdentity packageIdentity, ICollection<SourceRepository> repositories, PackageDownloadContext context, IDictionary<string, PackageArchiveReader> resolvedPackages, string globalPackagesFolder)
{
List<string> lastExceptions = new List<string>();

if (resolvedPackages.TryGetValue(packageIdentity.Id, out var existingPackage) && existingPackage.GetIdentity().Version >= packageIdentity.Version)
{
return;
}

Output.WriteLine($"Load: {packageIdentity}");

var localCached = GlobalPackagesFolderUtility.GetPackage(packageIdentity, globalPackagesFolder);
if (localCached == null)
foreach (var repository in repositories)
{
throw new InvalidOperationException($"Unable to find package {packageIdentity} in the local cache, restoring nuget packages first may fix this.");
}

var packageStream = localCached.PackageStream;
packageStream.Position = 0;
DownloadResourceResult downloadResult;

var package = new PackageArchiveReader(packageStream);
try
{
var downloadResource = await repository.GetResourceAsync<DownloadResource>();

resolvedPackages[packageIdentity.Id] = package;
downloadResult = await downloadResource.GetDownloadResourceResultAsync(packageIdentity, context, globalPackagesFolder, NullLogger.Instance, CancellationToken.None);
}
catch (NuGetProtocolException ex)
{
lastExceptions.Add(ex.Message);
continue; // Try next repo
}

await using var nuspec = package.GetNuspec();
if (downloadResult.Status != DownloadResourceResultStatus.Available)
continue; // Try next repo

bool ScanDependencies()
{
// Don't scan packages with pseudo-references, they don't get physically included.
if (string.Equals(packageIdentity.Id, "NETStandard.Library", StringComparison.OrdinalIgnoreCase))
return false;
var packageStream = downloadResult.PackageStream;
packageStream.Position = 0;

if (_recursive)
return true;
var package = new PackageArchiveReader(packageStream);

if (!string.IsNullOrEmpty(new NuspecReader(nuspec).GetProjectUrl()))
return false;
resolvedPackages[packageIdentity.Id] = package;

Output.WriteLine($" - No project url found in {packageIdentity}, scanning dependencies");
return true;
await using var nuspec = package.GetNuspec();

}
bool ScanDependencies()
{
// Don't scan packages with pseudo-references, they don't get physically included.
if (string.Equals(packageIdentity.Id, "NETStandard.Library", StringComparison.OrdinalIgnoreCase))
return false;

if (!ScanDependencies())
return;
if (_recursive)
return true;

var packageDependencies = package.GetPackageDependencies()?.ToArray();
if (packageDependencies is null)
return;
if (!string.IsNullOrEmpty(new NuspecReader(nuspec).GetProjectUrl()))
return false;

var bestMatching = GetNearestFramework(packageDependencies, project.TargetFramework);
var dependencies = bestMatching?.Packages
?? packageDependencies.SelectMany(item => item.Packages).Distinct();
Output.WriteLine($" - No project url found in {packageIdentity}, scanning dependencies");
return true;

foreach (var dependency in dependencies)
{
try
{
var identity = GetPackageIdentity(project, dependency.Id);
await LoadPackage(project, identity, resolvedPackages, globalPackagesFolder);
}
catch (InvalidOperationException)

if (!ScanDependencies())
return;

var packageDependencies = package.GetPackageDependencies()?.ToArray();
if (packageDependencies is null)
return;

var bestMatching = GetNearestFramework(packageDependencies, project.TargetFramework);
var dependencies = bestMatching?.Packages
?? packageDependencies.SelectMany(item => item.Packages).Distinct();

foreach (var dependency in dependencies)
{
// Ignore dependencies that can't be loaded.
try
{
var identity = GetPackageIdentity(project, dependency.Id);
await LoadPackage(project, identity, repositories, context, resolvedPackages, globalPackagesFolder);
}
catch (InvalidOperationException)
{
// Ignore dependencies that can't be loaded.
}
}
return;
}

throw new InvalidOperationException($"Package {packageIdentity} not found in any of the configured repositories: {string.Join(", ", lastExceptions)}");
}

private async Task<string> CreateLicenseFile(IEnumerable<PackageArchiveReader> packages)
Expand Down Expand Up @@ -423,7 +448,7 @@ private static NuGetFramework[] GetTargetFrameworks(Project project)
{
var frameworkNames = (project.GetProperty("TargetFrameworks") ?? project.GetProperty("TargetFramework"))
?.EvaluatedValue
?.Split(';')
.Split(';')
.Select(value => value.Trim());

var frameworks = frameworkNames?
Expand All @@ -444,19 +469,19 @@ public IEnumerable<FrameworkSpecificProject> GetFrameworkSpecificProjects()
private FrameworkSpecificProject GetProjectInFramework(NuGetFramework targetFramework)
{
if (TargetFrameworks.Length <= 1)
return new FrameworkSpecificProject(this, Project, TargetFrameworks.FirstOrDefault() ?? NuGetFramework.AnyFramework);
return new FrameworkSpecificProject(Project, TargetFrameworks.FirstOrDefault() ?? NuGetFramework.AnyFramework);

var bestMatching = GetNearestFramework(TargetFrameworks, targetFramework);
if (bestMatching == null)
return new FrameworkSpecificProject(this, Project, TargetFrameworks.FirstOrDefault() ?? NuGetFramework.AnyFramework);
return new FrameworkSpecificProject(Project, TargetFrameworks.FirstOrDefault() ?? NuGetFramework.AnyFramework);

var collection = TargetFrameworkCollections.ForceValue(bestMatching, framework => new TargetFrameworkCollection(framework));

return new FrameworkSpecificProject(this, collection.LoadProject(ProjectReference.AbsolutePath), bestMatching);
return new FrameworkSpecificProject(collection.LoadProject(ProjectReference.AbsolutePath), bestMatching);
}
}

private sealed record FrameworkSpecificProject(ProjectInfo ProjectInfo, Project Project, NuGetFramework TargetFramework)
private sealed record FrameworkSpecificProject(Project Project, NuGetFramework TargetFramework)
{
private LockFile? _lockFile;

Expand Down

0 comments on commit 275f6a4

Please sign in to comment.