feature: first
All checks were successful
Build / Compute Version (push) Successful in 4s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 2m47s
Build / Build Nuget package (CringePlugins) (push) Successful in 5m31s
Build / Build Nuget package (NuGet) (push) Successful in 6m2s
Build / Build Nuget package (SharedCringe) (push) Successful in 7m25s
Build / Build Launcher (push) Successful in 9m11s

This commit is contained in:
zznty
2022-10-28 01:58:54 +07:00
commit aa979e9519
81 changed files with 6162 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using NuGet.Frameworks;
namespace NuGet.Converters;
public class FrameworkJsonConverter(FrameworkNameFormat format) : JsonConverter<NuGetFramework>
{
public override NuGetFramework Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
throw new JsonException("Invalid framework string");
var s = reader.GetString()!;
return format switch
{
FrameworkNameFormat.ShortFolderName => NuGetFramework.ParseFolder(s),
FrameworkNameFormat.FrameworkName => NuGetFramework.ParseFrameworkName(s,
DefaultFrameworkNameProvider.Instance),
_ => throw new ArgumentOutOfRangeException()
};
}
public override void Write(Utf8JsonWriter writer, NuGetFramework value, JsonSerializerOptions options)
{
writer.WriteStringValue(FormatValue(value));
}
private string FormatValue(NuGetFramework value)
{
return format switch
{
FrameworkNameFormat.ShortFolderName => value.GetShortFolderName(),
FrameworkNameFormat.FrameworkName => value.DotNetFrameworkName,
_ => throw new ArgumentOutOfRangeException()
};
}
public override NuGetFramework ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options) => Read(ref reader, typeToConvert, options);
public override void WriteAsPropertyName(Utf8JsonWriter writer, NuGetFramework value,
JsonSerializerOptions options)
{
writer.WritePropertyName(FormatValue(value));
}
}
public enum FrameworkNameFormat
{
/// <summary>
/// The short folder name format (net8.0)
/// </summary>
ShortFolderName,
/// <summary>
/// Full framework name (.NETCoreApp,Version=v8.0)
/// </summary>
FrameworkName
}

View File

@@ -0,0 +1,30 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using NuGet.Deps;
namespace NuGet.Converters;
public class ManifestPackageKeyJsonConverter : JsonConverter<ManifestPackageKey>
{
public override ManifestPackageKey Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
throw new JsonException("Invalid package key string");
return ManifestPackageKey.Parse(reader.GetString()!);
}
public override void Write(Utf8JsonWriter writer, ManifestPackageKey value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
public override ManifestPackageKey ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options) => Read(ref reader, typeToConvert, options);
public override void WriteAsPropertyName(Utf8JsonWriter writer, ManifestPackageKey value,
JsonSerializerOptions options)
{
writer.WritePropertyName(value.ToString());
}
}

View File

@@ -0,0 +1,21 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using NuGet.Models;
namespace NuGet.Converters;
public class ResourceTypeJsonConverter : JsonConverter<ResourceType>
{
public override ResourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
throw new JsonException("Invalid resource type");
return ResourceType.Parse(reader.GetString()!);
}
public override void Write(Utf8JsonWriter writer, ResourceType value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}

View File

@@ -0,0 +1,21 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using NuGet.Versioning;
namespace NuGet.Converters;
public class VersionJsonConverter : JsonConverter<NuGetVersion>
{
public override NuGetVersion? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
throw new JsonException("Invalid version string");
return NuGetVersion.Parse(reader.GetString()!);
}
public override void Write(Utf8JsonWriter writer, NuGetVersion value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}

View File

@@ -0,0 +1,21 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using NuGet.Versioning;
namespace NuGet.Converters;
public class VersionRangeJsonConverter : JsonConverter<VersionRange>
{
public override VersionRange? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
throw new JsonException("Invalid version range");
return VersionRange.Parse(reader.GetString()!);
}
public override void Write(Utf8JsonWriter writer, VersionRange value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}

View File

