private static IReadOnlyCollection <SourcePackageDependencyInfo> PruneAvailablePackageDependencies( PackageIdentity packageIdentity, ResolutionContext resolutionContext, IEnumerable <SourcePackageDependencyInfo> availablePackageDependencies) { var prunedAvailablePackages = PrunePackageTree.RemoveAllVersionsForIdExcept( availablePackageDependencies, packageIdentity); if (resolutionContext.IncludePrerelease) { return(prunedAvailablePackages.ToList()); } return(PrunePackageTree.PrunePreleaseForStableTargets( prunedAvailablePackages, new[] { packageIdentity }, new[] { packageIdentity }).ToList()); }
private async Task <PackagesContext> GetRequiredPackages(ISet <PackageIdentity> primaryPackages, ISet <PackageIdentity> targetPackages, bool downgradeAllowed, ResolutionContext resolutionContext, NuGetFramework primaryFramework, ILogger logger, CancellationToken token) { var libraryPackage = GetFramworkLibrary(primaryFramework); var gatherContext = new GatherContext { ResolutionContext = resolutionContext, PrimarySources = _project.PrimarySources, DependencySources = _project.DependencySources, PackagesFolderSource = _project.LocalSourceRepository, PrimaryTargets = primaryPackages .Select(x => targetPackages.Contains(x) ? x : new PackageIdentity(x.Id, version: null)) .ToList(), AllowDowngrades = downgradeAllowed, PrimaryFramework = primaryFramework, DependencyFramework = MazeFrameworks.MapToNetFramework(primaryFramework), Log = logger }; var primaryPackageIds = primaryPackages.Select(x => x.Id).ToHashSet(); var allPackages = await ResolverGather.GatherAsync(gatherContext, token); var frameworkRelevantPackages = primaryPackages.Where(x => allPackages.First(y => y.Equals(x)).Dependencies.Any()).ToHashSet(); var frameworkRelevantTargets = targetPackages.Where(x => allPackages.First(y => y.Equals(x)).Dependencies.Any()).ToHashSet(); //we remove all primary packages that have no dependencies for the current framework meaning they don't support this framework var availablePackages = allPackages.Where(x => !primaryPackageIds.Contains(x.Id) || x.Dependencies.Any()).ToList(); if (!availablePackages.Any()) //packages not available for this framework { return(new PackagesContext(ImmutableDictionary <PackageIdentity, SourcePackageDependencyInfo> .Empty)); } //available packages now contains all versions of the package and all versions of each depdendency (recursive) //we try to prune the results down to only what we would allow to be installed //1. remove incorrect library packages var prunedAvailablePackages = PrunePackageTreeExtensions.RemoveLibraryPackage(availablePackages, libraryPackage); //2. remove all versions of the package we want to install except the version we actually want to install // it is not a problem if other primary packages might need an update prunedAvailablePackages = PrunePackageTreeExtensions.RemoveAllVersionsForIdExcept(prunedAvailablePackages, frameworkRelevantTargets); //3. remove the downgrades of primary packages if (!downgradeAllowed) { prunedAvailablePackages = PrunePackageTreeExtensions.PruneDowngrades(prunedAvailablePackages, frameworkRelevantPackages); } //4. remove prereleases if (!resolutionContext.IncludePrerelease) { prunedAvailablePackages = PrunePackageTree.PrunePreleaseForStableTargets(prunedAvailablePackages, frameworkRelevantPackages, frameworkRelevantTargets); } /* ===> PackageResolverContext * TargetIds New packages to install or update. These will prefer the highest version. * RequiredPackageIds The required packages (primary) * PackagesConfig Only for logging * PreferredVersions Preferred versions of each package. If the package does not exist here it will use the dependency behavior, or if it is a target the highest version will be used. * AvailablePackages All available packages that should be sorted out * DependencyBehavior The behavior for resolving a package version * PackageSources Only for logging * Log Logger * ======================================================================== * Return The complete resulting list */ var resolverContext = new PackageResolverContext( resolutionContext.DependencyBehavior, targetIds: frameworkRelevantTargets.Select(x => x.Id), requiredPackageIds: frameworkRelevantPackages.Select(x => x.Id), packagesConfig: Enumerable.Empty <PackageReference>(), preferredVersions: frameworkRelevantPackages, availablePackages: prunedAvailablePackages, packageSources: Enumerable.Empty <PackageSource>(), log: logger); var packageResolver = new PackageResolver(); //all final packages (including dependencies) var packages = packageResolver.Resolve(resolverContext, token).ToList(); //that's an array var dependencyMap = packages.ToDictionary(x => x, x => availablePackages.First(y => y.Equals(x)), PackageIdentity.Comparer); //remove library package and it's dependencies because they are always loaded var foundLibraryPackage = packages.FirstOrDefault(libraryPackage.IsSameId); if (foundLibraryPackage != null) { if (!foundLibraryPackage.Version.Equals(libraryPackage.Version)) { throw new InvalidOperationException($"Invalid version of {libraryPackage} found: {foundLibraryPackage}"); } RemovePackage(foundLibraryPackage); //TODO remove package also from SourceDependencyInfo? void RemovePackage(PackageIdentity packageIdentity) { var sourceInfo = dependencyMap[packageIdentity]; dependencyMap.Remove(packageIdentity); foreach (var dependency in sourceInfo.Dependencies) { var package = dependencyMap.FirstOrDefault(x => x.Key.IsSameId(dependency)).Key; if (package != null) { RemovePackage(package); } } } } return(new PackagesContext(dependencyMap)); }