From 78be6bd83718d207824f98808b0bd480dfe9354b Mon Sep 17 00:00:00 2001 From: zznty <94796179+zznty@users.noreply.github.com> Date: Mon, 28 Oct 2024 00:46:37 +0700 Subject: [PATCH] fix nuget --- CringeBootstrap/packages.lock.json | 24 +++- CringeLauncher/CringeLauncher.csproj | 3 +- CringeLauncher/packages.lock.json | 65 ++++++---- CringePlugins/Config/PackagesConfig.cs | 2 + CringePlugins/CringePlugins.csproj | 3 + CringePlugins/Loader/PluginsLifetime.cs | 22 ++-- CringePlugins/Resolver/BuiltInPackages.cs | 78 ++++++++++++ CringePlugins/Resolver/PackageResolver.cs | 28 ++--- CringePlugins/Utils/IntrospectionContext.cs | 8 +- CringePlugins/packages.lock.json | 90 +++++++++++++- NuGet/Converters/FrameworkJsonConverter.cs | 20 ++- .../ManifestPackageKeyJsonConverter.cs | 5 +- NuGet/Deps/DependenciesManifest.cs | 60 ++++++--- NuGet/Models/CatalogEntry.cs | 8 +- NuGet/Models/DependencyGroup.cs | 5 +- NuGet/Models/PackageType.cs | 3 - NuGet/NuGetClient.cs | 16 ++- NuGet/PackageSourceMapping.cs | 9 +- TestPlugin/TestPlugin.csproj | 1 + TestPlugin/packages.lock.json | 115 ++++++++++++++++++ 20 files changed, 472 insertions(+), 93 deletions(-) create mode 100644 CringePlugins/Resolver/BuiltInPackages.cs delete mode 100644 NuGet/Models/PackageType.cs create mode 100644 TestPlugin/packages.lock.json diff --git a/CringeBootstrap/packages.lock.json b/CringeBootstrap/packages.lock.json index 7e9baad..1ef9944 100644 --- a/CringeBootstrap/packages.lock.json +++ b/CringeBootstrap/packages.lock.json @@ -29,6 +29,22 @@ "NuGet.Versioning": "6.10.1" } }, + "Basic.Reference.Assemblies.Net80": { + "type": "Transitive", + "resolved": "1.7.9", + "contentHash": "1wbS9ZJLFVrKD2jqv27gekIrpjpLffR9sitLQh5drWoG9KbyR/CgrAhw5I0c8Eq3zFMOToCmrpZi3VpRoInCgg==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "4.11.0" + } + }, + "Basic.Reference.Assemblies.Net80Windows": { + "type": "Transitive", + "resolved": "1.7.9", + "contentHash": "98GFm8MC+pv37rTHaxBm5KFucqdJj0jK0XRHSGt2sXK9HNqtGImIFCFahxjUzskQjiUkPAzVhTou2OYZOuhhEg==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "4.11.0" + } + }, "dnlib": { "type": "Transitive", "resolved": "4.4.0", @@ -359,8 +375,8 @@ }, "SpaceEngineersDedicated.ReferenceAssemblies": { "type": "Transitive", - "resolved": "1.205.24", - "contentHash": "cgzWJWflVITp+fY5OPgffcoJ08KL5YHMQrMwaDAkUxfRwPgTzU8qOADsrMqq25vXsEbznU1DzNWwTPviYYi7UA==", + "resolved": "1.205.25", + "contentHash": "+70s6nJnBxEFYZY1qwKfM7FgYBYY6YDSPvbltEXrn7CVAeiWIxbtdcUZ4nDBGVTYqUWEI/r3zbLP1zlcNE27Dg==", "dependencies": { "SharpDX": "4.2.0-keen-cringe", "protobuf-net": "1.0.0" @@ -1294,7 +1310,6 @@ "dependencies": { "CringeBootstrap.Abstractions": "[1.0.0, )", "CringePlugins": "[1.0.0, )", - "ImGui.NET.DirectX": "[1.91.0.1, )", "Lib.Harmony.Thin": "[2.3.3, )", "Microsoft.CodeAnalysis.CSharp": "[4.11.0, )", "NLog": "[5.3.4, )", @@ -1311,6 +1326,9 @@ "cringeplugins": { "type": "Project", "dependencies": { + "Basic.Reference.Assemblies.Net80": "[1.7.9, )", + "Basic.Reference.Assemblies.Net80Windows": "[1.7.9, )", + "ImGui.NET.DirectX": "[1.91.0.1, )", "NLog": "[5.3.4, )", "NuGet": "[1.0.0, )", "SharedCringe": "[1.0.0, )", diff --git a/CringeLauncher/CringeLauncher.csproj b/CringeLauncher/CringeLauncher.csproj index 684e233..2d0da19 100644 --- a/CringeLauncher/CringeLauncher.csproj +++ b/CringeLauncher/CringeLauncher.csproj @@ -18,12 +18,11 @@ - + - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/CringeLauncher/packages.lock.json b/CringeLauncher/packages.lock.json index 0e14f31..d5059be 100644 --- a/CringeLauncher/packages.lock.json +++ b/CringeLauncher/packages.lock.json @@ -8,17 +8,6 @@ "resolved": "4.4.0", "contentHash": "cKHI720q+zfEEvzklWVGt6B0TH3AibAyJbpUJl4U6KvTP13tycfnqJpkGHRZ/oQ45BTIoIxIwltHIJVDN+iCqQ==" }, - "ImGui.NET.DirectX": { - "type": "Direct", - "requested": "[1.91.0.1, )", - "resolved": "1.91.0.1", - "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", - "dependencies": { - "System.Buffers": "4.5.1", - "System.Numerics.Vectors": "4.5.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, "Krafs.Publicizer": { "type": "Direct", "requested": "[2.2.1, )", @@ -67,8 +56,8 @@ "SpaceEngineersDedicated.ReferenceAssemblies": { "type": "Direct", "requested": "[1.*, )", - "resolved": "1.205.24", - "contentHash": "cgzWJWflVITp+fY5OPgffcoJ08KL5YHMQrMwaDAkUxfRwPgTzU8qOADsrMqq25vXsEbznU1DzNWwTPviYYi7UA==", + "resolved": "1.205.25", + "contentHash": "+70s6nJnBxEFYZY1qwKfM7FgYBYY6YDSPvbltEXrn7CVAeiWIxbtdcUZ4nDBGVTYqUWEI/r3zbLP1zlcNE27Dg==", "dependencies": { "SharpDX": "4.2.0-keen-cringe", "protobuf-net": "1.0.0" @@ -132,6 +121,32 @@ "NuGet.Versioning": "6.10.1" } }, + "Basic.Reference.Assemblies.Net80": { + "type": "Transitive", + "resolved": "1.7.9", + "contentHash": "1wbS9ZJLFVrKD2jqv27gekIrpjpLffR9sitLQh5drWoG9KbyR/CgrAhw5I0c8Eq3zFMOToCmrpZi3VpRoInCgg==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "4.11.0" + } + }, + "Basic.Reference.Assemblies.Net80Windows": { + "type": "Transitive", + "resolved": "1.7.9", + "contentHash": "98GFm8MC+pv37rTHaxBm5KFucqdJj0jK0XRHSGt2sXK9HNqtGImIFCFahxjUzskQjiUkPAzVhTou2OYZOuhhEg==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "4.11.0" + } + }, + "ImGui.NET.DirectX": { + "type": "Transitive", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", "resolved": "5.0.0", @@ -363,6 +378,9 @@ "cringeplugins": { "type": "Project", "dependencies": { + "Basic.Reference.Assemblies.Net80": "[1.7.9, )", + "Basic.Reference.Assemblies.Net80Windows": "[1.7.9, )", + "ImGui.NET.DirectX": "[1.91.0.1, )", "NLog": "[5.3.4, )", "NuGet": "[1.0.0, )", "SharedCringe": "[1.0.0, )", @@ -387,17 +405,6 @@ } }, "net8.0-windows10.0.19041/win-x64": { - "ImGui.NET.DirectX": { - "type": "Direct", - "requested": "[1.91.0.1, )", - "resolved": "1.91.0.1", - "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", - "dependencies": { - "System.Buffers": "4.5.1", - "System.Numerics.Vectors": "4.5.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, "Steamworks.NET": { "type": "Direct", "requested": "[20.1.0, )", @@ -422,6 +429,16 @@ "System.CodeDom": "8.0.0" } }, + "ImGui.NET.DirectX": { + "type": "Transitive", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, "System.Diagnostics.EventLog": { "type": "Transitive", "resolved": "8.0.0", diff --git a/CringePlugins/Config/PackagesConfig.cs b/CringePlugins/Config/PackagesConfig.cs index 9d7c8db..3084539 100644 --- a/CringePlugins/Config/PackagesConfig.cs +++ b/CringePlugins/Config/PackagesConfig.cs @@ -8,6 +8,8 @@ namespace CringePlugins.Config; public record PackagesConfig(ImmutableArray Sources, ImmutableArray Packages) { public static PackagesConfig Default { get; } = new([ + new("SpaceEngineersDedicated.ReferenceAssemblies", "https://nuget.storage.yandexcloud.net/index.json"), + new("ImGui.NET.DirectX", "https://nuget.storage.yandexcloud.net/index.json"), new(string.Empty, "https://api.nuget.org/v3/index.json") ], []); } \ No newline at end of file diff --git a/CringePlugins/CringePlugins.csproj b/CringePlugins/CringePlugins.csproj index 8146a47..39fbba1 100644 --- a/CringePlugins/CringePlugins.csproj +++ b/CringePlugins/CringePlugins.csproj @@ -21,7 +21,10 @@ + + + diff --git a/CringePlugins/Loader/PluginsLifetime.cs b/CringePlugins/Loader/PluginsLifetime.cs index 21078f3..88fed83 100644 --- a/CringePlugins/Loader/PluginsLifetime.cs +++ b/CringePlugins/Loader/PluginsLifetime.cs @@ -8,6 +8,7 @@ using NLog; using NuGet; using NuGet.Deps; using NuGet.Frameworks; +using NuGet.Versioning; namespace CringePlugins.Loader; @@ -19,7 +20,7 @@ public class PluginsLifetime : ILoadingStage private ImmutableArray _plugins = []; private readonly DirectoryInfo _dir = Directory.CreateDirectory(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CringeLauncher")); - private readonly NuGetFramework _runtimeFramework = NuGetFramework.ParseFolder("net8.0-windows"); + private readonly NuGetFramework _runtimeFramework = NuGetFramework.ParseFolder("net8.0-windows10.0.19041.0"); public async ValueTask Load(ISplashProgress progress) { @@ -83,18 +84,25 @@ public class PluginsLifetime : ILoadingStage private async Task LoadPlugins(IReadOnlySet packages, PackageSourceMapping sourceMapping) { var plugins = _plugins.ToBuilder(); + + var packageVersions = BuiltInPackages.GetPackages(_runtimeFramework) + .ToImmutableDictionary(b => b.Package.Id, b => b.Package.Version, + StringComparer.OrdinalIgnoreCase); + + packageVersions = packageVersions.AddRange(packages.Select(b => + new KeyValuePair(b.Package.Id, b.Package.Version))); + + var manifestBuilder = new DependencyManifestBuilder(_dir.CreateSubdirectory("cache"), sourceMapping, + dependency => packageVersions.TryGetValue(dependency.Id, out var version) && version.Major != 99 + ? version + : dependency.Range.MinVersion ?? dependency.Range.MaxVersion); foreach (var package in packages) { var dir = Path.Join(package.Directory.FullName, "lib", package.ResolvedFramework.GetShortFolderName()); await using (var stream = File.Create(Path.Join(dir, $"{package.Package.Id}.deps.json"))) - await DependencyManifestUtility.WriteDependencyManifestAsync(stream, package.Entry, _runtimeFramework, - sourceMapping, - dependency => - packages.First(b => b.Package.Id.Equals(dependency.Id, StringComparison.OrdinalIgnoreCase)) - .Package - .Version); + await manifestBuilder.WriteDependencyManifestAsync(stream, package.Entry, _runtimeFramework); LoadComponent(plugins, Path.Join(dir, $"{package.Package.Id}.dll")); } diff --git a/CringePlugins/Resolver/BuiltInPackages.cs b/CringePlugins/Resolver/BuiltInPackages.cs new file mode 100644 index 0000000..fb6dd3e --- /dev/null +++ b/CringePlugins/Resolver/BuiltInPackages.cs @@ -0,0 +1,78 @@ +using System.Collections.Immutable; +using System.Reflection; +using Basic.Reference.Assemblies; +using CringePlugins.Loader; +using CringePlugins.Utils; +using dnlib.DotNet; +using ImGuiNET; +using Microsoft.CodeAnalysis; +using NLog; +using NuGet.Frameworks; +using NuGet.Models; +using NuGet.Versioning; +using Sandbox.Game; +using SpaceEngineers.Game; +using VRage.Utils; + +namespace CringePlugins.Resolver; + +public static class BuiltInPackages +{ + private const string SeReferenceAssemblies = "SpaceEngineersDedicated.ReferenceAssemblies"; + private const string ImGui = "ImGui.NET.DirectX"; + + public static ImmutableArray GetPackages(NuGetFramework runtimeFramework) + { + var nlog = FromAssembly(runtimeFramework, version: new(5, 3, 4)); + Version seVersion = new MyVersion(MyPerGameSettings.BasicGameInfo.GameVersion!.Value); + + var se = FromAssembly(runtimeFramework, [ + nlog.AsDependency() + ], SeReferenceAssemblies, new(seVersion)); + var imGui = FromAssembly(runtimeFramework, id: ImGui); + + BuiltInSdkPackage MapSdkPackage( + (string FileName, byte[] ImageBytes, PortableExecutableReference Reference, Guid Mvid) r) + { + var def = ModuleDefMD.Load(r.ImageBytes, IntrospectionContext.Global.Context); + var attribute = def.CustomAttributes.Find(typeof(AssemblyFileVersionAttribute).FullName); + var version = attribute is null ? new(99, 0, 0) : NuGetVersion.Parse((string)attribute.ConstructorArguments[0].Value); + + return new BuiltInSdkPackage( + new(0, Path.GetFileNameWithoutExtension(r.FileName), version, []), runtimeFramework, + new(Path.GetFileNameWithoutExtension(r.FileName), version, [new(runtimeFramework, [])], null, [])); + } + + return + [ + ..Net80.ReferenceInfos.AllValues.Select(MapSdkPackage), + ..Net80Windows.ReferenceInfos.AllValues.Select(MapSdkPackage), + nlog, + se, + imGui, + FromAssembly(runtimeFramework, [se.AsDependency(), imGui.AsDependency()]), + ]; + } + + private static Dependency AsDependency(this ResolvedPackage package) => new(package.Package.Id, new(package.Package.Version)); + + private static BuiltInPackage FromAssembly(NuGetFramework runtimeFramework, ImmutableArray? dependencies = null, string? id = null, NuGetVersion? version = null) + { + var assembly = typeof(T).Assembly.GetName(); + id ??= assembly.Name!; + version ??= new NuGetVersion(assembly.Version ?? new(0, 0, 0)); + dependencies ??= []; + + return new( + new(0, id, version, [..dependencies.Value.Select(b => b.Id)]), + runtimeFramework, + new(id, version, [ + new(runtimeFramework, dependencies.Value) + ], null, []) + ); + } +} + +public record BuiltInPackage(Package Package, NuGetFramework ResolvedFramework, CatalogEntry Entry) : ResolvedPackage(Package, ResolvedFramework, Entry); + +public record BuiltInSdkPackage(Package Package, NuGetFramework ResolvedFramework, CatalogEntry Entry) : BuiltInPackage(Package, ResolvedFramework, Entry); \ No newline at end of file diff --git a/CringePlugins/Resolver/PackageResolver.cs b/CringePlugins/Resolver/PackageResolver.cs index fbb2043..ec0e6ac 100644 --- a/CringePlugins/Resolver/PackageResolver.cs +++ b/CringePlugins/Resolver/PackageResolver.cs @@ -12,7 +12,7 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray> ResolveAsync() { var order = 0; - var packages = new SortedSet(); + var packages = new SortedDictionary(); foreach (var reference in references) { @@ -20,25 +20,25 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray b.CatalogEntry.PackageTypes is [{ Name: "CringePlugin" }]).Select(b => b.CatalogEntry.Version)); - if (version is not null) - break; - } + var items = registrationRoot.Items.SelectMany(page => + page.Items.Where(b => b.CatalogEntry.PackageTypes is ["CringePlugin"])) + .ToImmutableDictionary(b => b.CatalogEntry.Version); + + var version = reference.Range.FindBestMatch(items.Values.Select(b => b.CatalogEntry.Version)); if (version is null) throw new Exception($"Unable to find version for package {reference.Id}"); var package = new Package(order, reference.Id, version, []); // todo resolve dependencies - if (packages.Add(package)) + if (packages.TryAdd(package, items[version].CatalogEntry)) continue; - if (!packages.TryGetValue(package, out var existingPackage)) + if (!packages.TryGetValue(package, out _)) throw new Exception($"Duplicate package {package.Id}"); + var existingPackage = packages.Keys.First(b => b.Version == package.Version && b.Id == package.Id); + if (package.Version < existingPackage.Version) throw new Exception($"Package reference {package.Id} has lower version {package.Version} than already resolved {existingPackage.Version}"); @@ -49,17 +49,13 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray.Empty.ToBuilder(); - foreach (var package in packages) + foreach (var (package, catalogEntry) in packages) { var client = await packageSources.GetClientAsync(package.Id); - - var (catalogEntryUrl, catalogEntry) = await client.GetPackageRegistrationAsync(package.Id, package.Version); - - catalogEntry ??= await client.GetPackageCatalogEntryAsync(catalogEntryUrl); var nearestGroup = NuGetFrameworkUtility.GetNearest(catalogEntry.DependencyGroups, runtimeFramework, g => g.TargetFramework); diff --git a/CringePlugins/Utils/IntrospectionContext.cs b/CringePlugins/Utils/IntrospectionContext.cs index d58158b..44de507 100644 --- a/CringePlugins/Utils/IntrospectionContext.cs +++ b/CringePlugins/Utils/IntrospectionContext.cs @@ -6,12 +6,12 @@ namespace CringePlugins.Utils; public class IntrospectionContext { public static IntrospectionContext Global { get; } = new(); - - private readonly ModuleContext _context = ModuleDef.CreateModuleContext(); + + internal readonly ModuleContext Context = ModuleDef.CreateModuleContext(); public IEnumerable CollectAttributedTypes(Module module, bool allowAbstract = false) where TAttribute : Attribute { - var moduleDef = ModuleDefMD.Load(module, _context); + var moduleDef = ModuleDefMD.Load(module, Context); return moduleDef.GetTypes() .Where(b => b.CustomAttributes.IsDefined(typeof(TAttribute).FullName) && (allowAbstract || !b.IsAbstract)) @@ -20,7 +20,7 @@ public class IntrospectionContext public IEnumerable CollectDerivedTypes(Module module, bool allowAbstract = false) { - var moduleDef = ModuleDefMD.Load(module, _context); + var moduleDef = ModuleDefMD.Load(module, Context); var token = moduleDef.ImportAsTypeSig(typeof(T)); diff --git a/CringePlugins/packages.lock.json b/CringePlugins/packages.lock.json index 7905d0f..0b38dbb 100644 --- a/CringePlugins/packages.lock.json +++ b/CringePlugins/packages.lock.json @@ -2,12 +2,41 @@ "version": 1, "dependencies": { "net8.0-windows7.0": { + "Basic.Reference.Assemblies.Net80": { + "type": "Direct", + "requested": "[1.7.9, )", + "resolved": "1.7.9", + "contentHash": "1wbS9ZJLFVrKD2jqv27gekIrpjpLffR9sitLQh5drWoG9KbyR/CgrAhw5I0c8Eq3zFMOToCmrpZi3VpRoInCgg==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "4.11.0" + } + }, + "Basic.Reference.Assemblies.Net80Windows": { + "type": "Direct", + "requested": "[1.7.9, )", + "resolved": "1.7.9", + "contentHash": "98GFm8MC+pv37rTHaxBm5KFucqdJj0jK0XRHSGt2sXK9HNqtGImIFCFahxjUzskQjiUkPAzVhTou2OYZOuhhEg==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "4.11.0" + } + }, "dnlib": { "type": "Direct", "requested": "[4.4.0, )", "resolved": "4.4.0", "contentHash": "cKHI720q+zfEEvzklWVGt6B0TH3AibAyJbpUJl4U6KvTP13tycfnqJpkGHRZ/oQ45BTIoIxIwltHIJVDN+iCqQ==" }, + "ImGui.NET.DirectX": { + "type": "Direct", + "requested": "[1.91.0.1, )", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, "Krafs.Publicizer": { "type": "Direct", "requested": "[2.2.1, )", @@ -23,13 +52,28 @@ "SpaceEngineersDedicated.ReferenceAssemblies": { "type": "Direct", "requested": "[1.*, )", - "resolved": "1.205.24", - "contentHash": "cgzWJWflVITp+fY5OPgffcoJ08KL5YHMQrMwaDAkUxfRwPgTzU8qOADsrMqq25vXsEbznU1DzNWwTPviYYi7UA==", + "resolved": "1.205.25", + "contentHash": "+70s6nJnBxEFYZY1qwKfM7FgYBYY6YDSPvbltEXrn7CVAeiWIxbtdcUZ4nDBGVTYqUWEI/r3zbLP1zlcNE27Dg==", "dependencies": { "SharpDX": "4.2.0-keen-cringe", "protobuf-net": "1.0.0" } }, + "Microsoft.CodeAnalysis.Analyzers": { + "type": "Transitive", + "resolved": "3.3.4", + "contentHash": "AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==" + }, + "Microsoft.CodeAnalysis.Common": { + "type": "Transitive", + "resolved": "4.11.0", + "contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==", + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + } + }, "NuGet.Frameworks": { "type": "Transitive", "resolved": "6.11.1", @@ -50,6 +94,34 @@ "resolved": "4.2.0-keen-cringe", "contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw==" }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Collections.Immutable": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==" + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "dependencies": { + "System.Collections.Immutable": "8.0.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, "cringebootstrap.abstractions": { "type": "Project" }, @@ -69,6 +141,18 @@ } } }, - "net8.0-windows7.0/win-x64": {} + "net8.0-windows7.0/win-x64": { + "ImGui.NET.DirectX": { + "type": "Direct", + "requested": "[1.91.0.1, )", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + } + } } } \ No newline at end of file diff --git a/NuGet/Converters/FrameworkJsonConverter.cs b/NuGet/Converters/FrameworkJsonConverter.cs index 0327247..24cb9bb 100644 --- a/NuGet/Converters/FrameworkJsonConverter.cs +++ b/NuGet/Converters/FrameworkJsonConverter.cs @@ -6,7 +6,7 @@ namespace NuGet.Converters; public class FrameworkJsonConverter(FrameworkNameFormat format) : JsonConverter { - public override NuGetFramework? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override NuGetFramework Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.String) throw new JsonException("Invalid framework string"); @@ -23,12 +23,26 @@ public class FrameworkJsonConverter(FrameworkNameFormat format) : JsonConverter< public override void Write(Utf8JsonWriter writer, NuGetFramework value, JsonSerializerOptions options) { - writer.WriteStringValue(format switch + 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)); } } diff --git a/NuGet/Converters/ManifestPackageKeyJsonConverter.cs b/NuGet/Converters/ManifestPackageKeyJsonConverter.cs index fb99a0d..46058fc 100644 --- a/NuGet/Converters/ManifestPackageKeyJsonConverter.cs +++ b/NuGet/Converters/ManifestPackageKeyJsonConverter.cs @@ -23,5 +23,8 @@ public class ManifestPackageKeyJsonConverter : JsonConverter JsonSerializerOptions options) => Read(ref reader, typeToConvert, options); public override void WriteAsPropertyName(Utf8JsonWriter writer, ManifestPackageKey value, - JsonSerializerOptions options) => Write(writer, value, options); + JsonSerializerOptions options) + { + writer.WritePropertyName(value.ToString()); + } } \ No newline at end of file diff --git a/NuGet/Deps/DependenciesManifest.cs b/NuGet/Deps/DependenciesManifest.cs index c74d0c9..b726c4b 100644 --- a/NuGet/Deps/DependenciesManifest.cs +++ b/NuGet/Deps/DependenciesManifest.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using System.IO.Compression; using System.Runtime.InteropServices; using System.Text.Json; using System.Text.Json.Serialization; @@ -55,7 +56,7 @@ public record ManifestPackageKey(string Id, NuGetVersion Version) public override string ToString() => $"{Id}/{Version}"; } -public static class DependencyManifestUtility +public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSourceMapping packageSources, Func versionResolver) { private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web) { @@ -68,14 +69,13 @@ public static class DependencyManifestUtility } }; - public static async ValueTask WriteDependencyManifestAsync(Stream stream, CatalogEntry catalogEntry, NuGetFramework targetFramework, - PackageSourceMapping packageSources, Func versionResolver) + public async ValueTask WriteDependencyManifestAsync(Stream stream, CatalogEntry catalogEntry, NuGetFramework targetFramework) { var runtimeTarget = new RuntimeTarget(targetFramework); var targets = ImmutableDictionary.Empty.ToBuilder(); - await MapCatalogEntry(catalogEntry, targetFramework, packageSources, versionResolver, targets); + await MapCatalogEntryAsync(catalogEntry, targetFramework, targets); var manifest = new DependenciesManifest(runtimeTarget, ImmutableDictionary.Empty, ImmutableDictionary>.Empty @@ -85,8 +85,8 @@ public static class DependencyManifestUtility await JsonSerializer.SerializeAsync(stream, manifest, SerializerOptions); } - private static async Task MapCatalogEntry(CatalogEntry catalogEntry, NuGetFramework targetFramework, - PackageSourceMapping packageSources, Func versionResolver, ImmutableDictionary.Builder targets) + private async Task MapCatalogEntryAsync(CatalogEntry catalogEntry, NuGetFramework targetFramework, + ImmutableDictionary.Builder targets) { if (targets.ContainsKey(new(catalogEntry.Id, catalogEntry.Version))) return; @@ -98,26 +98,58 @@ public static class DependencyManifestUtility return; targets.Add(new(catalogEntry.Id, catalogEntry.Version), - MapEntry(catalogEntry, nearest, targetFramework, versionResolver)); + await MapEntryAsync(catalogEntry, nearest)); - foreach (var dependency in nearest.Dependencies) + foreach (var dependency in nearest.Dependencies ?? []) { var client = await packageSources.GetClientAsync(dependency.Id); - var (url, entry) = await client.GetPackageRegistrationAsync(dependency.Id, versionResolver(dependency)); + var (url, entry) = await client.GetPackageRegistrationAsync(dependency.Id, versionResolver(dependency)!); entry ??= await client.GetPackageCatalogEntryAsync(url); - await MapCatalogEntry(entry, targetFramework, packageSources, versionResolver, targets); + await MapCatalogEntryAsync(entry, targetFramework, targets); } } - private static DependencyTarget MapEntry(CatalogEntry entry, DependencyGroup group, NuGetFramework targetFramework, Func versionResolver) + private async Task MapEntryAsync(CatalogEntry entry, DependencyGroup group) { - return new(group.Dependencies.ToImmutableDictionary(b => b.Id, versionResolver), - entry.PackageEntries.Where(b => b.FullName.StartsWith($"lib/{targetFramework.GetShortFolderName()}/")) + var packageEntries = entry.PackageEntries ?? await GetPackageContent(entry); + + return new(group.Dependencies?.ToImmutableDictionary(b => b.Id, versionResolver) ?? ImmutableDictionary.Empty, + packageEntries.Where(b => b.FullName.StartsWith($"lib/{group.TargetFramework.GetShortFolderName()}/")) .ToImmutableDictionary(b => b.FullName, _ => new RuntimeDependency()), - entry.PackageEntries.Where(b => + packageEntries.Where(b => b.FullName.StartsWith($"runtimes/{RuntimeInformation.RuntimeIdentifier}/native/")) .ToImmutableDictionary(b => b.FullName, _ => new Dependency())); } + + private async Task> 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); + } + } + } } \ No newline at end of file diff --git a/NuGet/Models/CatalogEntry.cs b/NuGet/Models/CatalogEntry.cs index b943755..b36d143 100644 --- a/NuGet/Models/CatalogEntry.cs +++ b/NuGet/Models/CatalogEntry.cs @@ -1,9 +1,9 @@ -using NuGet.Versioning; +using System.Collections.Immutable; +using NuGet.Versioning; namespace NuGet.Models; -public record CatalogEntry(string Id, NuGetVersion Version, DependencyGroup[] DependencyGroups, PackageType[]? PackageTypes, - CatalogPackageEntry[] PackageEntries, - bool Serviceable = true); +public record CatalogEntry(string Id, NuGetVersion Version, ImmutableArray DependencyGroups, ImmutableArray? PackageTypes, + ImmutableArray? PackageEntries); public record CatalogPackageEntry(string Name, string FullName, long CompressedLength, long Length); \ No newline at end of file diff --git a/NuGet/Models/DependencyGroup.cs b/NuGet/Models/DependencyGroup.cs index 4c7a3b5..f77c3b5 100644 --- a/NuGet/Models/DependencyGroup.cs +++ b/NuGet/Models/DependencyGroup.cs @@ -1,5 +1,6 @@ -using NuGet.Frameworks; +using System.Collections.Immutable; +using NuGet.Frameworks; namespace NuGet.Models; -public record DependencyGroup(NuGetFramework TargetFramework, Dependency[] Dependencies); \ No newline at end of file +public record DependencyGroup(NuGetFramework TargetFramework, ImmutableArray? Dependencies = null); \ No newline at end of file diff --git a/NuGet/Models/PackageType.cs b/NuGet/Models/PackageType.cs deleted file mode 100644 index b1d767f..0000000 --- a/NuGet/Models/PackageType.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace NuGet.Models; - -public record PackageType(string Name); \ No newline at end of file diff --git a/NuGet/NuGetClient.cs b/NuGet/NuGetClient.cs index c7c30dd..7d4fc80 100644 --- a/NuGet/NuGetClient.cs +++ b/NuGet/NuGetClient.cs @@ -1,4 +1,5 @@ -using System.Net.Http.Json; +using System.Net; +using System.Net.Http.Json; using System.Text.Json; using NuGet.Converters; using NuGet.Models; @@ -32,8 +33,9 @@ public class NuGetClient public Task GetPackageContentStreamAsync(string id, NuGetVersion version) { + id = id.ToLower(); return _client.GetStreamAsync(new Uri(_packageBaseAddress, - new Uri($"{id.ToLower()}/{version}.nupkg", UriKind.Relative))); + new Uri($"{id}/{version}/{id}.{version}.nupkg", UriKind.Relative))); } public Task GetPackageRegistrationAsync(string id, NuGetVersion version) @@ -61,12 +63,20 @@ public class NuGetClient public static async Task CreateFromIndexUrlAsync(string indexUrl) { - var client = new HttpClient(); + var client = new HttpClient(new HttpClientHandler + { + AutomaticDecompression = DecompressionMethods.All + }); var index = await client.GetFromJsonAsync(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)); } diff --git a/NuGet/PackageSourceMapping.cs b/NuGet/PackageSourceMapping.cs index 5cda169..4d22b8f 100644 --- a/NuGet/PackageSourceMapping.cs +++ b/NuGet/PackageSourceMapping.cs @@ -4,13 +4,14 @@ namespace NuGet; public class PackageSourceMapping(ImmutableArray sources) { - private readonly ImmutableDictionary> _clients = sources.Select(b => - new KeyValuePair>(b.Pattern, + private readonly ImmutableArray<(string pattern, Task client)> _clients = [ + ..sources.Select(b => + (b.Pattern, NuGetClient.CreateFromIndexUrlAsync(b.Url))) - .ToImmutableDictionary(); + ]; public Task GetClientAsync(string packageId) => - _clients.FirstOrDefault(b => packageId.StartsWith(b.Key)).Value; + _clients.FirstOrDefault(b => packageId.StartsWith(b.pattern)).client; } public record PackageSource(string Pattern, string Url); \ No newline at end of file diff --git a/TestPlugin/TestPlugin.csproj b/TestPlugin/TestPlugin.csproj index cc2ecfc..21f64a6 100644 --- a/TestPlugin/TestPlugin.csproj +++ b/TestPlugin/TestPlugin.csproj @@ -7,6 +7,7 @@ enable true true + CringePlugin diff --git a/TestPlugin/packages.lock.json b/TestPlugin/packages.lock.json new file mode 100644 index 0000000..070b0a2 --- /dev/null +++ b/TestPlugin/packages.lock.json @@ -0,0 +1,115 @@ +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": { + "ImGui.NET.DirectX": { + "type": "Direct", + "requested": "[1.91.0.1, )", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "NLog": { + "type": "Direct", + "requested": "[5.3.4, )", + "resolved": "5.3.4", + "contentHash": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A==" + }, + "SpaceEngineersDedicated.ReferenceAssemblies": { + "type": "Direct", + "requested": "[1.*, )", + "resolved": "1.205.24", + "contentHash": "cgzWJWflVITp+fY5OPgffcoJ08KL5YHMQrMwaDAkUxfRwPgTzU8qOADsrMqq25vXsEbznU1DzNWwTPviYYi7UA==", + "dependencies": { + "SharpDX": "4.2.0-keen-cringe", + "protobuf-net": "1.0.0" + } + }, + "dnlib": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cKHI720q+zfEEvzklWVGt6B0TH3AibAyJbpUJl4U6KvTP13tycfnqJpkGHRZ/oQ45BTIoIxIwltHIJVDN+iCqQ==" + }, + "NuGet.Frameworks": { + "type": "Transitive", + "resolved": "6.11.1", + "contentHash": "plTZ3ariSWQVsFn2mk83SsdmSg1VpgIMTSZpP/eSE/NNQF02p+M9ItxAYeUZBMX+cQ2nFkSwxQRJ0/fkaV9Hbg==" + }, + "NuGet.Versioning": { + "type": "Transitive", + "resolved": "6.11.1", + "contentHash": "YNn3BB71F+guJW42TbAhGcMh3gpyqFMZcPVD9pm5vcvGivTALtRely/VCPWQQ6JQ5PfwIrjPaJMO7VnqyeK3rg==" + }, + "protobuf-net": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "kTGOK0E87473sOImOjgZOnz3kTC2aMLffoRWQLYNuBLJnwNNmjanF9IkevZ9Q7yYLeABQfcF3BpeepuMntMVNw==" + }, + "SharpDX": { + "type": "Transitive", + "resolved": "4.2.0-keen-cringe", + "contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw==" + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "cringebootstrap.abstractions": { + "type": "Project" + }, + "cringeplugins": { + "type": "Project", + "dependencies": { + "NLog": "[5.3.4, )", + "NuGet": "[1.0.0, )", + "SharedCringe": "[1.0.0, )", + "SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )", + "dnlib": "[4.4.0, )" + } + }, + "nuget": { + "type": "Project", + "dependencies": { + "NuGet.Frameworks": "[6.11.1, )", + "NuGet.Versioning": "[6.11.1, )" + } + }, + "sharedcringe": { + "type": "Project", + "dependencies": { + "CringeBootstrap.Abstractions": "[1.0.0, )", + "NLog": "[5.3.4, )", + "SpaceEngineersDedicated.ReferenceAssemblies": "[1.*, )" + } + } + }, + "net8.0-windows7.0/win-x64": { + "ImGui.NET.DirectX": { + "type": "Direct", + "requested": "[1.91.0.1, )", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + } + } + } +} \ No newline at end of file