Skip to content

Commit

Permalink
Start
Browse files Browse the repository at this point in the history
Push more logic to mirror service

Refactor search

Refactor Azure Table search

Clean
  • Loading branch information
loic-sharma committed Oct 15, 2021
1 parent 5fc5072 commit 38c0603
Show file tree
Hide file tree
Showing 15 changed files with 527 additions and 23 deletions.
20 changes: 19 additions & 1 deletion src/BaGet.Core/IUrlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface IUrlGenerator
/// Get the URL for the package source (also known as the "service index").
/// See: https://docs.microsoft.com/en-us/nuget/api/service-index
/// </summary>
string GetServiceIndexUrl();
string GetServiceIndexV3Url();

/// <summary>
/// Get the URL for the root of the package content resource.
Expand Down Expand Up @@ -80,6 +80,13 @@ public interface IUrlGenerator
/// <param name="id">The package's ID</param>
string GetPackageVersionsUrl(string id);

/// <summary>
/// Get the URL to download a package (.nupkg).
/// See: https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-content-nupkg
/// </summary>
/// <param name="package">The package to download</param>
string GetPackageDownloadUrl(Package package);

/// <summary>
/// Get the URL to download a package (.nupkg).
/// See: https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-content-nupkg
Expand All @@ -101,5 +108,16 @@ public interface IUrlGenerator
/// <param name="id">The package's ID</param>
/// <param name="version">The package's version</param>
string GetPackageIconDownloadUrl(string id, NuGetVersion version);

/// <summary>
/// Get the URL for the package source that implements the legacy NuGet V2 API.
/// </summary>
string GetServiceIndexV2Url();

