private bool TryUpdate(IEnumerable<IPackage> dependents, ConflictResult conflictResult, IPackage package, out IEnumerable<IPackage> incompatiblePackages) { // Key dependents by id so we can look up the old package later var dependentsLookup = dependents.ToDictionary(d => d.Id, StringComparer.OrdinalIgnoreCase); var compatiblePackages = new Dictionary<IPackage, IPackage>(); // Initialize each compatible package to null foreach (var dependent in dependents) { compatiblePackages[dependent] = null; } // Get compatible packages in one batch so we don't have to make requests for each one var packages = from p in SourceRepository.FindCompatiblePackages(ConstraintProvider, dependentsLookup.Keys, package, TargetFramework, AllowPrereleaseVersions) group p by p.Id into g let oldPackage = dependentsLookup[g.Key] select new { OldPackage = oldPackage, NewPackage = g.Where(p => p.Version > oldPackage.Version) .OrderBy(p => p.Version) .ResolveSafeVersion() }; foreach (var p in packages) { compatiblePackages[p.OldPackage] = p.NewPackage; } // Get all packages that have an incompatibility with the specified package i.e. // We couldn't find a version in the repository that works with the specified package. incompatiblePackages = compatiblePackages.Where(p => p.Value == null) .Select(p => p.Key); if (incompatiblePackages.Any()) { return false; } IPackageConstraintProvider currentConstraintProvider = ConstraintProvider; try { // Add a constraint for the incoming package so we don't try to update it by mistake. // Scenario: // A 1.0 -> B [1.0] // B 1.0.1, B 1.5, B 2.0 // A 2.0 -> B (any version) // We have A 1.0 and B 1.0 installed. When trying to update to B 1.0.1, we'll end up trying // to find a version of A that works with B 1.0.1. The version in the above case is A 2.0. // When we go to install A 2.0 we need to make sure that when we resolve it's dependencies that we stay within bounds // i.e. when we resolve B for A 2.0 we want to keep the B 1.0.1 we've already chosen instead of trying to grab // B 1.5 or B 2.0. In order to achieve this, we add a constraint for version of B 1.0.1 so we stay within those bounds for B. // Respect all existing constraints plus an additional one that we specify based on the incoming package var constraintProvider = new DefaultConstraintProvider(); constraintProvider.AddConstraint(package.Id, new VersionSpec(package.Version)); ConstraintProvider = new AggregateConstraintProvider(ConstraintProvider, constraintProvider); // Mark the incoming package as visited so that we don't try walking the graph again Marker.MarkVisited(package); var failedPackages = new List<IPackage>(); // Update each of the existing packages to more compatible one foreach (var pair in compatiblePackages) { try { // Remove the old package Uninstall(pair.Key, conflictResult.DependentsResolver, conflictResult.Repository); // Install the new package Walk(pair.Value); } catch { // If we failed to update this package (most likely because of a conflict further up the dependency chain) // we keep track of it so we can report an error about the top level package. failedPackages.Add(pair.Key); } } incompatiblePackages = failedPackages; return !incompatiblePackages.Any(); } finally { // Restore the current constraint provider ConstraintProvider = currentConstraintProvider; // Mark the package as processing again Marker.MarkProcessing(package); } }
private bool TryUpdate(IEnumerable <IPackage> dependents, ConflictResult conflictResult, IPackage package, out IEnumerable <IPackage> incompatiblePackages) { // Key dependents by id so we can look up the old package later var dependentsLookup = dependents.ToDictionary(d => d.Id, StringComparer.OrdinalIgnoreCase); var compatiblePackages = new Dictionary <IPackage, IPackage>(); // Initialize each compatible package to null foreach (var dependent in dependents) { compatiblePackages[dependent] = null; } // Get compatible packages in one batch so we don't have to make requests for each one var packages = from p in SourceRepository.FindCompatiblePackages(ConstraintProvider, dependentsLookup.Keys, package, TargetFramework, AllowPrereleaseVersions) group p by p.Id into g let oldPackage = dependentsLookup[g.Key] select new { OldPackage = oldPackage, NewPackage = g.Where(p => p.Version > oldPackage.Version) .OrderBy(p => p.Version) .ResolveSafeVersion() }; foreach (var p in packages) { compatiblePackages[p.OldPackage] = p.NewPackage; } // Get all packages that have an incompatibility with the specified package i.e. // We couldn't find a version in the repository that works with the specified package. incompatiblePackages = compatiblePackages.Where(p => p.Value == null) .Select(p => p.Key); if (incompatiblePackages.Any()) { return(false); } IPackageConstraintProvider currentConstraintProvider = ConstraintProvider; try { // Add a constraint for the incoming package so we don't try to update it by mistake. // Scenario: // A 1.0 -> B [1.0] // B 1.0.1, B 1.5, B 2.0 // A 2.0 -> B (any version) // We have A 1.0 and B 1.0 installed. When trying to update to B 1.0.1, we'll end up trying // to find a version of A that works with B 1.0.1. The version in the above case is A 2.0. // When we go to install A 2.0 we need to make sure that when we resolve it's dependencies that we stay within bounds // i.e. when we resolve B for A 2.0 we want to keep the B 1.0.1 we've already chosen instead of trying to grab // B 1.5 or B 2.0. In order to achieve this, we add a constraint for version of B 1.0.1 so we stay within those bounds for B. // Respect all existing constraints plus an additional one that we specify based on the incoming package var constraintProvider = new DefaultConstraintProvider(); constraintProvider.AddConstraint(package.Id, new VersionSpec(package.Version)); ConstraintProvider = new AggregateConstraintProvider(ConstraintProvider, constraintProvider); // Mark the incoming package as visited so that we don't try walking the graph again Marker.MarkVisited(package); var failedPackages = new List <IPackage>(); // Update each of the existing packages to more compatible one foreach (var pair in compatiblePackages) { try { // Remove the old package Uninstall(pair.Key, conflictResult.DependentsResolver, conflictResult.Repository); // Install the new package Walk(pair.Value); } catch { // If we failed to update this package (most likely because of a conflict further up the dependency chain) // we keep track of it so we can report an error about the top level package. failedPackages.Add(pair.Key); } } incompatiblePackages = failedPackages; return(!incompatiblePackages.Any()); } finally { // Restore the current constraint provider ConstraintProvider = currentConstraintProvider; // Mark the package as processing again Marker.MarkProcessing(package); } }
public void GetUpdatedPackages_OnePackageReferencedWithConstraintAndUpdatesAvailable_LatestVersionReturnedBasedOnConstraint() { CreateProject(); project.FakePackages.Add(new FakePackage("Test", "1.0")); var sourceRepository = new FakePackageRepository(); FakePackage packageVersion2 = sourceRepository.AddFakePackageWithVersion("Test", "2.0"); FakePackage [] expectedPackages = new [] { packageVersion2 }; sourceRepository.AddFakePackageWithVersion("Test", "3.0"); var versionSpec = new VersionSpec(); versionSpec.MinVersion = new SemanticVersion("1.0"); versionSpec.IsMinInclusive = true; versionSpec.MaxVersion = new SemanticVersion("2.0"); versionSpec.IsMaxInclusive = true; var constraintProvider = new DefaultConstraintProvider(); constraintProvider.AddConstraint("Test", versionSpec); project.ConstraintProvider = constraintProvider; CreateUpdatedPackages(sourceRepository); IEnumerable<IPackage> packages = updatedPackages.GetUpdatedPackages(); PackageCollectionAssert.AreEqual(expectedPackages, packages); }
public void ReadPackages_TwoPackagesInSourceRepositoryAndTwoNewerPackageVersionAvailableAndProjectHasConstraint_NewerPackageVersionThatMeetsConstraintIsDisplayed() { CreateViewModel(); var versionSpec = new VersionSpec(); versionSpec.MinVersion = new SemanticVersion("1.0"); versionSpec.IsMinInclusive = true; versionSpec.MaxVersion = new SemanticVersion("2.0"); versionSpec.IsMaxInclusive = true; var constraintProvider = new DefaultConstraintProvider(); constraintProvider.AddConstraint("Test", versionSpec); solution.FakeProjectToReturnFromGetProject.ConstraintProvider = constraintProvider; AddPackageToLocalRepository("Test", "1.0.0.0"); AddPackageToActiveRepository("Test", "1.0.0.0"); FakePackage expectedPackage = AddPackageToActiveRepository("Test", "2.0.0.0"); AddPackageToActiveRepository("Test", "3.0.0.0"); viewModel.ReadPackages(); CompleteReadPackagesTask(); var expectedPackages = new FakePackage[] { expectedPackage }; PackageCollectionAssert.AreEqual(expectedPackages, viewModel.PackageViewModels); }
public void Execute_PackageHasConstraint_LatestPackageIsNotUpdatedButPackageWithHighestVersionThatMatchesConstraint () { CreateSolution (); var constraintProvider = new DefaultConstraintProvider (); var versionSpec = new VersionSpec (); versionSpec.MinVersion = new SemanticVersion ("1.0"); versionSpec.IsMinInclusive = true; versionSpec.IsMaxInclusive = true; versionSpec.MaxVersion = new SemanticVersion ("2.0"); constraintProvider.AddConstraint ("MyPackage", versionSpec); fakeProject.ConstraintProvider = constraintProvider; fakeProject.AddFakePackageToSourceRepository ("MyPackage", "1.0"); FakePackage packageVersion2 = fakeProject.AddFakePackageToSourceRepository ("MyPackage", "2.0"); fakeProject.AddFakePackageToSourceRepository ("MyPackage", "3.0"); fakeProject.FakePackages.Add (new FakePackage ("MyPackage", "1.0")); action.PackageId = "MyPackage"; action.Execute (); Assert.AreEqual (packageVersion2, fakeProject.PackagePassedToUpdatePackage); }
private bool TryUpdate(IEnumerable <IPackage> dependents, ConflictResult conflictResult, IPackage package, out IEnumerable <IPackage> incompatiblePackages) { bool flag; Dictionary <string, IPackage> dependentsLookup = Enumerable.ToDictionary <IPackage, string>(dependents, d => d.Id, StringComparer.OrdinalIgnoreCase); Dictionary <IPackage, IPackage> dictionary = new Dictionary <IPackage, IPackage>(); foreach (IPackage package2 in dependents) { dictionary[package2] = null; } foreach (var type in from p in FindCompatiblePackages(this.DependencyResolver, this.ConstraintProvider, dependentsLookup.Keys, package, base.TargetFramework, this.AllowPrereleaseVersions) group p by p.Id into g let oldPackage = dependentsLookup[g.Key] select new { OldPackage = oldPackage, NewPackage = this.SelectDependency(from p in g where p.Version > oldPackage.Version orderby p.Version select p) }) { dictionary[type.OldPackage] = type.NewPackage; } incompatiblePackages = from p in dictionary where p.Value == null select p.Key; if (incompatiblePackages.Any <IPackage>()) { return(false); } IPackageConstraintProvider constraintProvider = this.ConstraintProvider; try { DefaultConstraintProvider provider2 = new DefaultConstraintProvider(); provider2.AddConstraint(package.Id, new VersionSpec(package.Version)); IPackageConstraintProvider[] constraintProviders = new IPackageConstraintProvider[] { this.ConstraintProvider, provider2 }; this.ConstraintProvider = new AggregateConstraintProvider(constraintProviders); base.Marker.MarkVisited(package); List <IPackage> list = new List <IPackage>(); foreach (KeyValuePair <IPackage, IPackage> pair in dictionary) { try { this.Uninstall(pair.Key, conflictResult.DependentsResolver, conflictResult.Repository); base.Walk(pair.Value); } catch { list.Add(pair.Key); } } incompatiblePackages = list; flag = !incompatiblePackages.Any <IPackage>(); } finally { this.ConstraintProvider = constraintProvider; base.Marker.MarkProcessing(package); } return(flag); }