Skip to content

Commit

Permalink
[Client SDK] Add catalog client (loic-sharma#321)
Browse files Browse the repository at this point in the history
Add the low level catalog resource client. Part of loic-sharma#308
  • Loading branch information
loic-sharma authored Sep 4, 2019
1 parent fa5ddb7 commit eea6a82
Show file tree
Hide file tree
Showing 26 changed files with 924 additions and 73 deletions.
39 changes: 19 additions & 20 deletions src/BaGet.Core/Metadata/DatabasePackageMetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Threading.Tasks;
using BaGet.Core.Entities;
using BaGet.Core.Mirror;
using BaGet.Core.ServiceIndex;
using BaGet.Protocol;
using NuGet.Versioning;

Expand Down Expand Up @@ -130,25 +129,25 @@ private RegistrationIndexPageItem ToRegistrationIndexPageItem(Package package) =

private IReadOnlyList<DependencyGroupItem> ToDependencyGroups(Package package)
{
var groups = new List<DependencyGroupItem>();

var targetFrameworks = package.Dependencies.Select(d => d.TargetFramework).Distinct();

foreach (var target in targetFrameworks)
{
// A package may have no dependencies for a target framework. This is represented
// by a single dependency item with a null "Id" and "VersionRange".
var groupId = $"https://api.nuget.org/v3/catalog0/data/2015.02.01.06.24.15/{package.Id}.{package.Version}.json#dependencygroup/{target}";
var dependencyItems = package.Dependencies
.Where(d => d.TargetFramework == target)
.Where(d => d.Id != null && d.VersionRange != null)
.Select(d => new DependencyItem($"{groupId}/{d.Id}", d.Id, d.VersionRange))
.ToList();

groups.Add(new DependencyGroupItem(groupId, target, dependencyItems));
}

return groups;
return package.Dependencies
.GroupBy(d => d.TargetFramework)
.Select(group => new DependencyGroupItem
{
TargetFramework = group.Key,

// A package that supports a target framework but does not have dependencies while on
// that target framework is represented by a fake dependency with a null "Id" and "VersionRange".
// This fake dependency should not be included in the output.
Dependencies = group
.Where(d => d.Id != null && d.VersionRange != null)
.Select(d => new DependencyItem
{
Id = d.Id,
Range = d.VersionRange
})
.ToList()
})
.ToList();
}
}
}
4 changes: 2 additions & 2 deletions src/BaGet.Protocol/BaGet.Protocol.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
Expand All @@ -9,7 +9,7 @@

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NuGet.Versioning" Version="$(NuGetPackageVersion)" />
<PackageReference Include="NuGet.Protocol" Version="$(NuGetPackageVersion)" />
<PackageReference Include="System.Text.Encodings.Web" Version="4.5.0" />
</ItemGroup>

Expand Down
67 changes: 67 additions & 0 deletions src/BaGet.Protocol/Catalog/CatalogClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace BaGet.Protocol.Internal
{
public class CatalogClient : ICatalogResource
{
private readonly HttpClient _httpClient;
private readonly string _catalogUrl;

public CatalogClient(HttpClient httpClient, string catalogUrl)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_catalogUrl = catalogUrl ?? throw new ArgumentNullException(nameof(catalogUrl));
}

public async Task<CatalogIndex> GetIndexAsync(CancellationToken cancellationToken = default)
{
var response = await _httpClient.DeserializeUrlAsync<CatalogIndex>(_catalogUrl, cancellationToken);

return response.GetResultOrThrow();
}

public async Task<CatalogPage> GetPageAsync(string pageUrl, CancellationToken cancellationToken = default)
{
var response = await _httpClient.DeserializeUrlAsync<CatalogPage>(pageUrl, cancellationToken);

return response.GetResultOrThrow();
}

public async Task<PackageDeleteCatalogLeaf> GetPackageDeleteLeafAsync(string leafUrl, CancellationToken cancellationToken = default)
{
return await GetAndValidateLeafAsync<PackageDeleteCatalogLeaf>(
CatalogLeafType.PackageDelete,
leafUrl,
cancellationToken);
}

public async Task<PackageDetailsCatalogLeaf> GetPackageDetailsLeafAsync(string leafUrl, CancellationToken cancellationToken = default)
{
return await GetAndValidateLeafAsync<PackageDetailsCatalogLeaf>(
CatalogLeafType.PackageDetails,
leafUrl,
cancellationToken);
}

private async Task<T> GetAndValidateLeafAsync<T>(
CatalogLeafType type,
string leafUrl,
CancellationToken cancellationToken) where T : CatalogLeaf
{
var result = await _httpClient.DeserializeUrlAsync<T>(leafUrl, cancellationToken);
var leaf = result.GetResultOrThrow();

if (leaf.Type != type)
{
throw new ArgumentException(
$"The leaf type found in the document does not match the expected '{type}' type.",
nameof(type));
}

return leaf;
}
}
}
24 changes: 24 additions & 0 deletions src/BaGet.Protocol/Catalog/CatalogIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace BaGet.Protocol
{
/// <summary>
/// The catalog index is the entry point for the catalog resource.
/// Use this to discover catalog pages, which in turn can be used to discover catalog leafs.
/// See: https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-index
/// Based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogIndex.cs
/// </summary>
public class CatalogIndex
{
[JsonProperty("commitTimeStamp")]
public DateTimeOffset CommitTimestamp { get; set; }

[JsonProperty("count")]
public int Count { get; set; }

[JsonProperty("items")]
public List<CatalogPageItem> Items { get; set; }
}
}
37 changes: 37 additions & 0 deletions src/BaGet.Protocol/Catalog/CatalogLeaf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using BaGet.Protocol.Internal;
using Newtonsoft.Json;