/// <summary>
/// Get the URL for the metadata of a single package version.
/// </summary>
/// <param name="package">The package to lookup</param>
string GetPackageVersionV2Url(Package package);
}
}
8 changes: 1 addition & 7 deletions src/BaGet.Core/Metadata/DefaultPackageMetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,13 @@ namespace BaGet.Core
public class DefaultPackageMetadataService : IPackageMetadataService
{
private readonly IMirrorService _mirror;
private readonly IPackageService _packages;
private readonly RegistrationBuilder _builder;

public DefaultPackageMetadataService(
IMirrorService mirror,
IPackageService packages,
RegistrationBuilder builder)
{
_mirror = mirror ?? throw new ArgumentNullException(nameof(mirror));
_packages = packages ?? throw new ArgumentNullException(nameof(packages));
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
}

Expand All @@ -45,10 +42,7 @@ public class DefaultPackageMetadataService : IPackageMetadataService
NuGetVersion version,
CancellationToken cancellationToken = default)
{
// Allow read-through caching to happen if it is configured.
await _mirror.MirrorAsync(id, version, cancellationToken);

var package = await _packages.FindOrNullAsync(id, version, includeUnlisted: true, cancellationToken);
var package = await _mirror.FindPackageOrNullAsync(id, version, cancellationToken);
if (package == null)
{
return null;
Expand Down
6 changes: 3 additions & 3 deletions src/BaGet.Core/Metadata/RegistrationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public virtual RegistrationLeafResponse BuildLeaf(Package package)
Listed = package.Listed,
Published = package.Published,
RegistrationLeafUrl = _url.GetRegistrationLeafUrl(id, version),
PackageContentUrl = _url.GetPackageDownloadUrl(id, version),
PackageContentUrl = _url.GetPackageDownloadUrl(package),
RegistrationIndexUrl = _url.GetRegistrationIndexUrl(id)
};
}
Expand All @@ -61,7 +61,7 @@ public virtual RegistrationLeafResponse BuildLeaf(Package package)
new BaGetRegistrationIndexPageItem
{
RegistrationLeafUrl = _url.GetRegistrationLeafUrl(package.Id, package.Version),
PackageContentUrl = _url.GetPackageDownloadUrl(package.Id, package.Version),
PackageContentUrl = _url.GetPackageDownloadUrl(package),
PackageMetadata = new BaGetPackageMetadata
{
PackageId = package.Id,
Expand All @@ -78,7 +78,7 @@ public virtual RegistrationLeafResponse BuildLeaf(Package package)
Listed = package.Listed,
MinClientVersion = package.MinClientVersion,
ReleaseNotes = package.ReleaseNotes,
PackageContentUrl = _url.GetPackageDownloadUrl(package.Id, package.Version),
PackageContentUrl = _url.GetPackageDownloadUrl(package),
PackageTypes = package.PackageTypes.Select(t => t.Name).ToList(),
ProjectUrl = package.ProjectUrlString,
RepositoryUrl = package.RepositoryUrlString,
Expand Down
8 changes: 8 additions & 0 deletions src/BaGet.Core/Mirror/DisabledMirrorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ public DisabledMirrorService(IPackageService packages)
_packages = packages ?? throw new ArgumentNullException(nameof(packages));
}

public async Task<Package> FindPackageOrNullAsync(
string id,
NuGetVersion version,
CancellationToken cancellationToken)
{
return await _packages.FindOrNullAsync(id, version, includeUnlisted: true, cancellationToken);
}

public async Task<IReadOnlyList<NuGetVersion>> FindPackageVersionsAsync(string id, CancellationToken cancellationToken)
{
var packages = await _packages.FindAsync(id, includeUnlisted: true, cancellationToken);
Expand Down
13 changes: 13 additions & 0 deletions src/BaGet.Core/Mirror/IMirrorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ public interface IMirrorService
/// </returns>
Task<IReadOnlyList<Package>> FindPackagesAsync(string id, CancellationToken cancellationToken);

/// <summary>
/// Attempt to find a package's metadata using mirroring. This will merge
/// results from the configured upstream source with the locally indexed packages.
/// </summary>
/// <param name="id">The package's id to lookup</param>
/// <param name="version">The package's version to lookup</param>
/// <param name="cancellationToken">The token to cancel the lookup</param>
/// <returns>
/// The metadata for single version of a package.
/// Returns null if the package does not exist.
/// </returns>
Task<Package> FindPackageOrNullAsync(string id, NuGetVersion version, CancellationToken cancellationToken);

/// <summary>
/// If the package is unknown, attempt to index it from an upstream source.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/BaGet.Core/Mirror/MirrorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ public async Task<IReadOnlyList<Package>> FindPackagesAsync(string id, Cancellat
return result.Values.ToList();
}

public async Task<Package> FindPackageOrNullAsync(
string id,
NuGetVersion version,
CancellationToken cancellationToken)
{
await MirrorAsync(id, version, cancellationToken);

return await _localPackages.FindOrNullAsync(id, version, includeUnlisted: true, cancellationToken);
}

public async Task MirrorAsync(string id, NuGetVersion version, CancellationToken cancellationToken)
{
if (await _localPackages.ExistsAsync(id, version, cancellationToken))
Expand Down
12 changes: 12 additions & 0 deletions src/BaGet.Core/V2/IV2Builder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Xml.Linq;

namespace BaGet.Core
{
public interface IV2Builder
{
XElement BuildIndex();
XElement BuildPackages(IReadOnlyList<Package> packages);
XElement BuildPackage(Package package);
}
}
219 changes: 219 additions & 0 deletions src/BaGet.Core/V2/V2Builder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace BaGet.Core
{
public class V2Builder : IV2Builder
{
private readonly IUrlGenerator _url;

public V2Builder(IUrlGenerator url)
{
_url = url;
}

public XElement BuildIndex()
{
var serviceIndex = _url.GetServiceIndexV2Url();

return XElement.Parse($@"
<service xmlns=""http://www.w3.org/2007/app"" xmlns:atom=""http://www.w3.org/2005/Atom"" xml:base=""{serviceIndex}"">
<workspace>
<atom:title type=""text"">Default</atom:title>
<collection href=""Packages"">
<atom:title type=""text"">Packages</atom:title>
</collection>
</workspace>
</service>");
}

public XElement BuildPackages(IReadOnlyList<Package> packages)
{
// See: https://joelverhagen.github.io/NuGetUndocs/#endpoint-find-packages-by-id
var serviceIndex = _url.GetServiceIndexV2Url();

// TODO: Add <?xml version="1.0" encoding="utf-8"?> to top
return new XElement(
N.feed,
new XAttribute(N.baze, XNamespace.Get(serviceIndex)),
new XAttribute(N.m, NS.m),
new XAttribute(N.d, NS.d),
new XAttribute(N.georss, NS.georss),
new XAttribute(N.gml, NS.gml),
new XElement(N.m_count, packages.Count),

packages.Select(package =>
{
var packageV2Url = _url.GetPackageVersionV2Url(package);
var downloadUrl = _url.GetPackageDownloadUrl(package);
return new XElement(
N.entry,
new XElement(N.id, packageV2Url),
new XElement(N.title, package.Title),
new XElement(
N.content,
new XAttribute("type", "application/zip"),
new XAttribute("src", downloadUrl)
),
BuildAuthor(package),
BuildProperties(package)
);
})
);
}

public XElement BuildPackage(Package package)
{
// See: https://joelverhagen.github.io/NuGetUndocs/#endpoint-get-a-single-package
var serviceIndex = _url.GetServiceIndexV2Url();
var packageV2Url = _url.GetPackageVersionV2Url(package);
var downloadUrl = _url.GetPackageDownloadUrl(package);

return new XElement(
N.entry,
new XAttribute(N.baze, XNamespace.Get(serviceIndex)),
new XAttribute(N.m, NS.m),
new XAttribute(N.d, NS.d),
new XAttribute(N.georss, NS.georss),
new XAttribute(N.gml, NS.gml),
new XElement(N.id, packageV2Url),
new XElement(N.title, package.Title),

new XElement(
N.content,
new XAttribute("type", "application/zip"),
new XAttribute("src", downloadUrl)
),

BuildAuthor(package),
BuildProperties(package)
);
}

private XElement BuildProperties(Package package)
{
// See: https://joelverhagen.github.io/NuGetUndocs/#package-entity
return new XElement(
N.m_properties,
new XElement(N.d_Id, package.Id),
new XElement(N.d_Title, package.Title),
new XElement(N.d_Version, package.OriginalVersionString),
new XElement(N.d_NormalizedVersion, package.NormalizedVersionString),
new XElement(N.d_Authors, string.Join(", ", package.Authors)),
new XElement(N.d_Copyright, ""), // TODO
new XElement(N.d_Description, package.Description),
new XElement(
N.d_DownloadCount,
new XAttribute(N.m_type, "Edm.Int32"),
package.Downloads),
new XElement(N.d_LastEdited, package.Published),
new XElement(N.d_Published, package.Published),
new XElement(N.d_PackageHash, ""),
new XElement(N.d_PackageHashAlgorithm, ""),
new XElement(N.d_PackageSize, 0),
new XElement(N.d_ProjectUrl, package.ProjectUrl),
new XElement(N.d_IconUrl, package.IconUrl), // TODO, URL logic
new XElement(N.d_LicenseUrl, package.LicenseUrl), // TODO
new XElement(N.d_Tags, string.Join(", ", package.Tags)),
new XElement(N.d_RequireLicenseAcceptance, package.RequireLicenseAcceptance),

BuildDependencies(package)
);
}

private XElement BuildAuthor(Package package)
{
// TODO: No authors?
return new XElement(
N.author,
package.Authors.Select(author => new XElement(N.name, author))
);
}

private XElement BuildDependencies(Package package)
{
var flattenedDependencies = new List<string>();

flattenedDependencies.AddRange(
package
.Dependencies
.Where(IsFrameworkDependency)
.Select(dependency => dependency.TargetFramework)
.Distinct()
.Select(targetFramework => $"::{targetFramework}"));

flattenedDependencies.AddRange(
package
.Dependencies
.Where(dependency => !IsFrameworkDependency(dependency))
.Select(dependency => $"{dependency.Id}:{dependency.VersionRange}:{dependency.TargetFramework}"));

var result = string.Join("|", flattenedDependencies);

return new XElement(N.d_Dependencies, result);
}

private bool IsFrameworkDependency(PackageDependency dependency)
{
return dependency.Id == null && dependency.VersionRange == null;
}

private static class NS
{
public static readonly XNamespace xmlns = "http://www.w3.org/2005/Atom";
//public static readonly XNamespace baze = "https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet";
public static readonly XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
public static readonly XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
public static readonly XNamespace georss = "http://www.georss.org/georss";
public static readonly XNamespace gml = "http://www.opengis.net/gml";
}

private static class N
{
public static readonly XName feed = NS.xmlns + "feed";
public static readonly XName entry = NS.xmlns + "entry";
public static readonly XName title = NS.xmlns + "title";
public static readonly XName author = NS.xmlns + "author";
public static readonly XName name = NS.xmlns + "name";
public static readonly XName link = NS.xmlns + "link";
public static readonly XName id = NS.xmlns + "id";
public static readonly XName content = NS.xmlns + "content";

public static readonly XName m_count = NS.m + "count";
public static readonly XName m_properties = NS.m + "properties";
public static readonly XName m_type = NS.m + "type";

public static readonly XName d_Id = NS.d + "Id";
public static readonly XName d_Title = NS.d + "Title";
public static readonly XName d_Version = NS.d + "Version";
public static readonly XName d_NormalizedVersion = NS.d + "NormalizedVersion";
public static readonly XName d_Authors = NS.d + "Authors";
public static readonly XName d_Copyright = NS.d + "Copyright";
public static readonly XName d_Dependencies = NS.d + "Dependencies";
public static readonly XName d_Description = NS.d + "Description";
public static readonly XName d_IconUrl = NS.d + "IconUrl";
public static readonly XName d_LicenseUrl = NS.d + "LicenseUrl";
public static readonly XName d_ProjectUrl = NS.d + "ProjectUrl";
public static readonly XName d_Tags = NS.d + "Tags";
public static readonly XName d_ReportAbuseUrl = NS.d + "ReportAbuseUrl";
public static readonly XName d_RequireLicenseAcceptance = NS.d + "RequireLicenseAcceptance";
public static readonly XName d_DownloadCount = NS.d + "DownloadCount";
public static readonly XName d_Created = NS.d + "Created";
public static readonly XName d_LastEdited = NS.d + "LastEdited";
public static readonly XName d_Published = NS.d + "Published";
public static readonly XName d_PackageHash = NS.d + "PackageHash";
public static readonly XName d_PackageHashAlgorithm = NS.d + "PackageHashAlgorithm";
public static readonly XName d_MinClientVersion = NS.d + "MinClientVersion";
public static readonly XName d_PackageSize = NS.d + "PackageSize";

public static readonly XName baze = XNamespace.Xmlns + "base";
public static readonly XName m = XNamespace.Xmlns + "m";
public static readonly XName d = XNamespace.Xmlns + "d";
public static readonly XName georss = XNamespace.Xmlns + "georss";
public static readonly XName gml = XNamespace.Xmlns + "gml";
}
}
}

0 comments on commit 38c0603

Please sign in to comment.