public void Resolver_Basic_AllUnlisted() { var a100 = new ResolverPackage("a", new NuGetVersion(1, 0, 0), new NuGet.Packaging.Core.PackageDependency[] { new NuGet.Packaging.Core.PackageDependency("b", new VersionRange(new NuGetVersion(1, 0, 0), true, new NuGetVersion(5, 0, 0), true)) }, false, false); var b200 = new ResolverPackage("b", new NuGetVersion(2, 0, 0), null, false, false); var b250 = new ResolverPackage("b", new NuGetVersion(2, 5, 0), null, false, false); var b400 = new ResolverPackage("b", new NuGetVersion(4, 0, 0), null, false, false); var b500 = new ResolverPackage("b", new NuGetVersion(5, 0, 0), null, false, false); var b600 = new ResolverPackage("b", new NuGetVersion(6, 0, 0), null, false, false); List <ResolverPackage> available = new List <ResolverPackage>(); available.Add(a100); available.Add(b200); available.Add(b250); available.Add(b400); available.Add(b500); available.Add(b600); var resolver = new PackageResolver(); var context = CreatePackageResolverContext(DependencyBehavior.Lowest, a100, available); var solution = resolver.Resolve(context, CancellationToken.None) .OrderBy(pi => pi.Id) .ToList(); Assert.Equal(new PackageIdentity("a", new NuGetVersion(1, 0, 0)), solution[0], PackageIdentityComparer.Default); Assert.Equal(new PackageIdentity("b", new NuGetVersion(2, 0, 0)), solution[1], PackageIdentityComparer.Default); }
public void Resolver_Basic() { ResolverPackage target = new ResolverPackage("a", new NuGetVersion(1, 0, 0), new NuGet.Packaging.Core.PackageDependency[] { new NuGet.Packaging.Core.PackageDependency("b", new VersionRange(new NuGetVersion(1, 0, 0), true, new NuGetVersion(3, 0, 0), true)) }, true, false); var dep1 = new ResolverPackage("b", new NuGetVersion(2, 0, 0)); var dep2 = new ResolverPackage("b", new NuGetVersion(2, 5, 0)); var dep3 = new ResolverPackage("b", new NuGetVersion(4, 0, 0)); List <ResolverPackage> possible = new List <ResolverPackage>(); possible.Add(dep1); possible.Add(dep2); possible.Add(dep3); possible.Add(target); var resolver = new PackageResolver(); var context = CreatePackageResolverContext(DependencyBehavior.Lowest, target, possible); var solution = resolver.Resolve(context, CancellationToken.None).ToList(); Assert.Equal(2, solution.Count()); }
/// <summary> /// Ex: PackageA (> 1.0.0) /// </summary> private static string FormatDependencyConstraint(ResolverPackage package, string dependencyId) { // The range may not exist, or may inclue all versions. For this reason we trim the string afterwards to remove extra spaces due to empty ranges var range = package.FindDependencyRange(dependencyId); var dependencyString = String.Format(CultureInfo.InvariantCulture, "{0} {1}", dependencyId, range == null ? string.Empty : range.ToNonSnapshotRange().PrettyPrint()).Trim(); // A 1.0.0 dependency: B (= 1.5) return($"'{package.Id} {package.Version.ToNormalizedString()} constraint: {dependencyString}'"); }
public void Resolver_NoSolution() { ResolverPackage target = new ResolverPackage("a", new NuGetVersion(1, 0, 0), new NuGet.Packaging.Core.PackageDependency[] { new NuGet.Packaging.Core.PackageDependency("b", null) }); List <ResolverPackage> possible = new List <ResolverPackage>(); possible.Add(target); var resolver = new PackageResolver(DependencyBehavior.Lowest); Assert.Throws <NuGetResolverConstraintException>(() => resolver.Resolve(new ResolverPackage[] { target }, possible, CancellationToken.None)); }
private static IEnumerable <PackageDependency> GetBrokenDependencies(ResolverPackage package, IEnumerable <ResolverPackage> packages) { foreach (var dependency in package.Dependencies) { var target = packages.FirstOrDefault(targetPackage => StringComparer.OrdinalIgnoreCase.Equals(targetPackage.Id, dependency.Id)); if (!IsDependencySatisfied(dependency, target)) { yield return(dependency); } } yield break; }
private static List <ResolverPackage> FindCircularDependency(ResolverPackage package, Dictionary <string, ResolverPackage> packageLookUp, HashSet <ResolverPackage> visitedPackages) { // avoid checking depths beyond 20 packages deep if (package != null && !package.Absent && package.Dependencies.Any()) { var queue = new Queue <QueueNode>(); // added the first initial node to queue var node = new QueueNode(package, new List <ResolverPackage>()); queue.Enqueue(node); // BFS traversal to traverse through all the packages to find out circular dependency while (queue.Count > 0) { var source = queue.Dequeue(); // access parent packages list and add current package as well var parentPackages = new List <ResolverPackage>(source.ParentPackages); parentPackages.Add(source.Package); // walk the dependencies foreach (var dependency in source.Package.Dependencies.OrderBy(d => d.Id, StringComparer.OrdinalIgnoreCase)) { var dependencyPackage = packageLookUp[dependency.Id]; // If already visited, then it means it doesn't have any circular dependency so we can avoid processing this node again if (!visitedPackages.Contains(dependencyPackage)) { if (parentPackages.Contains(dependencyPackage)) { // circular dependency detected parentPackages.Add(dependencyPackage); return(parentPackages); } // add child node to Queue to process further var newQNode = new QueueNode(dependencyPackage, parentPackages); queue.Enqueue(newQNode); } } } } // add processed packages to local cache visitedPackages.Add(package); // end of the walk return(new List <ResolverPackage>()); }
/// <summary> /// Check if two packages can exist in the same solution. /// This is used by the resolver. /// </summary> internal static bool ShouldRejectPackagePair(ResolverPackage p1, ResolverPackage p2) { var p1ToP2Dependency = p1.FindDependencyRange(p2.Id); if (p1ToP2Dependency != null) { return(p2.Absent || !p1ToP2Dependency.Satisfies(p2.Version)); } var p2ToP1Dependency = p2.FindDependencyRange(p1.Id); if (p2ToP1Dependency != null) { return(p1.Absent || !p2ToP1Dependency.Satisfies(p1.Version)); } return(false); }
public void Resolver_Basic_AllUnlisted() { var a100 = new ResolverPackage("a", new NuGetVersion(1, 0, 0), new NuGet.Packaging.Core.PackageDependency[] { new NuGet.Packaging.Core.PackageDependency("b", new VersionRange(new NuGetVersion(1, 0, 0), true, new NuGetVersion(5, 0, 0), true)) }, false, false); var b200 = new ResolverPackage("b", new NuGetVersion(2, 0, 0), null, false, false); var b250 = new ResolverPackage("b", new NuGetVersion(2, 5, 0), null, false, false); var b400 = new ResolverPackage("b", new NuGetVersion(4, 0, 0), null, false, false); var b500 = new ResolverPackage("b", new NuGetVersion(5, 0, 0), null, false, false); var b600 = new ResolverPackage("b", new NuGetVersion(6, 0, 0), null, false, false); List<ResolverPackage> available = new List<ResolverPackage>(); available.Add(a100); available.Add(b200); available.Add(b250); available.Add(b400); available.Add(b500); available.Add(b600); var resolver = new PackageResolver(); var context = CreatePackageResolverContext(DependencyBehavior.Lowest, a100, available); var solution = resolver.Resolve(context, CancellationToken.None) .OrderBy(pi => pi.Id) .ToList(); Assert.Equal(new PackageIdentity("a", new NuGetVersion(1, 0, 0)), solution[0], PackageIdentityComparer.Default); Assert.Equal(new PackageIdentity("b", new NuGetVersion(2, 0, 0)), solution[1], PackageIdentityComparer.Default); }
private static IEnumerable<ResolverPackage> FindCircularDependency(ResolverPackage package, IEnumerable<string> parents, IEnumerable<ResolverPackage> solution) { // avoid checking depths beyond 20 packages deep if (parents.Count() < 20 && package != null && !package.Absent && package.Dependencies.Any()) { // walk the dependencies foreach (var dependency in package.Dependencies.OrderBy(d => d.Id, StringComparer.OrdinalIgnoreCase)) { var dependencyPackage = solution.FirstOrDefault(solutionPackage => StringComparer.OrdinalIgnoreCase.Equals(solutionPackage.Id, dependency.Id)); if (parents.Contains(dependency.Id, StringComparer.OrdinalIgnoreCase)) { // loop detected return new ResolverPackage[] { package, dependencyPackage }; } // recurse on dependencies var result = FindCircularDependency(dependencyPackage, parents.Concat(new string[] { package.Id }), solution); if (result.Any()) { return (new ResolverPackage[] { package }).Concat(result); } } } // end of the walk return Enumerable.Empty<ResolverPackage>(); }
/// <summary> /// Check if two packages can exist in the same solution. /// This is used by the resolver. /// </summary> internal static bool ShouldRejectPackagePair(ResolverPackage p1, ResolverPackage p2) { var p1ToP2Dependency = p1.FindDependencyRange(p2.Id); if (p1ToP2Dependency != null) { return p2.Absent || !p1ToP2Dependency.Satisfies(p2.Version); } var p2ToP1Dependency = p2.FindDependencyRange(p1.Id); if (p2ToP1Dependency != null) { return p1.Absent || !p2ToP1Dependency.Satisfies(p1.Version); } return false; }
private static bool IsDependencySatisfied(PackageDependency dependency, ResolverPackage package) { return package != null && !package.Absent && (dependency.VersionRange == null || dependency.VersionRange.Satisfies(package.Version)); }
private static IEnumerable<PackageDependency> GetBrokenDependencies(ResolverPackage package, IEnumerable<ResolverPackage> packages) { foreach (var dependency in package.Dependencies) { var target = packages.FirstOrDefault(targetPackage => StringComparer.OrdinalIgnoreCase.Equals(targetPackage.Id, dependency.Id)); if (!IsDependencySatisfied(dependency, target)) { yield return dependency; } } yield break; }
/// <summary> /// Ex: PackageA (> 1.0.0) /// </summary> private static string FormatDependencyConstraint(ResolverPackage package, string dependencyId) { // The range may not exist, or may inclue all versions. For this reason we trim the string afterwards to remove extra spaces due to empty ranges var range = package.FindDependencyRange(dependencyId); var dependencyString = String.Format(CultureInfo.InvariantCulture, "{0} {1}", dependencyId, range == null ? string.Empty : range.PrettyPrint()).Trim(); // A 1.0.0 dependency: B (= 1.5) return $"'{package.Id} {package.Version.ToString()} {Strings.DependencyConstraint}: {dependencyString}'"; }
/// <summary> /// This will try and get broken dependencies for target or it's dependencies WRT installed packages as well as all available packages to install /// </summary> /// <param name="package">target package</param> /// <param name="solution">last best known solution</param> /// <param name="availablePackages">all available packages from all sources</param> /// <returns>list of broken dependencies</returns> private static IEnumerable <PackageDependency> GetBrokenDependenciesWithInstalledPackages(ResolverPackage package, IEnumerable <ResolverPackage> solution, IEnumerable <PackageDependencyInfo> availablePackages, HashSet <string> visitedPackages) { if (visitedPackages.Contains(package.Id)) { yield break; } // BFS traversal of graph var queue = new Queue <ResolverPackage>(); queue.Enqueue(package); while (queue.Count > 0) { var node = queue.Dequeue(); foreach (var dependency in node.Dependencies) { var target = solution.FirstOrDefault(targetPackage => StringComparer.OrdinalIgnoreCase.Equals(targetPackage.Id, dependency.Id)); // true, if solution doesn't contain this dependency or // if neither solution package satisfy this dependency version nor available packages had any package which could satisfy this dependency. // This is required because our solution might not have selected the right version of this dependent package. if (target == null || (!IsDependencySatisfied(dependency, target) && !availablePackages.Where(p => StringComparer.OrdinalIgnoreCase.Equals(p.Id, dependency.Id)).Any(p => IsDependencySatisfied(dependency, p)))) { yield return(dependency); } if (target != null && visitedPackages.Add(dependency.Id)) { queue.Enqueue(target); } } } yield break; }
public void Resolver_NoSolution() { ResolverPackage target = new ResolverPackage("a", new NuGetVersion(1, 0, 0), new NuGet.Packaging.Core.PackageDependency[] { new NuGet.Packaging.Core.PackageDependency("b", null) }, true, false); List<ResolverPackage> possible = new List<ResolverPackage>(); possible.Add(target); var resolver = new PackageResolver(); var context = CreatePackageResolverContext(DependencyBehavior.Lowest, target, possible); Assert.Throws<NuGetResolverConstraintException>(() => resolver.Resolve(context, CancellationToken.None)); }
public void Resolver_Basic() { ResolverPackage target = new ResolverPackage("a", new NuGetVersion(1, 0, 0), new NuGet.Packaging.Core.PackageDependency[] { new NuGet.Packaging.Core.PackageDependency("b", new VersionRange(new NuGetVersion(1, 0, 0), true, new NuGetVersion(3, 0, 0), true)) }, true, false); var dep1 = new ResolverPackage("b", new NuGetVersion(2, 0, 0)); var dep2 = new ResolverPackage("b", new NuGetVersion(2, 5, 0)); var dep3 = new ResolverPackage("b", new NuGetVersion(4, 0, 0)); List<ResolverPackage> possible = new List<ResolverPackage>(); possible.Add(dep1); possible.Add(dep2); possible.Add(dep3); possible.Add(target); var resolver = new PackageResolver(); var context = CreatePackageResolverContext(DependencyBehavior.Lowest, target, possible); var solution = resolver.Resolve(context, CancellationToken.None).ToList(); Assert.Equal(2, solution.Count()); }
public QueueNode(ResolverPackage package, List <ResolverPackage> parentPackages) { Package = package; ParentPackages = parentPackages; }
private static bool IsDependencySatisfied(PackageDependency dependency, ResolverPackage package) { return(package != null && !package.Absent && (dependency.VersionRange == null || dependency.VersionRange.Satisfies(package.Version))); }