Skip to content

Commit d1e7143

Browse files
authored
Merge pull request #34 from nexB/return-download-url
Trye harder to return a download url
2 parents 4bc08c2 + 4ae0618 commit d1e7143

File tree

41 files changed

+303
-307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+303
-307
lines changed

CHANGELOG.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@ Changelog
22
=========
33

44

5+
v0.9.9
6+
-------
7+
8+
This is a minor bug fix release with this update:
9+
10+
* Try harder to return a download URL for a NuGet
11+
The NuGet API does not expose a way to get the downlaod URL, so we
12+
are fetching and probing in sequence a few places like the NuGet Client
13+
does internally.
14+
15+
16+
517
v0.9.8
618
-------
719

build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ dotnet publish \
1717
--runtime linux-x64 \
1818
--self-contained true \
1919
--configuration Release \
20-
-p:Version=0.9.8 \
20+
-p:Version=0.9.9 \
2121
--output build \
2222
src/nuget-inspector/nuget-inspector.csproj

release.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
rm -rf release/
1717
mkdir release
1818

19-
VERSION=0.9.8
19+
VERSION=0.9.9
2020

2121
TARGET_BASE=nuget-inspector-$(git describe)
2222

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[bumpversion]
22
commit = False
33
tag = False
4-
current_version = 0.9.8
4+
current_version = 0.9.9
55
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
66
serialize =
77
{major}.{minor}.{patch}-{release}

src/nuget-inspector/Config.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ public static class Config
99
public static bool TRACE_DEEP = false;
1010
public static bool TRACE_META = false;
1111
public static bool TRACE_OUTPUT = false;
12-
public const string NUGET_INSPECTOR_VERSION = "0.9.8";
12+
public const string NUGET_INSPECTOR_VERSION = "0.9.9";
1313
#pragma warning restore CA2211
1414
}

src/nuget-inspector/NugetApi.cs

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,18 @@ public class NugetApi
3333
private readonly Dictionary<string, JObject?> catalog_entry_by_catalog_url = new();
3434
private readonly Dictionary<string, List<PackageSearchMetadataRegistration>> psmrs_by_package_name = new();
3535
private readonly Dictionary<PackageIdentity, PackageSearchMetadataRegistration?> psmr_by_identity = new();
36-
private readonly Dictionary<(PackageIdentity, NuGetFramework), PackageDownload?> download_by_identity = new();
36+
private readonly Dictionary<PackageIdentity, PackageDownload?> download_by_identity = new();
3737
private readonly Dictionary<(PackageIdentity, NuGetFramework), SourcePackageDependencyInfo> spdi_by_identity = new();
3838

3939
private readonly List<SourceRepository> source_repositories = new();
4040
private readonly List<PackageMetadataResource> metadata_resources = new();
4141
private readonly List<DependencyInfoResource> dependency_info_resources = new();
4242

4343
private readonly ISettings settings;
44-
44+
private readonly List<Lazy<INuGetResourceProvider>> providers = new();
4545
private readonly NuGetFramework project_framework;
46+
private readonly List<PackageSource> package_sources = new();
47+
private readonly NugetLogger nuget_logger = new();
4648

