From 59f344da25deea09f524ff574fc52fdfa82ae80e Mon Sep 17 00:00:00 2001 From: zznty <94796179+zznty@users.noreply.github.com> Date: Thu, 10 Jul 2025 16:46:53 +0700 Subject: [PATCH] fix plugin dependencies resolution at runtime --- CringePlugins/Loader/PluginsLifetime.cs | 23 ++++++++++++++++++- NuGet/Deps/DependenciesManifest.cs | 30 ++++++++++++++++--------- NuGet/Models/NuGetRuntimeFramework.cs | 2 +- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/CringePlugins/Loader/PluginsLifetime.cs b/CringePlugins/Loader/PluginsLifetime.cs index 86f1d38..f7c1106 100644 --- a/CringePlugins/Loader/PluginsLifetime.cs +++ b/CringePlugins/Loader/PluginsLifetime.cs @@ -58,6 +58,8 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client, D var resolver = new PackageResolver(_runtimeFramework.Framework, packagesConfig.Packages, sourceMapping); var cacheDir = dir.CreateSubdirectory("cache"); + + InitializeSharedStore(ref cacheDir); var invalidPackages = new List(); var packages = await resolver.ResolveAsync(cacheDir, launcherConfig.DisablePluginUpdates, invalidPackages); @@ -149,7 +151,7 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client, D foreach (var package in packages) { - if (builtInPackages.ContainsKey(package.Package.Id)) continue; + if (builtInPackages.ContainsKey(package.Package.Id) || package.Entry.PackageTypes is not ["CringePlugin"]) continue; var packageClient = await sourceMapping.GetClientAsync(package.Package.Id); @@ -219,4 +221,23 @@ internal class PluginsLifetime(ConfigHandler configHandler, HttpClient client, D Log.Error(e, "Failed to load plugin {PluginPath}", path); } } + + // initializes dotnet shared store for plugin resolver to look for dependencies + private void InitializeSharedStore(ref DirectoryInfo cacheDir) + { + const string envVar = "DOTNET_SHARED_STORE"; + + string[] paths = []; + if (Environment.GetEnvironmentVariable(envVar) is { } value) + { + paths = value.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); + } + + paths = [cacheDir.FullName, ..paths]; + + Environment.SetEnvironmentVariable(envVar, string.Join(Path.PathSeparator, paths)); + + cacheDir = cacheDir.CreateSubdirectory("x64"); // todo change this to automatic if we ever get to aarch64 + cacheDir = cacheDir.CreateSubdirectory(new NuGetFramework(_runtimeFramework.Framework.Framework, _runtimeFramework.Framework.Version).GetShortFolderName()); + } } \ No newline at end of file diff --git a/NuGet/Deps/DependenciesManifest.cs b/NuGet/Deps/DependenciesManifest.cs index 53b6800..2257220 100644 --- a/NuGet/Deps/DependenciesManifest.cs +++ b/NuGet/Deps/DependenciesManifest.cs @@ -84,21 +84,25 @@ public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSour var runtimeTarget = new RuntimeTarget(targetFramework); var targets = ImmutableDictionary.Empty.ToBuilder(); + var libraries = ImmutableDictionary.Empty.ToBuilder(); - await MapCatalogEntryAsync(catalogEntry, targetFramework, targets); + await MapCatalogEntryAsync(catalogEntry, targetFramework, targets, libraries); var manifest = new DependenciesManifest(runtimeTarget, ImmutableDictionary.Empty, ImmutableDictionary>.Empty .Add(targetFramework, targets.ToImmutable()), - ImmutableDictionary.Empty); + libraries.ToImmutable()); await DependencyManifestSerializer.SerializeAsync(stream, manifest); } private async Task MapCatalogEntryAsync(CatalogEntry catalogEntry, NuGetRuntimeFramework targetFramework, - ImmutableDictionary.Builder targets) + ImmutableDictionary.Builder targets, + ImmutableDictionary.Builder libraries) { - if (targets.ContainsKey(new(catalogEntry.Id, catalogEntry.Version)) || !catalogEntry.DependencyGroups.HasValue) + var packageKey = new ManifestPackageKey(catalogEntry.Id, catalogEntry.Version); + + if (targets.ContainsKey(packageKey) || !catalogEntry.DependencyGroups.HasValue) return; // TODO take into account the target framework runtime identifier @@ -108,15 +112,18 @@ public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSour if (nearest is null) return; - targets.Add(new(catalogEntry.Id, catalogEntry.Version), + targets.Add(packageKey, await MapEntryAsync(catalogEntry, nearest)); + libraries.Add(packageKey, + new DependencyLibrary(LibraryType.Package, Serviceable: true, Path: packageKey)); + foreach (var entry in (nearest.Dependencies ?? []).Select(catalogEntryResolver)) { if (entry is null) continue; - await MapCatalogEntryAsync(entry, targetFramework, targets); + await MapCatalogEntryAsync(entry, targetFramework, targets, libraries); } } @@ -127,11 +134,12 @@ public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSour return new( group.Dependencies?.ToImmutableDictionary(b => b.Id, b => catalogEntryResolver(b)!.Version) ?? ImmutableDictionary.Empty, - packageEntries.Where(b => b.FullName.StartsWith($"lib/{group.TargetFramework.GetShortFolderName()}/")) - .ToImmutableDictionary(b => b.FullName, _ => new RuntimeDependency()), + packageEntries.Where(b => b.FullName.StartsWith($@"lib\{group.TargetFramework.GetShortFolderName()}\") && + Path.GetExtension(b.FullName.AsSpan()) is ".dll") + .ToImmutableDictionary(b => b.FullName.Replace('\\', '/'), _ => new RuntimeDependency()), packageEntries.Where(b => - b.FullName.StartsWith($"runtimes/{RuntimeInformation.RuntimeIdentifier}/native/")) - .ToImmutableDictionary(b => b.FullName, _ => new Dependency())); + b.FullName.StartsWith($@"runtimes\{RuntimeInformation.RuntimeIdentifier}\native\")) + .ToImmutableDictionary(b => b.FullName.Replace('\\', '/'), _ => new Dependency())); } private async Task> GetPackageContent(CatalogEntry entry) @@ -145,7 +153,7 @@ public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSour return [ ..dir.EnumerateFiles("*", SearchOption.AllDirectories) - .Select(b => new CatalogPackageEntry(b.Name, b.FullName, b.Length, b.Length)) + .Select(b => new CatalogPackageEntry(b.Name, Path.GetRelativePath(dir.FullName, b.FullName), b.Length, b.Length)) ]; } diff --git a/NuGet/Models/NuGetRuntimeFramework.cs b/NuGet/Models/NuGetRuntimeFramework.cs index 5305acd..a06f1c3 100644 --- a/NuGet/Models/NuGetRuntimeFramework.cs +++ b/NuGet/Models/NuGetRuntimeFramework.cs @@ -22,6 +22,6 @@ public record NuGetRuntimeFramework(NuGetFramework Framework, string? RuntimeIde public override string ToString() { - return string.IsNullOrEmpty(RuntimeIdentifier) ? Framework.ToString() : $"{Framework}/{RuntimeIdentifier}"; + return string.IsNullOrEmpty(RuntimeIdentifier) ? Framework.DotNetFrameworkName : $"{Framework.DotNetFrameworkName}/{RuntimeIdentifier}"; } } \ No newline at end of file