public async Task<IEnumerable<NuGetProjectAction>> PreviewInstallPackageAsync(NuGetProject nuGetProject, PackageIdentity packageIdentity, ResolutionContext resolutionContext, INuGetProjectContext nuGetProjectContext, IEnumerable<SourceRepository> primarySources, IEnumerable<SourceRepository> secondarySources, CancellationToken token) { if(nuGetProject == null) { throw new ArgumentNullException("nuGetProject"); } if (packageIdentity == null) { throw new ArgumentNullException("packageIdentity"); } if(resolutionContext == null) { throw new ArgumentNullException("resolutionContext"); } if(nuGetProjectContext == null) { throw new ArgumentNullException("nuGetProjectContext"); } if (primarySources == null) { throw new ArgumentNullException("primarySources"); } if (secondarySources == null) { secondarySources = SourceRepositoryProvider.GetRepositories().Where(e => e.PackageSource.IsEnabled); } if(!primarySources.Any()) { throw new ArgumentException("primarySources"); } if(packageIdentity.Version == null) { throw new ArgumentNullException("packageIdentity.Version"); } // TODO: BUGBUG: HACK: Multiple primary repositories is mainly intended for nuget.exe at the moment // The following special case for ProjectK is not correct, if they used nuget.exe // and multiple repositories in the -Source switch if (nuGetProject is ProjectManagement.Projects.ProjectKNuGetProjectBase) { var action = NuGetProjectAction.CreateInstallProjectAction(packageIdentity, primarySources.First()); return new NuGetProjectAction[] { action }; } var projectInstalledPackageReferences = await nuGetProject.GetInstalledPackagesAsync(token); var oldListOfInstalledPackages = projectInstalledPackageReferences.Select(p => p.PackageIdentity); if(oldListOfInstalledPackages.Any(p => p.Equals(packageIdentity))) { string projectName; nuGetProject.TryGetMetadata<string>(NuGetProjectMetadataKeys.Name, out projectName); throw new InvalidOperationException(String.Format(NuGet.ProjectManagement.Strings.PackageAlreadyExistsInProject, packageIdentity, projectName ?? String.Empty)); } List<NuGetProjectAction> nuGetProjectActions = new List<NuGetProjectAction>(); // TODO: these sources should be ordered // TODO: search in only the active source but allow dependencies to come from other sources? var effectiveSources = GetEffectiveSources(primarySources, secondarySources); if (resolutionContext.DependencyBehavior != DependencyBehavior.Ignore) { try { bool downgradeAllowed = false; var packageTargetsForResolver = new HashSet<PackageIdentity>(oldListOfInstalledPackages, PackageIdentity.Comparer); // Note: resolver needs all the installed packages as targets too. And, metadata should be gathered for the installed packages as well var installedPackageWithSameId = packageTargetsForResolver.Where(p => p.Id.Equals(packageIdentity.Id, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if(installedPackageWithSameId != null) { packageTargetsForResolver.Remove(installedPackageWithSameId); if(installedPackageWithSameId.Version > packageIdentity.Version) { // Looks like the installed package is of higher version than one being installed. So, we take it that downgrade is allowed downgradeAllowed = true; } } packageTargetsForResolver.Add(packageIdentity); // Step-1 : Get metadata resources using gatherer var targetFramework = nuGetProject.GetMetadata<NuGetFramework>(NuGetProjectMetadataKeys.TargetFramework); nuGetProjectContext.Log(MessageLevel.Info, Strings.AttemptingToGatherDependencyInfo, packageIdentity, targetFramework); var primaryPackages = new List<PackageIdentity>() { packageIdentity }; // If any targets are prerelease we should gather with prerelease on and filter afterwards bool includePrereleaseInGather = resolutionContext.IncludePrerelease || (packageTargetsForResolver.Any(p => (p.HasVersion && p.Version.IsPrerelease))); ResolutionContext contextForGather = new ResolutionContext(resolutionContext.DependencyBehavior, includePrereleaseInGather, resolutionContext.IncludeUnlisted); var availablePackageDependencyInfoWithSourceSet = await ResolverGather.GatherPackageDependencyInfo(contextForGather, primaryPackages, packageTargetsForResolver, targetFramework, primarySources, effectiveSources, token); if (!availablePackageDependencyInfoWithSourceSet.Any()) { throw new InvalidOperationException(String.Format(Strings.UnableToGatherDependencyInfo, packageIdentity)); } // Prune the results down to only what we would allow to be installed // Keep only the target package we are trying to install for that Id IEnumerable<SourceDependencyInfo> prunedAvailablePackages = PrunePackageTree.RemoveAllVersionsForIdExcept(availablePackageDependencyInfoWithSourceSet, packageIdentity); if (!resolutionContext.IncludePrerelease) { prunedAvailablePackages = PrunePackageTree.PrunePreleaseForStableTargets(prunedAvailablePackages, packageTargetsForResolver); } // Remove versions that do not satisfy 'allowedVersions' attribute in packages.config, if any prunedAvailablePackages = PrunePackageTree.PruneDisallowedVersions(prunedAvailablePackages, projectInstalledPackageReferences); // TODO: prune down level packages? // Step-2 : Call IPackageResolver.Resolve to get new list of installed packages // TODO: Consider using IPackageResolver once it is extensible var packageResolver = new PackageResolver(resolutionContext.DependencyBehavior); nuGetProjectContext.Log(MessageLevel.Info, Strings.AttemptingToResolveDependencies, packageIdentity, resolutionContext.DependencyBehavior); // Note: resolver prefers installed package versions if the satisfy the dependency version constraints // So, since we want an exact version of a package, create a new list of installed packages where the packageIdentity being installed // is present after removing the one with the same id var preferredPackageReferences = new List<PackageReference>(projectInstalledPackageReferences.Where(pr => !pr.PackageIdentity.Id.Equals(packageIdentity.Id, StringComparison.OrdinalIgnoreCase))); preferredPackageReferences.Add(new PackageReference(packageIdentity, targetFramework)); IEnumerable<PackageIdentity> newListOfInstalledPackages = packageResolver.Resolve(packageTargetsForResolver, prunedAvailablePackages, preferredPackageReferences, token); if (newListOfInstalledPackages == null) { throw new InvalidOperationException(String.Format(Strings.UnableToResolveDependencyInfo, packageIdentity, resolutionContext.DependencyBehavior)); } // Step-3 : Get the list of nuGetProjectActions to perform, install/uninstall on the nugetproject // based on newPackages obtained in Step-2 and project.GetInstalledPackages nuGetProjectContext.Log(MessageLevel.Info, Strings.ResolvingActionsToInstallPackage, packageIdentity); var newPackagesToUninstall = new List<PackageIdentity>(); foreach(var oldInstalledPackage in oldListOfInstalledPackages) { var newPackageWithSameId = newListOfInstalledPackages .Where(np => oldInstalledPackage.Id.Equals(np.Id, StringComparison.OrdinalIgnoreCase) && !oldInstalledPackage.Version.Equals(np.Version)).FirstOrDefault(); if(newPackageWithSameId != null) { if(!downgradeAllowed && oldInstalledPackage.Version > newPackageWithSameId.Version) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Strings.NewerVersionAlreadyReferenced, newPackageWithSameId.Id)); } newPackagesToUninstall.Add(oldInstalledPackage); } } var newPackagesToInstall = newListOfInstalledPackages.Where(p => !oldListOfInstalledPackages.Contains(p)); foreach (PackageIdentity newPackageToUninstall in newPackagesToUninstall) { nuGetProjectActions.Add(NuGetProjectAction.CreateUninstallProjectAction(newPackageToUninstall)); } var comparer = PackageIdentity.Comparer; foreach (PackageIdentity newPackageToInstall in newPackagesToInstall) { // find the package match based on identity SourceDependencyInfo sourceDepInfo = prunedAvailablePackages.Where(p => comparer.Equals(p, newPackageToInstall)).SingleOrDefault(); if (sourceDepInfo == null) { // this really should never happen throw new InvalidOperationException(String.Format(Strings.PackageNotFound, packageIdentity)); } nuGetProjectActions.Add(NuGetProjectAction.CreateInstallProjectAction(newPackageToInstall, sourceDepInfo.Source)); } } catch (InvalidOperationException) { throw; } catch (AggregateException aggregateEx) { throw new InvalidOperationException(aggregateEx.Message, aggregateEx); } catch (Exception ex) { if (String.IsNullOrEmpty(ex.Message)) { throw new InvalidOperationException(String.Format(Strings.PackageCouldNotBeInstalled, packageIdentity), ex); } else { throw new InvalidOperationException(ex.Message, ex); } } } else { var sourceRepository = await GetSourceRepository(packageIdentity, effectiveSources); nuGetProjectActions.Add(NuGetProjectAction.CreateInstallProjectAction(packageIdentity, sourceRepository)); } nuGetProjectContext.Log(MessageLevel.Info, Strings.ResolvedActionsToInstallPackage, packageIdentity); return nuGetProjectActions; }
public async Task<IEnumerable<NuGetProjectAction>> PreviewReinstallPackagesAsync(IEnumerable<PackageIdentity> packagesToInstall, NuGetProject nuGetProject, ResolutionContext resolutionContext, INuGetProjectContext nuGetProjectContext, SourceRepository primarySourceRepository, IEnumerable<SourceRepository> secondarySources, CancellationToken token) { if(packagesToInstall == null) { throw new ArgumentNullException("packagesToInstall"); } if (nuGetProject == null) { throw new ArgumentNullException("nuGetProject"); } if (resolutionContext == null) { throw new ArgumentNullException("resolutionContext"); } if (nuGetProjectContext == null) { throw new ArgumentNullException("nuGetProjectContext"); } if(packagesToInstall.Any(p => p.Version == null)) { throw new ArgumentException("packagesToInstall"); } if (primarySourceRepository == null) { throw new ArgumentNullException("primarySourceRepository"); } var primarySources = new List<SourceRepository>() { primarySourceRepository }; if (secondarySources == null) { secondarySources = SourceRepositoryProvider.GetRepositories().Where(e => e.PackageSource.IsEnabled); } var projectInstalledPackageReferences = await nuGetProject.GetInstalledPackagesAsync(token); var oldListOfInstalledPackages = projectInstalledPackageReferences.Select(p => p.PackageIdentity); // Note: resolver needs all the installed packages as targets too. And, metadata should be gathered for the installed packages as well var packageTargetsForResolver = new HashSet<PackageIdentity>(oldListOfInstalledPackages, PackageIdentity.Comparer); foreach(var packageToInstall in packagesToInstall) { packageTargetsForResolver.Add(packageToInstall); } List<NuGetProjectAction> nuGetProjectActions = new List<NuGetProjectAction>(); // TODO: these sources should be ordered // TODO: search in only the active source but allow dependencies to come from other sources? var effectiveSources = GetEffectiveSources(primarySources, secondarySources); try { // If any targets are prerelease we should gather with prerelease on and filter afterwards bool includePrereleaseInGather = resolutionContext.IncludePrerelease || (packageTargetsForResolver.Any(p => (p.HasVersion && p.Version.IsPrerelease))); ResolutionContext contextForGather = new ResolutionContext(resolutionContext.DependencyBehavior, includePrereleaseInGather, resolutionContext.IncludeUnlisted); // Step-1 : Get metadata resources using gatherer var targetFramework = nuGetProject.GetMetadata<NuGetFramework>(NuGetProjectMetadataKeys.TargetFramework); nuGetProjectContext.Log(MessageLevel.Info, Strings.AttemptingToGatherDependencyInfoForMultiplePackages, targetFramework); var availablePackageDependencyInfoWithSourceSet = await ResolverGather.GatherPackageDependencyInfo(contextForGather, packagesToInstall, packageTargetsForResolver, targetFramework, primarySources, effectiveSources, token); if (!availablePackageDependencyInfoWithSourceSet.Any()) { throw new InvalidOperationException(Strings.UnableToGatherDependencyInfoForMultiplePackages); } // Prune the results down to only what we would allow to be installed IEnumerable<SourceDependencyInfo> prunedAvailablePackages = availablePackageDependencyInfoWithSourceSet; // Keep only the target package we are trying to install for that Id foreach (var packageIdentity in packagesToInstall) { prunedAvailablePackages = PrunePackageTree.RemoveAllVersionsForIdExcept(prunedAvailablePackages, packageIdentity); } if (!resolutionContext.IncludePrerelease) { prunedAvailablePackages = PrunePackageTree.PrunePreleaseForStableTargets(prunedAvailablePackages, packageTargetsForResolver); } // TODO: prune down level packages? // Remove versions that do not satisfy 'allowedVersions' attribute in packages.config, if any prunedAvailablePackages = PrunePackageTree.PruneDisallowedVersions(prunedAvailablePackages, projectInstalledPackageReferences); // Step-2 : Call IPackageResolver.Resolve to get new list of installed packages // TODO: Consider using IPackageResolver once it is extensible var packageResolver = new PackageResolver(resolutionContext.DependencyBehavior); nuGetProjectContext.Log(MessageLevel.Info, Strings.AttemptingToResolveDependenciesForMultiplePackages); IEnumerable<PackageIdentity> newListOfInstalledPackages = packageResolver.Resolve(packageTargetsForResolver, prunedAvailablePackages, projectInstalledPackageReferences, token); if (newListOfInstalledPackages == null) { throw new InvalidOperationException(Strings.UnableToResolveDependencyInfoForMultiplePackages); } var packagesInDependencyOrder = (await GetInstalledPackagesInDependencyOrder(nuGetProject, nuGetProjectContext, token)).Reverse(); foreach(var package in packagesInDependencyOrder) { nuGetProjectActions.Add(NuGetProjectAction.CreateUninstallProjectAction(package)); } var comparer = PackageIdentity.Comparer; foreach (PackageIdentity newPackageToInstall in newListOfInstalledPackages) { // find the package match based on identity SourceDependencyInfo sourceDepInfo = availablePackageDependencyInfoWithSourceSet.Where(p => comparer.Equals(p, newPackageToInstall)).SingleOrDefault(); if (sourceDepInfo == null) { // this really should never happen throw new InvalidOperationException(String.Format(Strings.PackageNotFound, newPackageToInstall)); } nuGetProjectActions.Add(NuGetProjectAction.CreateInstallProjectAction(newPackageToInstall, sourceDepInfo.Source)); } } catch(InvalidOperationException) { throw; } catch (AggregateException aggregateEx) { throw new InvalidOperationException(aggregateEx.Message, aggregateEx); } catch (Exception ex) { if(String.IsNullOrEmpty(ex.Message)) { throw new InvalidOperationException(Strings.PackagesCouldNotBeInstalled, ex); } else { throw new InvalidOperationException(ex.Message, ex); } } return nuGetProjectActions; }
public async Task<IEnumerable<PackageIdentity>> GetInstalledPackagesInDependencyOrder(NuGetProject nuGetProject, INuGetProjectContext nuGetProjectContext, CancellationToken token) { var targetFramework = nuGetProject.GetMetadata<NuGetFramework>(NuGetProjectMetadataKeys.TargetFramework); var installedPackages = await nuGetProject.GetInstalledPackagesAsync(token); var installedPackageIdentities = installedPackages.Select(pr => pr.PackageIdentity); var dependencyInfoFromPackagesFolder = await GetDependencyInfoFromPackagesFolder(installedPackageIdentities, targetFramework, includePrerelease: true); var packageResolver = new PackageResolver(DependencyBehavior.Lowest); return packageResolver.Resolve(installedPackageIdentities, dependencyInfoFromPackagesFolder, installedPackages, token); }
static void Main(string[] args) { // Import Dependencies var p = new Program(); // hold onto the container, otherwise the lazy objects will be disposed! var container = p.Initialize(); // Json.NET is already installed List<PackageReference> installed = new List<PackageReference>(); installed.Add(new PackageReference(new PackageIdentity("Newtonsoft.Json", NuGetVersion.Parse("6.0.5")), NuGetFramework.Parse("portable-net40+win8"))); // build the repo provider instead of importing it so that it has only v3 var repositoryProvider = new SourceRepositoryProvider(new V3OnlyPackageSourceProvider(), p.ResourceProviders.ToArray()); // package to install var target = new PackageIdentity("WindowsAzure.Storage", NuGetVersion.Parse("4.0.1")); // project target framework var framework = NuGetFramework.Parse("net451"); // build repos var repos = repositoryProvider.GetRepositories(); Stopwatch timer = new Stopwatch(); // get a distinct set of packages from all repos HashSet<PackageDependencyInfo> packages = new HashSet<PackageDependencyInfo>(PackageDependencyInfo.Comparer); // find all needed packages from online foreach (var repo in repos) { // get the resolver data resource var depInfo = repo.GetResource<DepedencyInfoResource>(); // resources can always be null if (depInfo != null) { timer.Restart(); var task = depInfo.ResolvePackages(new PackageIdentity[] { target }, framework, true); task.Wait(); foreach (var pkg in task.Result) { packages.Add(pkg); } timer.Stop(); Console.WriteLine("Online fetch time: " + timer.Elapsed); } } timer.Restart(); // find the best set to install PackageResolver resolver = new PackageResolver(DependencyBehavior.Lowest); var toInstall = resolver.Resolve(new PackageIdentity[] { target }, packages, installed, CancellationToken.None); timer.Stop(); Console.WriteLine("Resolve time: " + timer.Elapsed); Console.WriteLine("------------------------"); foreach (var pkg in toInstall) { Console.WriteLine(pkg.Id + " " + pkg.Version.ToNormalizedString()); } }