4749
public NugetApi(
4850
string nuget_config_path,
@@ -51,15 +53,14 @@ public NugetApi(
5153
bool with_nuget_org)
5254
{
5355
this.project_framework = project_framework;
54-
List<Lazy<INuGetResourceProvider>> providers = new();
55-
providers.AddRange(Repository.Provider.GetCoreV3());
56+
this.providers.AddRange(Repository.Provider.GetCoreV3());
5657

5758
settings = LoadNugetConfigSettings(
5859
nuget_config_path: nuget_config_path,
5960
project_root_path: project_root_path);
6061

6162
PopulateResources(
62-
providers: providers,
63+
providers: this.providers,
6364
settings: settings,
6465
with_nuget_org: with_nuget_org);
6566
}
@@ -138,7 +139,7 @@ private List<PackageSearchMetadataRegistration> FindPackageVersionsThroughCache(
138139
psmr = (PackageSearchMetadataRegistration)metadata_resource.GetMetadataAsync(
139140
package: pid,
140141
sourceCacheContext: source_cache_context,
141-
log: new NugetLogger(),
142+
log: nuget_logger,
142143
token: CancellationToken.None
143144
).Result;
144145

@@ -305,7 +306,8 @@ private void PopulateResources(
305306
bool with_nuget_org = false)
306307
{
307308
PackageSourceProvider package_source_provider = new(settings: settings);
308-
List<PackageSource> package_sources = package_source_provider.LoadPackageSources().ToList();
309+
package_sources.AddRange(package_source_provider.LoadPackageSources());
310+
309311
if (Config.TRACE)
310312
Console.WriteLine($"\nPopulateResources: Loaded {package_sources.Count} package sources from nuget.config");
311313

@@ -409,7 +411,7 @@ public IEnumerable<PackageDependency> GetPackageDependenciesForPackage(PackageId
409411
package: identity,
410412
projectFramework: framework,
411413
cacheContext: source_cache_context,
412-
log: new NugetLogger(),
414+
log: nuget_logger,
413415
token: CancellationToken.None);
414416

415417
spdi = infoTask.Result;
@@ -436,6 +438,43 @@ public IEnumerable<PackageDependency> GetPackageDependenciesForPackage(PackageId
436438
return null;
437439
}
438440

441+
/// <summary>
442+
/// Return the download URL of the package or null.
443+
/// This is based on the logic of private NuGet code.
444+
/// 1. Try the SourcePackageDependencyInfo.DownloadUri if present.
445+
/// 2. Try the registration metadata JObject, since there is no API
446+
/// 3. FUTURE: fall back to craft a URL by hand.
447+
/// </summary>
448+
public string? GetDownloadUrl(PackageIdentity identity)
449+
{
450+
if (spdi_by_identity.TryGetValue(key: (identity, project_framework), out SourcePackageDependencyInfo? spdi))
451+
{
452+
var du = spdi.DownloadUri;
453+
if (du != null && !string.IsNullOrWhiteSpace(du.ToString()))
454+
return du.ToString();
455+
456+
RegistrationResourceV3 rrv3 = spdi.Source.GetResource<RegistrationResourceV3>(CancellationToken.None);
457+
if (rrv3 != null)
458+
{
459+
var meta = rrv3.GetPackageMetadata(
460+
identity: identity,
461+
cacheContext: source_cache_context,
462+
log: nuget_logger,
463+
token: CancellationToken.None).Result;
464+
JToken? content = meta?["packageContent"];
465+
if (content != null)
466+
return content.ToString();
467+
}
468+
}
469+
// TODO last resort: Try if we have package base address URL
470+
// var base = "TBD";
471+
// var name = identity.Id.ToLowerInvariant();
472+
// var version = identity.Version.ToNormalizedString().ToLowerInvariant();
473+
// return $"{base}/{name}/{version}/{name}.{version}.nupkg";
474+
475+
return null;
476+
}
477+
439478
/// <summary>
440479
/// Return a PackageDownload for a given package identity.
441480
/// Cache entries for a given package identity as needed
@@ -450,12 +489,14 @@ public IEnumerable<PackageDependency> GetPackageDependenciesForPackage(PackageId
450489
if (Config.TRACE_NET)
451490
Console.WriteLine($" GetPackageDownload: {identity}, with_details: {with_details} project_framework: {project_framework}");
452491

492+
PackageDownload? download = null;
453493
// try the cache
454-
if (download_by_identity.TryGetValue((identity, project_framework), out PackageDownload? download))
494+
if (download_by_identity.TryGetValue(identity, out download))
455495
{
456496
if (Config.TRACE_NET)
457497
Console.WriteLine($" Caching hit for package '{identity}'");
458-
return download;
498+
if (download != null)
499+
return download;
459500
}
460501
else
461502
{
@@ -471,14 +512,16 @@ public IEnumerable<PackageDependency> GetPackageDependenciesForPackage(PackageId
471512
if (spdi != null)
472513
{
473514
download = PackageDownload.FromSpdi(spdi);
474-
download_by_identity[(identity, project_framework)] = download;
475515
}
476-
// else
477-
// {
478-
// download_by_identity[(identity, project_framework)] = download;
479-
// }
480516
}
481517

518+
if (download != null && string.IsNullOrWhiteSpace(download.download_url))
519+
download.download_url = GetDownloadUrl(identity) ?? "";
520+
download_by_identity[identity] = download;
521+
522+
if (Config.TRACE_NET)
523+
Console.WriteLine($" Found download: {download}'");
524+
482525
if (!with_details || (with_details && download?.IsEnhanced() == true))
483526
return download;
484527

@@ -527,7 +570,7 @@ public IEnumerable<PackageDependency> GetPackageDependenciesForPackage(PackageId
527570
if (Config.TRACE_NET)
528571
Console.WriteLine($" failed to fetch metadata details for: {package_catalog_url}: {ex}");
529572
catalog_entry_by_catalog_url[package_catalog_url] = null;
530-
return null;
573+
return download;
531574
}
532575
}
533576
if (catalog_entry != null)
@@ -542,10 +585,9 @@ public IEnumerable<PackageDependency> GetPackageDependenciesForPackage(PackageId
542585
}
543586
if (Config.TRACE_NET)
544587
Console.WriteLine($" download: {download}");
545-
download_by_identity[(identity, project_framework)] = download;
546588
return download;
547589
}
548-
return null;
590+
return download;
549591
}
550592

551593
/// <summary>
@@ -634,7 +676,7 @@ public HashSet<SourcePackageDependencyInfo> ResolveDependenciesForPackageConfig(
634676
preferredVersions: direct_deps,
635677
availablePackages: available_dependencies,
636678
packageSources: source_repositories.Select(s => s.PackageSource),
637-
log: new NugetLogger());
679+
log: nuget_logger);
638680

639681
var resolver = new PackageResolver();
640682
resolver.Resolve(context: context, token: CancellationToken.None);
@@ -674,7 +716,6 @@ public HashSet<SourcePackageDependencyInfo> ResolveDependenciesForPackageConfig(
674716
public HashSet<SourcePackageDependencyInfo> ResolveDependenciesForPackageReference(
675717
IEnumerable<PackageReference> target_references)
676718
{
677-
var nuget_logger = new NugetLogger();
678719
var psm = PackageSourceMapping.GetPackageSourceMapping(settings);
679720
var walk_context = new RemoteWalkContext(
680721
cacheContext: source_cache_context,
@@ -709,7 +750,8 @@ public HashSet<SourcePackageDependencyInfo> ResolveDependenciesForPackageReferen
709750
walk_context.RemoteLibraryProviders.Add(provider);
710751
}
711752

712-
// we need a fake root lib as this is the only allowed input
753+
// We need a fake root lib as there is only one allowed input
754+
// This represents the project
713755
var rootlib = new LibraryRange(
714756
name: "root_project",
715757
versionRange: VersionRange.Parse("1.0.0"),
@@ -728,6 +770,7 @@ public HashSet<SourcePackageDependencyInfo> ResolveDependenciesForPackageReferen
728770

729771
var resolved_package_info_by_package_id = new Dictionary<PackageId, ResolvedPackageInfo>();
730772

773+
// we iterate only inner nodes, because we have only one outer node: the "fake" root project
731774
foreach (GraphNode<RemoteResolveResult> inner in resolved_graph.InnerNodes)
732775
{
733776
if (Config.TRACE_DEEP)
@@ -759,6 +802,9 @@ public HashSet<SourcePackageDependencyInfo> ResolveDependenciesForPackageReferen
759802
return flat_dependencies;
760803
}
761804

805+
/// <summary>
806+
/// Flatten the graph and populate the result a mapping recursively
807+
/// </summary>
762808
public static void FlattenGraph(
763809
GraphNode<RemoteResolveResult> node,
764810
Dictionary<PackageId, ResolvedPackageInfo> resolved_package_info_by_package_id)
@@ -819,6 +865,9 @@ public static void FlattenGraph(
819865
}
820866
}
821867

868+
/// <summary>
869+
/// Check the dependency for errors, raise exceptions if these are found
870+
/// </summary>
822871
public static void CheckGraphForErrors(GraphNode<RemoteResolveResult> resolved_graph)
823872
{
824873
var analysis = resolved_graph.Analyze();
@@ -879,7 +928,10 @@ public class ResolvedPackageInfo
879928
public RemoteMatch? remote_match;
880929
}
881930

882-
internal class ProjectLibraryProvider : NuGet.DependencyResolver.IDependencyProvider
931+
/// <summary>
932+
/// A dependency provider that collects only the local package references
933+
/// </summary>
934+
internal class ProjectLibraryProvider : IDependencyProvider
883935
{
884936
private readonly ICollection<PackageId> package_ids;
885937

src/nuget-inspector/nuget-inspector.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
<PackageId>nuget-inspector</PackageId>
2424
<Product>nuget-inspector</Product>
2525
<AssemblyName>nuget-inspector</AssemblyName>
26-
<Version>0.9.8</Version>
26+
<Version>0.9.9</Version>
2727
<Authors>nexB Inc.</Authors>
2828
<Company>nexB Inc</Company>
29-
<AssemblyVersion>0.9.8.0</AssemblyVersion>
30-
<FileVersion>0.9.8.0</FileVersion>
29+
<AssemblyVersion>0.9.9.0</AssemblyVersion>
30+
<FileVersion>0.9.9.0</FileVersion>
3131
<Description>A NuGet and Dotnet package dependency resolver</Description>
3232
<PackageProjectUrl>https://github.com/nexB/nuget-inspector</PackageProjectUrl>
3333
<PackageLicenseUrl>Apache-2.0 AND MIT</PackageLicenseUrl>

tests/data/complex/ort-4522/xxx.csproj-expected.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@
331331
"datafile_path": "",
332332
"dependencies": [],
333333
"warnings": [
334-
"Failed to get remote metadata for name: 'Softwarehelden.NuGet.Deploy' version: '1.0.32'. System.Exception: No package metadata found for Softwarehelden.NuGet.Deploy.1.0.32.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 172\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
334+
"Failed to get remote metadata for name: 'Softwarehelden.NuGet.Deploy' version: '1.0.32'. System.Exception: No package metadata found for Softwarehelden.NuGet.Deploy.1.0.32.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 173\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
335335
],
336336
"errors": []
337337
}
@@ -621,7 +621,7 @@
621621
"datafile_path": "",
622622
"dependencies": [],
623623
"warnings": [
624-
"Failed to get remote metadata for name: 'Softwarehelden.NuGet.Deploy' version: '1.0.32'. System.Exception: No package metadata found for Softwarehelden.NuGet.Deploy.1.0.32.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 172\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
624+
"Failed to get remote metadata for name: 'Softwarehelden.NuGet.Deploy' version: '1.0.32'. System.Exception: No package metadata found for Softwarehelden.NuGet.Deploy.1.0.32.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 173\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
625625
],
626626
"errors": []
627627
}

tests/data/complex/thirdparty-suites/dependencychecker/DependencyChecker-22983ae/DependencyChecker.Test/TestProjects/NetStandard/NetStandard/NetStandard/NetStandard.csproj-expected.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"notice": "Dependency tree generated with nuget-inspector.\nnuget-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/nuget-inspector/ for support and download.",
1212
"warnings": [],
1313
"errors": [
14-
"Failed to process project file: /complex/thirdparty-suites/dependencychecker/DependencyChecker-22983ae/DependencyChecker.Test/TestProjects/NetStandard/NetStandard/NetStandard/NetStandard.csproj with:\nSystem.Exception: Failed to resolve graph with: NoVersionNotFound Accepted\n ---> System.NullReferenceException: Object reference not set to an instance of an object.\n at NugetInspector.NugetApi.FlattenGraph(GraphNode`1 node, Dictionary`2 resolved_package_info_by_package_id) in ./nuget-inspector/NugetApi.cs:line 785\n --- End of inner exception stack trace ---\n at NugetInspector.NugetApi.FlattenGraph(GraphNode`1 node, Dictionary`2 resolved_package_info_by_package_id) in ./nuget-inspector/NugetApi.cs:line 818\n at NugetInspector.NugetApi.ResolveDependenciesForPackageReference(IEnumerable`1 target_references) in ./nuget-inspector/NugetApi.cs:line 736\n at NugetInspector.ProjectFileProcessor.ResolveUsingLib() in ./nuget-inspector/ProjectFileProcessor.cs:line 445\n at NugetInspector.ProjectScanner.RunScan() in ./nuget-inspector/ProjectScanner.cs:line 293"
14+
"Failed to process project file: /complex/thirdparty-suites/dependencychecker/DependencyChecker-22983ae/DependencyChecker.Test/TestProjects/NetStandard/NetStandard/NetStandard/NetStandard.csproj with:\nSystem.Exception: Failed to resolve graph with: NoVersionNotFound Accepted\n ---> System.NullReferenceException: Object reference not set to an instance of an object.\n at NugetInspector.NugetApi.FlattenGraph(GraphNode`1 node, Dictionary`2 resolved_package_info_by_package_id) in ./nuget-inspector/NugetApi.cs:line 831\n --- End of inner exception stack trace ---\n at NugetInspector.NugetApi.FlattenGraph(GraphNode`1 node, Dictionary`2 resolved_package_info_by_package_id) in ./nuget-inspector/NugetApi.cs:line 864\n at NugetInspector.NugetApi.ResolveDependenciesForPackageReference(IEnumerable`1 target_references) in ./nuget-inspector/NugetApi.cs:line 779\n at NugetInspector.ProjectFileProcessor.ResolveUsingLib() in ./nuget-inspector/ProjectFileProcessor.cs:line 445\n at NugetInspector.ProjectScanner.RunScan() in ./nuget-inspector/ProjectScanner.cs:line 293"
1515
]
1616
}
1717
],