@@ -0,0 +1,155 @@
using System.Collections.Immutable;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
using NuGet.Converters;
using NuGet.Frameworks;
using NuGet.Models;
using NuGet.Versioning;
namespace NuGet.Deps;
public record DependenciesManifest(RuntimeTarget RuntimeTarget,
ImmutableDictionary<NuGetFramework, string> CompilationOptions,
ImmutableDictionary<NuGetFramework, ImmutableDictionary<ManifestPackageKey, DependencyTarget>> Targets,
ImmutableDictionary<ManifestPackageKey, DependencyLibrary> Libraries);
public record DependencyLibrary(
LibraryType Type,
string Sha512 = "",
bool Serviceable = false,
ManifestPackageKey? Path = null,
string? HashPath = null);
[JsonConverter(typeof(JsonStringEnumConverter<LibraryType>))]
public enum LibraryType
{
Project,
Package
}
public record DependencyTarget(ImmutableDictionary<string, NuGetVersion>? Dependencies,
// key is file path relative to package root
ImmutableDictionary<string, RuntimeDependency>? Runtime,
// key is file path relative to package root
ImmutableDictionary<string, Dependency>? Native);
public record Dependency(Version? FileVersion = null);
public record RuntimeDependency(Version? AssemblyVersion = null, Version? FileVersion = null) : Dependency(FileVersion);
public record RuntimeTarget([property: JsonPropertyName("name")] NuGetFramework Framework, string Signature = "");
[JsonConverter(typeof(ManifestPackageKeyJsonConverter))]
public record ManifestPackageKey(string Id, NuGetVersion Version)
{
public static ManifestPackageKey Parse(string str)
{
var index = str.IndexOf('/');
if (index < 0)
throw new FormatException("Invalid package key: " + str);
return new ManifestPackageKey(str[..index], NuGetVersion.Parse(str[(index + 1)..]));
}
public override string ToString() => $"{Id}/{Version}";
}
public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSourceMapping packageSources, Func<Models.Dependency, NuGetVersion?> versionResolver)
{
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = true,
Converters =
{
new FrameworkJsonConverter(FrameworkNameFormat.FrameworkName),
new VersionJsonConverter()
}
};
public async ValueTask WriteDependencyManifestAsync(Stream stream, CatalogEntry catalogEntry, NuGetFramework targetFramework)
{
var runtimeTarget = new RuntimeTarget(targetFramework);
var targets = ImmutableDictionary<ManifestPackageKey, DependencyTarget>.Empty.ToBuilder();
await MapCatalogEntryAsync(catalogEntry, targetFramework, targets);
var manifest = new DependenciesManifest(runtimeTarget, ImmutableDictionary<NuGetFramework, string>.Empty,
ImmutableDictionary<NuGetFramework, ImmutableDictionary<ManifestPackageKey, DependencyTarget>>.Empty
.Add(targetFramework, targets.ToImmutable()),
ImmutableDictionary<ManifestPackageKey, DependencyLibrary>.Empty);
await JsonSerializer.SerializeAsync(stream, manifest, SerializerOptions);
}
private async Task MapCatalogEntryAsync(CatalogEntry catalogEntry, NuGetFramework targetFramework,
ImmutableDictionary<ManifestPackageKey, DependencyTarget>.Builder targets)
{
if (targets.ContainsKey(new(catalogEntry.Id, catalogEntry.Version)))
return;
var nearest = NuGetFrameworkUtility.GetNearest(catalogEntry.DependencyGroups, targetFramework,
group => group.TargetFramework);
if (nearest is null)
return;
targets.Add(new(catalogEntry.Id, catalogEntry.Version),
await MapEntryAsync(catalogEntry, nearest));
foreach (var dependency in nearest.Dependencies ?? [])
{
var client = await packageSources.GetClientAsync(dependency.Id);
var (url, entry) = await client.GetPackageRegistrationAsync(dependency.Id, versionResolver(dependency)!);
entry ??= await client.GetPackageCatalogEntryAsync(url);
await MapCatalogEntryAsync(entry, targetFramework, targets);
}
}
private async Task<DependencyTarget> MapEntryAsync(CatalogEntry entry, DependencyGroup group)
{
var packageEntries = entry.PackageEntries ?? await GetPackageContent(entry);
return new(group.Dependencies?.ToImmutableDictionary(b => b.Id, versionResolver) ?? ImmutableDictionary<string, NuGetVersion>.Empty,
packageEntries.Where(b => b.FullName.StartsWith($"lib/{group.TargetFramework.GetShortFolderName()}/"))
.ToImmutableDictionary(b => b.FullName, _ => new RuntimeDependency()),
packageEntries.Where(b =>
b.FullName.StartsWith($"runtimes/{RuntimeInformation.RuntimeIdentifier}/native/"))
.ToImmutableDictionary(b => b.FullName, _ => new Dependency()));
}
private async Task<ImmutableArray<CatalogPackageEntry>> GetPackageContent(CatalogEntry entry)
{
while (true)
{
var dir = new DirectoryInfo(Path.Join(cacheDirectory.FullName, entry.Id, entry.Version.ToString()));
if (dir.Exists)
{
return
[
..dir.EnumerateFiles("*", SearchOption.AllDirectories)
.Select(b => new CatalogPackageEntry(b.Name, b.FullName, b.Length, b.Length))
];
}
var client = await packageSources.GetClientAsync(entry.Id);
dir.Create();
{
await using var stream = await client.GetPackageContentStreamAsync(entry.Id, entry.Version);
using var memStream = new MemoryStream();
await stream.CopyToAsync(memStream);
memStream.Position = 0;
using var archive = new ZipArchive(memStream, ZipArchiveMode.Read);
archive.ExtractToDirectory(dir.FullName);
}
}
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Immutable;
using NuGet.Versioning;
namespace NuGet.Models;
public record CatalogEntry(string Id, NuGetVersion Version, ImmutableArray<DependencyGroup> DependencyGroups, ImmutableArray<string>? PackageTypes,
ImmutableArray<CatalogPackageEntry>? PackageEntries);
public record CatalogPackageEntry(string Name, string FullName, long CompressedLength, long Length);

View File

@@ -0,0 +1,5 @@
using NuGet.Versioning;
namespace NuGet.Models;
public record Dependency(string Id, VersionRange Range);

View File

@@ -0,0 +1,6 @@
using System.Collections.Immutable;
using NuGet.Frameworks;
namespace NuGet.Models;
public record DependencyGroup(NuGetFramework TargetFramework, ImmutableArray<Dependency>? Dependencies = null);

View File

@@ -0,0 +1,5 @@
using NuGet.Versioning;
namespace NuGet.Models;
public record NuGetIndex(NuGetVersion Version, Resource[] Resources);

View File

@@ -0,0 +1,6 @@
using System.Text.Json.Serialization;
namespace NuGet.Models;
public record Registration([property: JsonPropertyName("catalogEntry")] string CatalogEntryUrl,
[property: JsonPropertyName("sleet:catalogEntry")] CatalogEntry? SleetEntry);

View File

@@ -0,0 +1,3 @@
namespace NuGet.Models;
public record RegistrationEntry(CatalogEntry CatalogEntry);

View File

@@ -0,0 +1,5 @@
using NuGet.Versioning;
namespace NuGet.Models;
public record RegistrationPage(int Count, NuGetVersion Lower, NuGetVersion Upper, RegistrationEntry[] Items);

View File

@@ -0,0 +1,3 @@
namespace NuGet.Models;
public record RegistrationRoot(int Count, RegistrationPage[] Items);

5
NuGet/Models/Resource.cs Normal file
View File

@@ -0,0 +1,5 @@
using System.Text.Json.Serialization;
namespace NuGet.Models;
public record Resource([property: JsonPropertyName("@id")] string Url, [property: JsonPropertyName("@type")] ResourceType Type, string? Comment);

View File

@@ -0,0 +1,26 @@
using System.Text.Json.Serialization;
using NuGet.Converters;
using NuGet.Versioning;
namespace NuGet.Models;
[JsonConverter(typeof(ResourceTypeJsonConverter))]
public record ResourceType(string Id, NuGetVersion? Version)
{
public static ResourceType Parse(string typeString)
{
var slash = typeString.IndexOf('/');
if (slash < 0)
return new ResourceType(typeString, null);
var id = typeString[..slash];
var versionStr = typeString[(slash + 1)..];
return NuGetVersion.TryParse(versionStr, out var version)
? new ResourceType(id, version)
: new ResourceType(id, null);
}
public override string ToString() => $"{Id}/{Version}";
}

16
NuGet/NuGet.csproj Normal file
View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NuGet.Frameworks" Version="6.11.1" />
<PackageReference Include="NuGet.Versioning" Version="6.11.1" />
</ItemGroup>
</Project>

83
NuGet/NuGetClient.cs Normal file
View File

@@ -0,0 +1,83 @@
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using NuGet.Converters;
using NuGet.Models;
using NuGet.Versioning;
namespace NuGet;
public class NuGetClient
{
private readonly HttpClient _client;
private readonly Uri _packageBaseAddress;
private readonly Uri _registration;
public static JsonSerializerOptions SerializerOptions { get; } = new(JsonSerializerDefaults.Web)
{
Converters =
{
new VersionJsonConverter(),
new VersionRangeJsonConverter(),
new FrameworkJsonConverter(FrameworkNameFormat.ShortFolderName),
},
WriteIndented = true
};
private NuGetClient(HttpClient client, Uri packageBaseAddress, Uri registration)
{
_client = client;
_packageBaseAddress = packageBaseAddress;
_registration = registration;
}
public Task<Stream> GetPackageContentStreamAsync(string id, NuGetVersion version)
{
id = id.ToLower();
return _client.GetStreamAsync(new Uri(_packageBaseAddress,
new Uri($"{id}/{version}/{id}.{version}.nupkg", UriKind.Relative)));
}
public Task<Registration> GetPackageRegistrationAsync(string id, NuGetVersion version)
{
return _client.GetFromJsonAsync<Registration>(
new Uri(_registration,
new Uri($"{id.ToLower()}/{version}.json", UriKind.Relative)),
SerializerOptions
)!;
}
public Task<RegistrationRoot> GetPackageRegistrationRootAsync(string id)
{
return _client.GetFromJsonAsync<RegistrationRoot>(
new Uri(_registration,
new Uri($"{id.ToLower()}/index.json", UriKind.Relative)),
SerializerOptions
)!;
}
public Task<CatalogEntry> GetPackageCatalogEntryAsync(string url)
{
return _client.GetFromJsonAsync<CatalogEntry>(url, SerializerOptions)!;
}
public static async Task<NuGetClient> CreateFromIndexUrlAsync(string indexUrl)
{
var client = new HttpClient(new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.All
});
var index = await client.GetFromJsonAsync<NuGetIndex>(indexUrl, SerializerOptions);
var (packageBaseAddress, _, _) = index!.Resources.First(b => b.Type.Id == "PackageBaseAddress");
var (registration, _, _) = index!.Resources.First(b => b.Type.Id == "RegistrationsBaseUrl");
if (!packageBaseAddress.EndsWith('/'))
packageBaseAddress += '/';
if (!registration.EndsWith('/'))
registration += '/';
return new NuGetClient(client, new Uri(packageBaseAddress), new Uri(registration));
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Immutable;
namespace NuGet;
public class PackageSourceMapping(ImmutableArray<PackageSource> sources)
{
private readonly ImmutableArray<(string pattern, Task<NuGetClient> client)> _clients = [
..sources.Select(b =>
(b.Pattern,
NuGetClient.CreateFromIndexUrlAsync(b.Url)))
];
public Task<NuGetClient> GetClientAsync(string packageId) =>
_clients.FirstOrDefault(b => packageId.StartsWith(b.pattern)).client;
}
public record PackageSource(string Pattern, string Url);

20
NuGet/packages.lock.json Normal file
View File

@@ -0,0 +1,20 @@
{
"version": 1,
"dependencies": {
"net8.0": {
"NuGet.Frameworks": {
"type": "Direct",
"requested": "[6.11.1, )",
"resolved": "6.11.1",
"contentHash": "plTZ3ariSWQVsFn2mk83SsdmSg1VpgIMTSZpP/eSE/NNQF02p+M9ItxAYeUZBMX+cQ2nFkSwxQRJ0/fkaV9Hbg=="
},
"NuGet.Versioning": {
"type": "Direct",
"requested": "[6.11.1, )",
"resolved": "6.11.1",
"contentHash": "YNn3BB71F+guJW42TbAhGcMh3gpyqFMZcPVD9pm5vcvGivTALtRely/VCPWQQ6JQ5PfwIrjPaJMO7VnqyeK3rg=="
}
},
"net8.0/win-x64": {}
}
}