namespace BaGet.Protocol
{
/// <summary>
/// A catalog leaf. Represents a single package event.
/// Leafs can be discovered from a <see cref="CatalogPage"/>.
/// See: https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-leaf
/// Based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogLeaf.cs
/// </summary>
public class CatalogLeaf : ICatalogLeafItem
{
[JsonProperty("@id")]
public string Url { get; set; }

[JsonProperty("@type")]
[JsonConverter(typeof(CatalogLeafTypeConverter))]
public CatalogLeafType Type { get; set; }

[JsonProperty("catalog:commitId")]
public string CommitId { get; set; }

[JsonProperty("catalog:commitTimeStamp")]
public DateTimeOffset CommitTimestamp { get; set; }

[JsonProperty("id")]
public string PackageId { get; set; }

[JsonProperty("published")]
public DateTimeOffset Published { get; set; }

[JsonProperty("version")]
public string PackageVersion { get; set; }
}
}
30 changes: 30 additions & 0 deletions src/BaGet.Protocol/Catalog/CatalogLeafItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using BaGet.Protocol.Internal;
using Newtonsoft.Json;

namespace BaGet.Protocol
{
/// <summary>
/// An item in a <see cref="CatalogPage"/> that references a <see cref="CatalogLeaf"/>.
/// See: https://docs.microsoft.com/en-us/nuget/api/catalog-resource#catalog-item-object-in-a-page
/// Based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogLeafItem.cs
/// </summary>
public class CatalogLeafItem : ICatalogLeafItem
{
[JsonProperty("@id")]
public string Url { get; set; }

[JsonProperty("@type")]
[JsonConverter(typeof(CatalogLeafItemTypeConverter))]
public CatalogLeafType Type { get; set; }

[JsonProperty("commitTimeStamp")]
public DateTimeOffset CommitTimestamp { get; set; }

[JsonProperty("nuget:id")]
public string PackageId { get; set; }

[JsonProperty("nuget:version")]
public string PackageVersion { get; set; }
}
}
19 changes: 19 additions & 0 deletions src/BaGet.Protocol/Catalog/CatalogLeafType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace BaGet.Protocol
{
/// <summary>
/// The type of a <see cref="CatalogLeaf"/>.
/// Based off: https://github.com/NuGet/NuGet.Services.Metadata/blob/64af0b59c5a79e0143f0808b39946df9f16cb2e7/src/NuGet.Protocol.Catalog/Models/CatalogLeafType.cs
/// </summary>
public enum CatalogLeafType
{
/// <summary>
/// The <see cref="CatalogLeaf"/> represents the snapshot of a package's metadata.
/// </summary>
PackageDetails = 1,

/// <summary>
/// The <see cref="CatalogLeaf"/> represents a package that was deleted.
/// </summary>
PackageDelete = 2,
}
}
Loading

0 comments on commit eea6a82

Please sign in to comment.