tests/data/complex/thirdparty-suites/dependencychecker/DependencyChecker-22983ae/DependencyChecker.Test/TestProjects/net462withoutPackages/DependencyChecker.csproj-expected.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
"datafile_path": "",
8989
"dependencies": [],
9090
"warnings": [
91-
"Failed to get remote metadata for name: 'CommandLine' version: '2.4.3'. System.Exception: No package metadata found for CommandLine.2.4.3.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 172\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
91+
"Failed to get remote metadata for name: 'CommandLine' version: '2.4.3'. System.Exception: No package metadata found for CommandLine.2.4.3.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 173\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
9292
],
9393
"errors": []
9494
},
@@ -638,7 +638,7 @@
638638
"datafile_path": "",
639639
"dependencies": [],
640640
"warnings": [
641-
"Failed to get remote metadata for name: 'CommandLine' version: '2.4.3'. System.Exception: No package metadata found for CommandLine.2.4.3.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 172\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
641+
"Failed to get remote metadata for name: 'CommandLine' version: '2.4.3'. System.Exception: No package metadata found for CommandLine.2.4.3.\n at NugetInspector.NugetApi.FindPackageVersion(PackageIdentity pid) in ./nuget-inspector/NugetApi.cs:line 173\n at NugetInspector.BasePackage.UpdateWithRemoteMetadata(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 333\n at NugetInspector.BasePackage.Update(NugetApi nugetApi, Boolean with_details) in ./nuget-inspector/Models.cs:line 312"
642642
],
643643
"errors": []
644644
},

0 commit comments

Comments
 (0)