diff --git a/Bonsai.Configuration/OverlayHelper.cs b/Bonsai.Configuration/OverlayHelper.cs index fa8cb9707..9d26e4c62 100644 --- a/Bonsai.Configuration/OverlayHelper.cs +++ b/Bonsai.Configuration/OverlayHelper.cs @@ -1,7 +1,10 @@ using Bonsai.NuGet; using NuGet.Configuration; using NuGet.Packaging; +using NuGet.Packaging.Core; +using NuGet.RuntimeModel; using NuGet.Versioning; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -14,6 +17,22 @@ static class OverlayHelper const string NuGetOverlayCommandFileName = "NuGet-Overlay.cmd"; const string NuGetOverlayCommand = "nuget overlay"; const string NuGetOverlayVersionArgument = "-Version"; + static readonly string[] SupportedRuntimes = new[] { "win-x86", "win-x64" }; + + static RuntimeGraph GetRuntimeGraph(PackageReaderBase packageReader) + { + var runtimeGraphFilePath = packageReader.GetFiles().FirstOrDefault(path => string.Equals( + Path.GetFileName(path), + RuntimeGraph.RuntimeGraphFileName, + StringComparison.OrdinalIgnoreCase)); + if (runtimeGraphFilePath != null) + { + var runtimeGraphStream = packageReader.GetStream(runtimeGraphFilePath); + return JsonRuntimeFormat.ReadRuntimeGraph(runtimeGraphStream); + } + + return null; + } static IEnumerable ReadAllLines(Stream stream) { @@ -26,11 +45,11 @@ static IEnumerable ReadAllLines(Stream stream) } } - public static NuGetVersion FindOverlayVersion(PackageReaderBase package) + static NuGetVersion FindOverlayVersion(PackageReaderBase packageReader) { - return (from file in package.GetFiles() + return (from file in packageReader.GetFiles() where Path.GetFileName(file) == NuGetOverlayCommandFileName - from line in ReadAllLines(package.GetStream(file)) + from line in ReadAllLines(packageReader.GetStream(file)) where line.StartsWith(NuGetOverlayCommand) let version = line.Split(' ') .SkipWhile(xs => xs != NuGetOverlayVersionArgument) @@ -39,12 +58,26 @@ where line.StartsWith(NuGetOverlayCommand) select NuGetVersion.Parse(version)).FirstOrDefault(); } - public static IEnumerable FindPivots(PackageReaderBase package, string installPath) + public static IEnumerable FindPivots(PackageIdentity package, PackageReaderBase packageReader) { - return from file in package.GetFiles() - where Path.GetFileName(file) == PivotListFileName - from pivot in ReadAllLines(package.GetStream(file)) - select pivot; + var runtimeGraph = GetRuntimeGraph(packageReader); + if (runtimeGraph != null) + { + return from runtimeName in SupportedRuntimes + from dependency in runtimeGraph.FindRuntimeDependencies(runtimeName, package.Id) + select new PackageIdentity(dependency.Id, dependency.VersionRange.MinVersion); + } + + var overlayVersion = FindOverlayVersion(packageReader); + if (overlayVersion != null) + { + return from file in packageReader.GetFiles() + where Path.GetFileName(file) == PivotListFileName + from pivot in ReadAllLines(packageReader.GetStream(file)) + select new PackageIdentity(pivot, overlayVersion); + } + + return Enumerable.Empty(); } public static PackageManager CreateOverlayManager(IPackageManager packageManager, string installPath) diff --git a/Bonsai.Configuration/PackageConfigurationUpdater.cs b/Bonsai.Configuration/PackageConfigurationUpdater.cs index f8f7c5518..8d47d8f6d 100644 --- a/Bonsai.Configuration/PackageConfigurationUpdater.cs +++ b/Bonsai.Configuration/PackageConfigurationUpdater.cs @@ -22,7 +22,6 @@ public class PackageConfigurationUpdater : IDisposable const string PackageTagFilter = "Bonsai"; const string GalleryDirectory = "Gallery"; const string ExtensionsDirectory = "Extensions"; - const string BuildDirectory = "build"; const string BinDirectory = "bin"; const string DebugDirectory = "debug"; const string BonsaiExtension = ".bonsai"; @@ -41,6 +40,7 @@ public class PackageConfigurationUpdater : IDisposable static readonly string ContentFolder = PathUtility.EnsureTrailingSlash(PackagingConstants.Folders.Content); static readonly char[] DirectorySeparators = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; static readonly NuGetFramework NativeFramework = NuGetFramework.ParseFrameworkName("native,Version=v0.0", DefaultFrameworkNameProvider.Instance); + static readonly NuGetFramework WindowsFramework = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Windows, FrameworkConstants.EmptyVersion); public PackageConfigurationUpdater(NuGetFramework projectFramework, PackageConfiguration configuration, IPackageManager manager, string bootstrapperPath = null, PackageIdentity bootstrapperName = null) { @@ -57,7 +57,6 @@ public PackageConfigurationUpdater(NuGetFramework projectFramework, PackageConfi var galleryPath = Path.Combine(bootstrapperDirectory, GalleryDirectory); var galleryPackageSource = new PackageSource(galleryPath); galleryRepository = new SourceRepository(galleryPackageSource, Repository.Provider.GetCoreV3()); - bootstrapperFramework = projectFramework; } string GetRelativePath(string path) @@ -117,7 +116,7 @@ static string ResolvePathPlatformName(string path) static IEnumerable GetAssemblyLocations(NuGetFramework projectFramework, PackageReaderBase package) { - var nearestFramework = package.GetItems(BuildDirectory).GetNearest(projectFramework); + var nearestFramework = package.GetItems(PackagingConstants.Folders.Build).GetNearest(projectFramework); if (nearestFramework == null) return Enumerable.Empty(); return from file in nearestFramework.Items @@ -128,7 +127,14 @@ where Path.GetExtension(file) == AssemblyExtension && static IEnumerable GetLibraryFolders(PackageReaderBase package, string installPath) { - var nativeFramework = package.GetItems(BuildDirectory).FirstOrDefault( + var buildFolders = GetBuildLibraryFolders(package, installPath); + var runtimeFolders = GetRuntimeLibraryFolders(package, installPath); + return buildFolders.Concat(runtimeFolders); + } + + static IEnumerable GetBuildLibraryFolders(PackageReaderBase package, string installPath) + { + var nativeFramework = package.GetItems(PackagingConstants.Folders.Build).FirstOrDefault( frameworkGroup => NuGetFramework.FrameworkNameComparer.Equals(frameworkGroup.TargetFramework, NativeFramework)); if (nativeFramework == null) return Enumerable.Empty(); @@ -139,6 +145,17 @@ group file by Path.GetDirectoryName(file) into folder select new LibraryFolder(Path.Combine(installPath, folder.Key), platform); } + static IEnumerable GetRuntimeLibraryFolders(PackageReaderBase package, string installPath) + { + return from frameworkGroup in package.GetItems(PackagingConstants.Folders.Runtimes) + where NuGetFramework.FrameworkNameComparer.Equals(frameworkGroup.TargetFramework, WindowsFramework) + let platform = frameworkGroup.TargetFramework.Profile + where !string.IsNullOrWhiteSpace(platform) + from file in frameworkGroup.Items + group file by new { platform, path = Path.GetDirectoryName(file) } into folder + select new LibraryFolder(Path.Combine(installPath, folder.Key.path), folder.Key.platform); + } + static IEnumerable GetCompatibleAssemblyReferences(NuGetFramework projectFramework, PackageReaderBase package) { var nearestFramework = package.GetReferenceItems().GetNearest(projectFramework); @@ -304,7 +321,7 @@ public PackageConfigurationPlugin(PackageConfigurationUpdater owner) public override async Task OnPackageInstallingAsync(PackageIdentity package, NuGetFramework projectFramework, PackageReaderBase packageReader, string installPath) { var entryPoint = package.Id + BonsaiExtension; - var nearestFrameworkGroup = packageReader.GetContentItems().GetNearest(Owner.bootstrapperFramework); + var nearestFrameworkGroup = packageReader.GetContentItems().GetNearest(projectFramework); var executablePackage = nearestFrameworkGroup?.Items.Any(file => PathUtility.GetRelativePath(ContentFolder, file) == entryPoint); if (executablePackage.GetValueOrDefault()) { @@ -323,19 +340,17 @@ public override async Task OnPackageInstallingAsync(PackageIdentity packag } else { - var pivots = OverlayHelper.FindPivots(packageReader, installPath).ToArray(); + var pivots = OverlayHelper.FindPivots(package, packageReader).ToArray(); if (pivots.Length > 0) { PathUtility.EnsureParentDirectory(Path.Combine(installPath, package.Id)); - var overlayVersion = OverlayHelper.FindOverlayVersion(packageReader); var overlayManager = OverlayHelper.CreateOverlayManager(Owner.packageManager, installPath); overlayManager.Logger = Owner.packageManager.Logger; try { foreach (var pivot in pivots) { - var pivotIdentity = new PackageIdentity(pivot, overlayVersion); - var pivotPackage = await overlayManager.InstallPackageAsync(pivotIdentity, projectFramework, ignoreDependencies: true, CancellationToken.None); + var pivotPackage = await overlayManager.InstallPackageAsync(pivot, projectFramework, ignoreDependencies: true, CancellationToken.None); if (pivotPackage == null) throw new InvalidOperationException(string.Format("The package '{0}' could not be found.", pivot)); } } @@ -343,8 +358,7 @@ public override async Task OnPackageInstallingAsync(PackageIdentity packag { foreach (var pivot in pivots) { - var pivotIdentity = new PackageIdentity(pivot, overlayVersion); - await overlayManager.UninstallPackageAsync(pivotIdentity, projectFramework, removeDependencies: false, CancellationToken.None); + await overlayManager.UninstallPackageAsync(pivot, projectFramework, removeDependencies: false, CancellationToken.None); } throw; } @@ -368,20 +382,20 @@ public override Task OnPackageInstalledAsync(PackageIdentity package, NuGetFrame Owner.AddContentFolders(installPath, ExtensionsDirectory); Owner.RegisterLibraryFolders(packageReader, relativePath); Owner.RegisterAssemblyLocations(packageReader, installPath, relativePath, false); - var pivots = OverlayHelper.FindPivots(packageReader, installPath).ToArray(); + var pivots = OverlayHelper.FindPivots(package, packageReader).ToArray(); if (pivots.Length > 0) { var overlayManager = OverlayHelper.CreateOverlayManager(Owner.packageManager, installPath); foreach (var pivot in pivots) { - var pivotPackage = overlayManager.LocalRepository.FindLocalPackage(pivot); + var pivotPackage = overlayManager.LocalRepository.FindLocalPackage(pivot.Id); using var pivotReader = pivotPackage.GetReader(); Owner.RegisterLibraryFolders(pivotReader, relativePath); Owner.RegisterAssemblyLocations(pivotReader, installPath, relativePath, false); } } - var assemblyLocations = GetCompatibleAssemblyReferences(Owner.bootstrapperFramework, packageReader); + var assemblyLocations = GetCompatibleAssemblyReferences(projectFramework, packageReader); Owner.RegisterAssemblyLocations(assemblyLocations, installPath, relativePath, taggedPackage); packageConfiguration.Save(); @@ -411,13 +425,13 @@ public override async Task OnPackageUninstalledAsync(PackageIdentity package, Nu Owner.RemoveContentFolders(packageReader, installPath, ExtensionsDirectory); Owner.RemoveLibraryFolders(packageReader, relativePath); Owner.RemoveAssemblyLocations(packageReader, relativePath, false); - var pivots = OverlayHelper.FindPivots(packageReader, installPath).ToArray(); + var pivots = OverlayHelper.FindPivots(package, packageReader).ToArray(); if (pivots.Length > 0) { var overlayManager = OverlayHelper.CreateOverlayManager(Owner.packageManager, installPath); foreach (var pivot in pivots) { - var pivotPackage = overlayManager.LocalRepository.FindLocalPackage(pivot); + var pivotPackage = overlayManager.LocalRepository.FindLocalPackage(pivot.Id); if (pivotPackage != null) { using var pivotReader = pivotPackage.GetReader(); @@ -427,19 +441,17 @@ public override async Task OnPackageUninstalledAsync(PackageIdentity package, Nu } } - var assemblyLocations = GetCompatibleAssemblyReferences(Owner.bootstrapperFramework, packageReader); + var assemblyLocations = GetCompatibleAssemblyReferences(projectFramework, packageReader); Owner.RemoveAssemblyLocations(assemblyLocations, relativePath, taggedPackage); Owner.packageConfiguration.Save(); if (pivots.Length > 0) { - var overlayVersion = OverlayHelper.FindOverlayVersion(packageReader); var overlayManager = OverlayHelper.CreateOverlayManager(Owner.packageManager, installPath); overlayManager.Logger = Owner.packageManager.Logger; foreach (var pivot in pivots) { - var pivotIdentity = new PackageIdentity(pivot, overlayVersion); - await overlayManager.UninstallPackageAsync(pivotIdentity, projectFramework, removeDependencies: false, CancellationToken.None); + await overlayManager.UninstallPackageAsync(pivot, projectFramework, removeDependencies: false, CancellationToken.None); } } } diff --git a/Bonsai/Bonsai.csproj b/Bonsai/Bonsai.csproj index 110ba7a6d..d36e2bc44 100644 --- a/Bonsai/Bonsai.csproj +++ b/Bonsai/Bonsai.csproj @@ -6,7 +6,7 @@ Bonsai Rx Reactive Extensions true net472 - 2.6.3 + 2.7.0 Exe true ..\Bonsai.Editor\Bonsai.ico