Skip to content

Commit

Permalink
Merge pull request #891 from WildGums/feature/allow_multiple_versions
Browse files Browse the repository at this point in the history
allow to install multiple versions of the same packages
  • Loading branch information
mkhomutov authored Jan 15, 2025
2 parents b39a5a5 + cc1fb27 commit 04aae21
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,23 @@ namespace Orc.NuGetExplorer
string GetDirectory(string relativeDirectoryName);
string GetFile(string relativeFilePath);
}
[System.Runtime.CompilerServices.RequiredMember]
public class InstallationContext
{
[System.Obsolete(("Constructors of types with required members are not supported in this version of " +
"your compiler."), true)]
[System.Runtime.CompilerServices.CompilerFeatureRequired("RequiredMembers")]
public InstallationContext() { }
public bool AllowMultipleVersions { get; set; }
public bool IgnoreMissingPackages { get; set; }
[System.Runtime.CompilerServices.RequiredMember]
public NuGet.Packaging.Core.PackageIdentity Package { get; set; }
public System.Func<NuGet.Packaging.Core.PackageIdentity, bool>? PackagePredicate { get; set; }
[System.Runtime.CompilerServices.RequiredMember]
public Orc.NuGetExplorer.IExtensibleProject Project { get; set; }
[System.Runtime.CompilerServices.RequiredMember]
public System.Collections.Generic.IReadOnlyList<NuGet.Protocol.Core.Types.SourceRepository> Repositories { get; set; }
}
public class InstallerResult
{
public InstallerResult(System.Collections.Generic.IDictionary<NuGet.Protocol.Core.Types.SourcePackageDependencyInfo, NuGet.Protocol.Core.Types.DownloadResourceResult> downloadResult) { }
Expand Down Expand Up @@ -1249,6 +1266,10 @@ namespace Orc.NuGetExplorer.Services
public interface IPackageInstallationService
{
NuGet.Packaging.VersionFolderPathResolver InstallerPathResolver { get; }
System.Threading.Tasks.Task<Orc.NuGetExplorer.InstallerResult> InstallAsync(Orc.NuGetExplorer.InstallationContext context, System.Threading.CancellationToken cancellationToken = default);
[System.Obsolete(("Use `InstallAsync(InstallationContext context, CancellationToken cancellationToke" +
"n = default)` instead. Will be treated as an error from version 6.0.0. Will be r" +
"emoved in version 7.0.0."), false)]
System.Threading.Tasks.Task<Orc.NuGetExplorer.InstallerResult> InstallAsync(NuGet.Packaging.Core.PackageIdentity package, Orc.NuGetExplorer.IExtensibleProject project, System.Collections.Generic.IReadOnlyList<NuGet.Protocol.Core.Types.SourceRepository> repositories, bool ignoreMissingPackages = false, System.Func<NuGet.Packaging.Core.PackageIdentity, bool>? packagePredicate = null, System.Threading.CancellationToken cancellationToken = default);
System.Threading.Tasks.Task<long?> MeasurePackageSizeFromRepositoryAsync(NuGet.Packaging.Core.PackageIdentity packageIdentity, NuGet.Protocol.Core.Types.SourceRepository sourceRepository);
System.Threading.Tasks.Task UninstallAsync(NuGet.Packaging.Core.PackageIdentity package, Orc.NuGetExplorer.IExtensibleProject project, System.Collections.Generic.IEnumerable<NuGet.Packaging.PackageReference> installedPackageReferences, System.Func<NuGet.Packaging.Core.PackageIdentity, bool>? packagePredicate = null, System.Threading.CancellationToken cancellationToken = default);
Expand Down
12 changes: 10 additions & 2 deletions src/Orc.NuGetExplorer/Management/NuGetProjectPackageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,16 @@ public async Task<bool> InstallPackageForProjectAsync(IExtensibleProject project

return false;
}

var installerResults = await _packageInstallationService.InstallAsync(package, project, repositories, project.IgnoreDependencies, packagePredicate, token);
var context = new InstallationContext
{
Project = project,
Repositories = repositories,
Package = package,
PackagePredicate = packagePredicate,
AllowMultipleVersions = true
};

var installerResults = await _packageInstallationService.InstallAsync(context, token);
if (!installerResults.Result.Any())
{
if (showErrors)
Expand Down
17 changes: 17 additions & 0 deletions src/Orc.NuGetExplorer/Models/InstallationContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Orc.NuGetExplorer;

using System;
using System.Collections.Generic;
using System.Threading;
using NuGet.Packaging.Core;
using NuGet.Protocol.Core.Types;

public class InstallationContext
{
public required PackageIdentity Package { get; set; }
public required IExtensibleProject Project { get; set; }
public required IReadOnlyList<SourceRepository> Repositories { get; set; }
public bool IgnoreMissingPackages { get; set; }
public Func<PackageIdentity, bool>? PackagePredicate { get; set; }
public bool AllowMultipleVersions { get; set; } = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ public interface IPackageInstallationService
/// </summary>
VersionFolderPathResolver InstallerPathResolver { get; }

Task<InstallerResult> InstallAsync(
Task<InstallerResult> InstallAsync(InstallationContext context, CancellationToken cancellationToken = default);

[ObsoleteEx(ReplacementTypeOrMember = "InstallAsync(InstallationContext context, CancellationToken cancellationToken = default)", TreatAsErrorFromVersion = "6", RemoveInVersion = "7")]
public Task<InstallerResult> InstallAsync(
PackageIdentity package,
IExtensibleProject project,
IReadOnlyList<SourceRepository> repositories,
Expand Down
59 changes: 42 additions & 17 deletions src/Orc.NuGetExplorer/Services/PackageInstallationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -90,6 +91,23 @@ public PackageInstallationService(IServiceLocator serviceLocator,

public VersionFolderPathResolver InstallerPathResolver => _installerPathResolver;

[ObsoleteEx(ReplacementTypeOrMember = "InstallAsync(InstallationContext context, CancellationToken cancellationToken = default)", TreatAsErrorFromVersion = "6", RemoveInVersion = "7")]
public Task<InstallerResult> InstallAsync(PackageIdentity package, IExtensibleProject project, IReadOnlyList<SourceRepository> repositories, bool ignoreMissingPackages = false, Func<PackageIdentity, bool>? packagePredicate = null, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(package);
ArgumentNullException.ThrowIfNull(project);
ArgumentNullException.ThrowIfNull(repositories);
var context = new InstallationContext
{
Package = package,
Project = project,
Repositories = repositories,
IgnoreMissingPackages = ignoreMissingPackages,
PackagePredicate = packagePredicate,
};
return InstallAsync(context, cancellationToken);
}

public async Task UninstallAsync(PackageIdentity package, IExtensibleProject project, IEnumerable<PackageReference> installedPackageReferences,
Func<PackageIdentity, bool>? packagePredicate = null, CancellationToken cancellationToken = default)
{
Expand Down Expand Up @@ -184,17 +202,16 @@ public async Task UninstallAsync(PackageIdentity package, IExtensibleProject pro
}

[Time]
public async Task<InstallerResult> InstallAsync(
PackageIdentity package,
IExtensibleProject project,
IReadOnlyList<SourceRepository> repositories,
bool ignoreMissingPackages = false,
Func<PackageIdentity, bool>? packagePredicate = null,
CancellationToken cancellationToken = default)
public async Task<InstallerResult> InstallAsync(InstallationContext context, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(package);
ArgumentNullException.ThrowIfNull(project);
ArgumentNullException.ThrowIfNull(repositories);
ArgumentNullException.ThrowIfNull(context);

var project = context.Project;
var package = context.Package;
var repositories = context.Repositories;
var ignoreMissingPackages = context.IgnoreMissingPackages;
var packagePredicate = context.PackagePredicate;
var allowMultipleVersions = context.AllowMultipleVersions;

try
{
Expand Down Expand Up @@ -235,7 +252,7 @@ public async Task<InstallerResult> InstallAsync(

var dependencyInfoResources = new DependencyInfoResourceCollection(dependencyResources);

resolverContext = await ResolveDependenciesAsync(package, targetFramework, PackageIdentityComparer.Default, dependencyInfoResources,
resolverContext = await ResolveDependenciesAsync(package, targetFramework, PackageIdentityComparer.Default, dependencyInfoResources,
sourceCacheContext, project, ignoreMissingPackages, packagePredicate, cancellationToken);

if (resolverContext is null ||
Expand Down Expand Up @@ -271,12 +288,20 @@ public async Task<InstallerResult> InstallAsync(
throw Log.ErrorAndCreateException<IncompatiblePackageException>($"Package {package} incompatible with project target platform {targetFramework}");
}

// Step 5. Build install list using NuGet Resolver and select available resources.
// Track packages which already installed and make sure only one version of package exists
var resolver = new Resolver.PackageResolver();
var availablePackagesToInstall = await resolver.ResolveWithVersionOverrideAsync(resolverContext, project, DependencyBehavior.Highest,
(project, conflict) => _fileSystemService.CreateDeleteme(conflict.PackageIdentity.Id, project.GetInstallPath(conflict.PackageIdentity)),
cancellationToken);
// Step 5. Build install list using NuGet Resolver and select available resources.
List<SourcePackageDependencyInfo> availablePackagesToInstall;
if (allowMultipleVersions)
{
availablePackagesToInstall = resolverContext.AvailablePackages.ToList();
}
else
{
// Track packages which already installed and make sure only one version of package exists
var resolver = new Resolver.PackageResolver();
availablePackagesToInstall = await resolver.ResolveWithVersionOverrideAsync(resolverContext, project, DependencyBehavior.Highest,
(project, conflict) => _fileSystemService.CreateDeleteme(conflict.PackageIdentity.Id, project.GetInstallPath(conflict.PackageIdentity)),
cancellationToken);
}

// Step 6. Download everything except main package and extract all
availablePackagesToInstall.Remove(mainPackageInfo);
Expand Down

0 comments on commit 04aae21

Please sign in to comment.