示例#1
0
        public void ResolverUtility_CircularDependencyCheckIndirectWithOthers()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("z", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("y", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("y", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("c", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("c", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("d", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("d", "2.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("z", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreateAbsentPackage("a"));
            solution.Add(CreatePackage("x", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("z", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("t", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("a", VersionRange.Parse("[1.0.0]"))));

            // Act
            var result = ResolverUtility.FindCircularDependency(solution);

            // Assert
            var message = String.Join(" => ", result);

            Assert.Equal("c 1.0.0 => d 2.0.0 => z 1.0.0 => y 1.0.0 => c 1.0.0", message);
        }
示例#2
0
        public void ResolverUtility_GetLowestDistanceFromTarget()
        {
            // Arrange
            var targets = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            targets.Add("A");

            var packages = new List <ResolverPackage>()
            {
                CreatePackage("A", "1.0.0", "B", "1.0.0"),
                CreatePackage("B", "1.0.0", "C", "1.0.0"),
                CreatePackage("C", "1.0.0", "D", "1.0.0"),
                CreatePackage("D", "1.0.0"),
            };

            // Act
            var distanceA = ResolverUtility.GetLowestDistanceFromTarget("A", targets, packages);
            var distanceB = ResolverUtility.GetLowestDistanceFromTarget("B", targets, packages);
            var distanceC = ResolverUtility.GetLowestDistanceFromTarget("C", targets, packages);
            var distanceD = ResolverUtility.GetLowestDistanceFromTarget("D", targets, packages);
            var distanceE = ResolverUtility.GetLowestDistanceFromTarget("E", targets, packages);

            // Assert
            Assert.Equal(0, distanceA);
            Assert.Equal(1, distanceB);
            Assert.Equal(2, distanceC);
            Assert.Equal(3, distanceD);
            Assert.Equal(20, distanceE); // max, not found
        }
示例#3
0
        private async Task ExecuteInitPs1ForPackagesConfig(
            NuGetPackageManager packageManager,
            Dictionary <NuGetFramework, HashSet <PackageIdentity> > packagesConfigInstalled,
            HashSet <PackageIdentity> finishedPackages)
        {
            // Get the path to the Packages folder.
            var packagesFolderPath  = packageManager.PackagesFolderSourceRepository.PackageSource.Source;
            var packagePathResolver = new PackagePathResolver(packagesFolderPath);

            var packagesToSort   = new HashSet <ResolverPackage>();
            var resolvedPackages = new HashSet <PackageIdentity>();

            var dependencyInfoResource = await packageManager
                                         .PackagesFolderSourceRepository
                                         .GetResourceAsync <DependencyInfoResource>();

            // Order by the highest framework first to make this deterministic
            // Process each framework/id/version once to avoid duplicate work
            // Packages may have different dependendcy orders depending on the framework, but there is
            // no way to fully solve this across an entire solution so we make a best effort here.
            foreach (var framework in packagesConfigInstalled.Keys.OrderByDescending(fw => fw, new NuGetFrameworkSorter()))
            {
                foreach (var package in packagesConfigInstalled[framework])
                {
                    if (resolvedPackages.Add(package))
                    {
                        var dependencyInfo = await dependencyInfoResource.ResolvePackage(
                            package,
                            framework,
                            NullLogger.Instance,
                            CancellationToken.None);

                        // This will be null for unrestored packages
                        if (dependencyInfo != null)
                        {
                            packagesToSort.Add(new ResolverPackage(dependencyInfo, listed: true, absent: false));
                        }
                    }
                }
            }

            // Order packages by dependency order
            var sortedPackages = ResolverUtility.TopologicalSort(packagesToSort);

            foreach (var package in sortedPackages)
            {
                if (finishedPackages.Add(package))
                {
                    // Find the package path in the packages folder.
                    var installPath = packagePathResolver.GetInstalledPath(package);

                    if (string.IsNullOrEmpty(installPath))
                    {
                        continue;
                    }

                    await ExecuteInitPs1Async(installPath, package);
                }
            }
        }
        public void ResolverUtility_GetDiagnosticMessageForIncompatibleDependencyWithAllowedVersion()
        {
            // Install a 1.0.0 - which requires d 1.0.0 but d 2.0.0 is already installed.

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0-1111", "b", "[1.0.0]"));
            solution.Add(CreatePackage("b", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("c", VersionRange.Parse("[1.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("d", VersionRange.Parse("[1.0.0-1234]")),
                                       new NuGet.Packaging.Core.PackageDependency("e", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("c", "2.0.0"));
            solution.Add(CreatePackage("d", "2.0.0"));
            solution.Add(CreatePackage("e", "1.0.0"));
            solution.Add(CreatePackage("f", "1.0.0", "d", "[2.0.0]"));

            var installed = new List <PackageReference>();

            installed.Add(CreateInstalledPackage("d", "2.0.0"));

            var available = solution.ToList();

            available.Add(CreatePackage("c", "1.0.0"));

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, installed, new string[] { "a" }, Enumerable.Empty <PackageSource>());

            // Assert
            Assert.Equal("Unable to resolve dependencies. 'd 2.0.0' is not compatible with 'a 1.0.0 constraint: d (= 1.0.0)'.", message);
        }
        public void ResolverUtility_GetDiagnosticMessageForMissingTargetDependency()
        {
            // Install b 1.1.0 - which requires d 1.0.0 which is missing from any source.

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("b", "1.1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("c", VersionRange.Parse("[2.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("d", VersionRange.Parse("[1.0.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("e", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("c", "3.0.0"));
            solution.Add(CreatePackage("e", "1.0.0"));

            var installed = new List <PackageReference>();

            installed.Add(CreateInstalledPackage("c", "1.0.0"));

            var available = solution.ToList();

            available.Add(CreatePackage("c", "1.0.0"));
            available.Add(CreatePackage("c", "2.0.0"));

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, installed, new string[] { "b" }, Enumerable.Empty <PackageSource>());

            // Assert
            Assert.Equal("Unable to find a version of 'd' that is compatible with 'b 1.1.0 constraint: d (= 1.0.0)'.", message);
        }
        public void ResolverUtility_NoCircularDependencyCheck()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("b", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("b", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("c", VersionRange.Parse("[1.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("g", VersionRange.Parse("[1.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("j", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("c", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("d", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("d", "1.0.0", null));
            solution.Add(CreatePackage("g", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("h", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("h", "1.0.0", null));
            solution.Add(CreatePackage("j", "1.0.0", null));

            // Act
            var result = ResolverUtility.FindFirstCircularDependency(solution);

            // Assert
            Assert.False(result.Any());
        }
        public void ResolverUtility_MultipleCircularDependencyCheck()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("x", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("a", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("a", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("b", VersionRange.Parse("[1.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("e", VersionRange.Parse("[1.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("f", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("b", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("c", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("c", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("d", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("d", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("a", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("e", "1.0.0", null));

            solution.Add(CreatePackage("f", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("g", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("g", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("h", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("h", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("i", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("i", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("f", VersionRange.Parse("[1.0.0]"))));

            // Act
            var result = ResolverUtility.FindFirstCircularDependency(solution);

            // Assert
            Assert.Equal("x 1.0.0 => a 1.0.0 => b 1.0.0 => c 1.0.0 => d 1.0.0 => a 1.0.0", String.Join(" => ", result));
        }
        public void ResolverUtility_TopologicalSort()
        {
            // Arrange
            var packages = new List <ResolverPackage>()
            {
                CreatePackage("A", "1.0.0", "B", "1.0.0"),
                CreatePackage("B", "1.0.0", "C", "1.0.0"),
                CreatePackage("C", "1.0.0", "D", "1.0.0"),
                CreatePackage("D", "1.0.0"),
                CreatePackage("E1", "1.0.0"),
                CreatePackage("E3", "1.0.0"),
                CreatePackage("E2", "1.0.0")
            };

            // Act
            var sorted = ResolverUtility.TopologicalSort(packages).ToList();

            // Assert
            Assert.Equal(7, sorted.Count);
            Assert.Equal("D", sorted[0].Id);
            Assert.Equal("C", sorted[1].Id);
            Assert.Equal("B", sorted[2].Id);
            Assert.Equal("A", sorted[3].Id);
            Assert.Equal("E1", sorted[4].Id);
            Assert.Equal("E2", sorted[5].Id);
            Assert.Equal("E3", sorted[6].Id);
        }
示例#9
0
        public void ResolverUtility_GetDiagnosticMessageForIncompatibleTargetWithAllowedVersion()
        {
            // Install b 2.0.0 - a requires b 1.0.0

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0", "b", "[1.0.0]"));
            solution.Add(CreatePackage("b", "2.0.0"));

            var installed = new List <PackageReference>();

            installed.Add(new PackageReference(new PackageIdentity("b",
                                                                   NuGetVersion.Parse("2.0.0")),
                                               NuGetFramework.Parse("net45"),
                                               true, false, false, VersionRange.Parse("[2.0.0]")));

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, installed, new string[] { "b" });

            // Assert
            Assert.Equal("Unable to find a version of 'b' that is compatible with 'a 1.0.0 constraint: b (= 1.0.0)'. 'b' has an additional constraint (= 2.0.0) defined in packages.config.", message);
        }
示例#10
0
        public void ResolverUtility_GetDiagnosticMessageForIncompatibleTargetInstalledNoAllowedVersion()
        {
            // Install b 2.0.0 - a requires b 1.0.0

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0", "b", "[1.0.0]"));
            solution.Add(CreatePackage("b", "2.0.0"));

            var installed = new List <PackageReference>();

            installed.Add(new PackageReference(new PackageIdentity("b",
                                                                   NuGetVersion.Parse("2.0.0")),
                                               NuGetFramework.Parse("net45"),
                                               true, false, false, null));

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, installed, new string[] { "b" });

            // Assert
            Assert.Equal("Unable to resolve dependencies. 'b 2.0.0' is not compatible with 'a 1.0.0 constraint: b (= 1.0.0)'.", message);
        }
示例#11
0
        public async Task FindLibraryEntryAsync_LogsOnlyPackages(LibraryDependencyTarget libraryDependencyTarget)
        {
            // Arrange
            const string packageX = "x", version = "1.0.0-beta.1", source = "source";
            var          range          = new LibraryRange(packageX, VersionRange.Parse(version), libraryDependencyTarget);
            var          cacheContext   = new SourceCacheContext();
            var          testLogger     = new TestLogger();
            var          framework      = NuGetFramework.Parse("net45");
            var          token          = CancellationToken.None;
            var          edge           = new GraphEdge <RemoteResolveResult>(null, null, null);
            var          actualIdentity = new LibraryIdentity(packageX, NuGetVersion.Parse(version), LibraryType.Package);
            var          dependencies   = new[] { new LibraryDependency()
                                                  {
                                                      LibraryRange = new LibraryRange("y", VersionRange.All, LibraryDependencyTarget.Package)
                                                  } };
            var dependencyInfo = LibraryDependencyInfo.Create(actualIdentity, framework, dependencies);

            //package source mapping configuration
            Dictionary <string, IReadOnlyList <string> > patterns = new();

            patterns.Add(source, new List <string>()
            {
                packageX
            });
            PackageSourceMapping sourceMappingConfiguration = new(patterns);
            var context = new RemoteWalkContext(cacheContext, sourceMappingConfiguration, testLogger);

            var remoteProvider = new Mock <IRemoteDependencyProvider>();

            remoteProvider.Setup(e => e.FindLibraryAsync(range, It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(actualIdentity);
            remoteProvider.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider.SetupGet(e => e.Source).Returns(new PackageSource(source));
            remoteProvider.Setup(e => e.GetDependenciesAsync(It.IsAny <LibraryIdentity>(), It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo);
            context.RemoteLibraryProviders.Add(remoteProvider.Object);

            // Act
            var result = await ResolverUtility.FindLibraryEntryAsync(range, framework, null, context, token);

            // Assert
            Assert.Equal(0, testLogger.Errors);
            testLogger.DebugMessages.TryPeek(out string message);
            if (libraryDependencyTarget == LibraryDependencyTarget.Package)
            {
                Assert.Equal($"Package source mapping matches found for package ID '{packageX}' are: '{source}'.", message);
                Assert.Equal(version, result.Key.Version.ToString());
                Assert.Equal(source, result.Data.Match.Provider.Source.Name);
            }
            else
            {
                Assert.Equal(message, null);
            }
        }
示例#12
0
        public async Task FindPackage_VerifyFloatingPackageIsRequiredOnlyFromASingleSource()
        {
            // Arrange
            var range          = new LibraryRange("x", VersionRange.Parse("1.0.0-*"), LibraryDependencyTarget.Package);
            var cacheContext   = new SourceCacheContext();
            var testLogger     = new TestLogger();
            var framework      = NuGetFramework.Parse("net45");
            var context        = new RemoteWalkContext(cacheContext, testLogger);
            var token          = CancellationToken.None;
            var edge           = new GraphEdge <RemoteResolveResult>(null, null, null);
            var actualIdentity = new LibraryIdentity("x", NuGetVersion.Parse("1.0.0-beta.1"), LibraryType.Package);
            var higherIdentity = new LibraryIdentity("x", NuGetVersion.Parse("1.0.0-beta.2"), LibraryType.Package);
            var dependencies   = new[] { new LibraryDependency()
                                         {
                                             LibraryRange = new LibraryRange("y", VersionRange.All, LibraryDependencyTarget.Package)
                                         } };
            var dependencyInfo  = LibraryDependencyInfo.Create(actualIdentity, framework, dependencies);
            var dependencyInfo2 = LibraryDependencyInfo.Create(higherIdentity, framework, dependencies);

            var downloadCount = 0;

            // Source1 returns 1.0.0-beta.1
            var remoteProvider = new Mock <IRemoteDependencyProvider>();

            remoteProvider.Setup(e => e.FindLibraryAsync(range, It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(actualIdentity);
            remoteProvider.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider.SetupGet(e => e.Source).Returns(new PackageSource("test"));
            remoteProvider.Setup(e => e.GetDependenciesAsync(It.IsAny <LibraryIdentity>(), It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo)
            .Callback(() => ++ downloadCount);
            context.RemoteLibraryProviders.Add(remoteProvider.Object);

            // Source2 returns 1.0.0-beta.2
            var remoteProvider2 = new Mock <IRemoteDependencyProvider>();

            remoteProvider2.Setup(e => e.FindLibraryAsync(range, It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(higherIdentity);
            remoteProvider2.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider2.SetupGet(e => e.Source).Returns(new PackageSource("test"));
            remoteProvider2.Setup(e => e.GetDependenciesAsync(It.IsAny <LibraryIdentity>(), It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo2)
            .Callback(() => ++ downloadCount);
            context.RemoteLibraryProviders.Add(remoteProvider2.Object);

            // Act
            var result = await ResolverUtility.FindLibraryEntryAsync(range, framework, null, edge, context, token);

            // Assert
            // Verify only one download happened
            Assert.Equal(1, downloadCount);
            Assert.Equal("1.0.0-beta.2", result.Key.Version.ToString());
        }
示例#13
0
        public void ResolverUtility_GetDiagnosticMessageNoPackages()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, Enumerable.Empty <PackageReference>(), new string[] { });

            // Assert
            Assert.Equal("Unable to resolve dependencies.", message);
        }
示例#14
0
        private static IEnumerable <PackageDependency> GetBrokenDependencies(SourcePackageDependencyInfo package, IEnumerable <PackageIdentity> packages)
        {
            foreach (var dependency in package.Dependencies)
            {
                var target = packages.FirstOrDefault(targetPackage => StringComparer.OrdinalIgnoreCase.Equals(targetPackage.Id, dependency.Id));

                if (!ResolverUtility.IsDependencySatisfied(dependency, target))
                {
                    yield return(dependency);
                }
            }

            yield break;
        }
示例#15
0
        public void ResolverUtility_CircularDependencyCheckBasic()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("b", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("b", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("a", VersionRange.Parse("[1.0.0]"))));

            // Act
            var result = ResolverUtility.FindCircularDependency(solution);

            // Assert
            Assert.Equal("a 1.0.0 => b 1.0.0 => a 1.0.0", String.Join(" => ", result));
        }
        public void ResolverUtility_GetDiagnosticMessageAllAbsentPackages()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreateAbsentPackage("a"));
            solution.Add(CreateAbsentPackage("b"));
            solution.Add(CreateAbsentPackage("c"));

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, Enumerable.Empty <PackageReference>(), new string[] { "a" }, Enumerable.Empty <PackageSource>());

            // Assert
            Assert.Equal("Unable to resolve dependencies.", message);
        }
示例#17
0
        public void ResolverUtility_GetDiagnosticMessageForTargetMissingDependency()
        {
            // Install a, b cannot be found

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0", "b", "[1.0.0, )"));

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, Enumerable.Empty <PackageReference>(), new string[] { "a" });

            // Assert
            Assert.Equal("Unable to resolve dependency 'b'.", message);
        }
示例#18
0
        public void ResolverUtility_CircularDependencyCheckAbsentPackages()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("z", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("a", VersionRange.Parse("[1.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("b", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreateAbsentPackage("a"));
            solution.Add(CreateAbsentPackage("b"));
            solution.Add(CreateAbsentPackage("y"));

            // Act
            var result = ResolverUtility.FindCircularDependency(solution);

            // Assert
            Assert.False(result.Any());
        }
示例#19
0
        public void ResolverUtility_GetDiagnosticMessageForTargetAbsentDependency()
        {
            // Install a, b cannot be found

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0", "b", "[1.0.0, )"));
            solution.Add(CreateAbsentPackage("b"));

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, Enumerable.Empty <PackageReference>(), new string[] { "a" });

            // Assert
            Assert.Equal("Unable to find a version of 'b' that is compatible with 'a 1.0.0 constraint: b (\u2265 1.0.0)'.", message);
        }
示例#20
0
        public void ResolverUtility_GetDiagnosticMessageForTargetIncompatibleDependency()
        {
            // Install a, b 1.0.0 cannot be found

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0", "b", "[1.0.0]"));
            solution.Add(CreatePackage("b", "2.0.0"));

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, Enumerable.Empty <PackageReference>(), new string[] { "a" });

            // Assert
            Assert.Equal("Unable to resolve dependencies. 'b 2.0.0' is not compatible with 'a 1.0.0 constraint: b (= 1.0.0)'.", message);
        }
示例#21
0
        public async Task FindPackage_VerifyMissingListedPackageSucceedsOnRetry()
        {
            // Arrange
            var range          = new LibraryRange("x", VersionRange.Parse("1.0.0-beta"), LibraryDependencyTarget.Package);
            var cacheContext   = new SourceCacheContext();
            var testLogger     = new TestLogger();
            var framework      = NuGetFramework.Parse("net45");
            var context        = new RemoteWalkContext(cacheContext, testLogger);
            var token          = CancellationToken.None;
            var edge           = new GraphEdge <RemoteResolveResult>(null, null, null);
            var actualIdentity = new LibraryIdentity("x", NuGetVersion.Parse("1.0.0-beta"), LibraryType.Package);
            var dependencies   = new[] { new LibraryDependency()
                                         {
                                             LibraryRange = new LibraryRange("y", VersionRange.All, LibraryDependencyTarget.Package)
                                         } };
            var dependencyInfo = LibraryDependencyInfo.Create(actualIdentity, framework, dependencies);

            var remoteProvider = new Mock <IRemoteDependencyProvider>();

            remoteProvider.Setup(e => e.FindLibraryAsync(range, framework, It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(actualIdentity);
            remoteProvider.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider.SetupGet(e => e.Source).Returns(new PackageSource("test"));

            var hitCount = 0;

            remoteProvider.Setup(e => e.GetDependenciesAsync(actualIdentity, framework, cacheContext, testLogger, token))
            .ThrowsAsync(new PackageNotFoundProtocolException(new PackageIdentity(actualIdentity.Name, actualIdentity.Version)))
            .Callback(() => ++ hitCount);

            remoteProvider.Setup(e => e.GetDependenciesAsync(actualIdentity, framework, It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo)
            .Callback(() => ++ hitCount);

            context.RemoteLibraryProviders.Add(remoteProvider.Object);

            // Act
            var result = await ResolverUtility.FindLibraryEntryAsync(range, framework, null, edge, context, token);

            // Assert
            Assert.Equal(1, hitCount);
            Assert.Equal("x", result.Key.Name);
        }
示例#22
0
        public void ResolverUtility_GetDiagnosticMessageForIncompatibleTarget()
        {
            // Install b 2.0.0 - a requires b 1.0.0

            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0", "b", "[1.0.0]"));
            solution.Add(CreatePackage("b", "2.0.0"));

            var installed = new List <PackageReference>();

            installed.Add(CreateInstalledPackage("a", "1.0.0"));

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, installed, new string[] { "b" });

            // Assert
            Assert.Equal("Unable to resolve dependencies. 'b 2.0.0' is not compatible with 'a 1.0.0 constraint: b (= 1.0.0)'.", message);
        }
示例#23
0
        public async Task FindPackage_VerifyMissingVersionPackageReturnsUnresolved()
        {
            // Arrange
            var range        = new LibraryRange("x", VersionRange.Parse("1.0.0-beta"), LibraryDependencyTarget.Package);
            var cacheContext = new SourceCacheContext();
            var testLogger   = new TestLogger();
            var framework    = NuGetFramework.Parse("net45");
            var context      = new RemoteWalkContext(cacheContext, testLogger);
            var edge         = new GraphEdge <RemoteResolveResult>(null, null, null);

            var remoteProvider = new Mock <IRemoteDependencyProvider>();

            context.RemoteLibraryProviders.Add(remoteProvider.Object);

            // Act
            var result = await ResolverUtility.FindLibraryEntryAsync(range, framework, null, edge, context, CancellationToken.None);

            // Assert
            Assert.Equal(LibraryType.Unresolved, result.Data.Match.Library.Type);
            Assert.Equal("x", result.Data.Match.Library.Name);
            Assert.Equal("1.0.0-beta", result.Data.Match.Library.Version.ToString());
        }
示例#24
0
        public void ResolverUtility_GetDiagnosticMessageVerifyDiamondDependencySortsById()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0",
                                       new NuGet.Packaging.Core.PackageDependency("b", VersionRange.Parse("[2.0.0]")),
                                       new NuGet.Packaging.Core.PackageDependency("c", VersionRange.Parse("[1.0.0]"))));
            solution.Add(CreatePackage("c", "1.0.0", "d", "[1.0.0]"));
            solution.Add(CreateAbsentPackage("d"));
            solution.Add(CreatePackage("b", "2.0.0", "d", "[1.0.0]"));

            var installed = new List <PackageReference>();

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, installed, new string[] { "a" });

            // Assert
            Assert.Equal("Unable to find a version of 'd' that is compatible with 'b 2.0.0 constraint: d (= 1.0.0)', 'c 1.0.0 constraint: d (= 1.0.0)'.", message);
        }
示例#25
0
        public void ResolverUtility_GetDiagnosticMessageVerifyDependencyDistanceIsUsed()
        {
            // Arrange
            var solution = new List <ResolverPackage>();

            solution.Add(CreatePackage("a", "1.0.0", "y", "[1.0.0]"));
            solution.Add(CreatePackage("y", "1.0.0", "z", "[1.0.0]"));
            solution.Add(CreateAbsentPackage("z"));
            solution.Add(CreatePackage("a", "1.0.0", "b", "[1.0.0]"));
            solution.Add(CreatePackage("b", "1.0.0", "c", "[1.0.0]"));
            solution.Add(CreateAbsentPackage("c"));

            var installed = new List <PackageReference>();

            var available = solution.ToList();

            // Act
            var message = ResolverUtility.GetDiagnosticMessage(solution, available, installed, new string[] { "a" });

            // Assert
            Assert.Equal("Unable to find a version of 'z' that is compatible with 'y 1.0.0 constraint: z (= 1.0.0)'.", message);
        }
示例#26
0
        public async Task FindPackage_VerifyFindLibraryEntryReturnsOriginalCase()
        {
            // Arrange
            var range          = new LibraryRange("x", VersionRange.Parse("1.0.0-beta"), LibraryDependencyTarget.Package);
            var cacheContext   = new SourceCacheContext();
            var testLogger     = new TestLogger();
            var framework      = NuGetFramework.Parse("net45");
            var context        = new RemoteWalkContext(cacheContext, testLogger);
            var token          = CancellationToken.None;
            var edge           = new GraphEdge <RemoteResolveResult>(null, null, null);
            var actualIdentity = new LibraryIdentity("X", NuGetVersion.Parse("1.0.0-bEta"), LibraryType.Package);
            var dependencies   = new[] { new LibraryDependency()
                                         {
                                             LibraryRange = new LibraryRange("y", VersionRange.All, LibraryDependencyTarget.Package)
                                         } };
            var dependencyInfo = LibraryDependencyInfo.Create(actualIdentity, framework, dependencies);

            var remoteProvider = new Mock <IRemoteDependencyProvider>();

            remoteProvider.Setup(e => e.FindLibraryAsync(range, framework, cacheContext, testLogger, token))
            .ReturnsAsync(actualIdentity);

            remoteProvider.Setup(e => e.GetDependenciesAsync(actualIdentity, framework, cacheContext, testLogger, token))
            .ReturnsAsync(dependencyInfo);

            context.RemoteLibraryProviders.Add(remoteProvider.Object);

            // Act
            var result = await ResolverUtility.FindLibraryEntryAsync(range, framework, null, edge, context, token);

            // Assert
            Assert.Equal(LibraryType.Package, result.Data.Match.Library.Type);
            Assert.Equal("X", result.Data.Match.Library.Name);
            Assert.Equal("1.0.0-bEta", result.Data.Match.Library.Version.ToString());
            Assert.Equal("y", result.Data.Dependencies.Single().Name);
        }
示例#27
0
        public async Task FindPackage_WhenNoPackageSourceMappingIsEnabledForAPackage_Fails()
        {
            // Arrange
            const string packageX = "x", version = "1.0.0-beta.1";
            var          range        = new LibraryRange(packageX, VersionRange.Parse(version), LibraryDependencyTarget.Package);
            var          cacheContext = new SourceCacheContext();
            var          testLogger   = new TestLogger();
            var          framework    = NuGetFramework.Parse("net45");

            var token          = CancellationToken.None;
            var edge           = new GraphEdge <RemoteResolveResult>(null, null, null);
            var actualIdentity = new LibraryIdentity(packageX, NuGetVersion.Parse(version), LibraryType.Package);
            var dependencies   = new[] { new LibraryDependency()
                                         {
                                             LibraryRange = new LibraryRange("y", VersionRange.All, LibraryDependencyTarget.Package)
                                         } };
            var dependencyInfo = LibraryDependencyInfo.Create(actualIdentity, framework, dependencies);

            var downloadCount = 0;

            //package source mapping configuration
            Dictionary <string, IReadOnlyList <string> > patterns = new();

            patterns.Add("source2", new List <string>()
            {
                "z"
            });
            patterns.Add("source1", new List <string>()
            {
                "y"
            });
            PackageSourceMapping sourceMappingConfiguration = new(patterns);
            var context = new RemoteWalkContext(cacheContext, sourceMappingConfiguration, testLogger);

            // Source1 returns 1.0.0-beta.1
            var remoteProvider = new Mock <IRemoteDependencyProvider>();

            remoteProvider.Setup(e => e.FindLibraryAsync(range, It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(actualIdentity);
            remoteProvider.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider.SetupGet(e => e.Source).Returns(new PackageSource("source1"));
            remoteProvider.Setup(e => e.GetDependenciesAsync(It.IsAny <LibraryIdentity>(), It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo)
            .Callback(() => ++ downloadCount);
            context.RemoteLibraryProviders.Add(remoteProvider.Object);

            // Source2 returns 1.0.0-beta.1
            var remoteProvider2 = new Mock <IRemoteDependencyProvider>();

            remoteProvider2.Setup(e => e.FindLibraryAsync(range, It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(actualIdentity);
            remoteProvider2.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider2.SetupGet(e => e.Source).Returns(new PackageSource("source2"));
            remoteProvider2.Setup(e => e.GetDependenciesAsync(It.IsAny <LibraryIdentity>(), It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo)
            .Callback(() => ++ downloadCount);
            context.RemoteLibraryProviders.Add(remoteProvider2.Object);

            // Act
            var result = await ResolverUtility.FindLibraryEntryAsync(range, framework, null, context, token);

            Assert.Equal(0, downloadCount);
            Assert.Equal(0, testLogger.Errors);
            Assert.Equal(1, testLogger.DebugMessages.Count);
            testLogger.DebugMessages.TryPeek(out string message);
            Assert.Equal($"Package source mapping match not found for package ID '{packageX}'.", message);
        }
示例#28
0
        public async Task FindPackage_VerifyPackageSourcesAreFilteredWhenPackageSourceMappingIsEnabled_Success()
        {
            // Arrange
            const string packageX = "x", packageY = "y", version = "1.0.0-beta.1", source1 = "source1", source2 = "source2";
            var          range          = new LibraryRange(packageX, VersionRange.Parse(version), LibraryDependencyTarget.Package);
            var          cacheContext   = new SourceCacheContext();
            var          testLogger     = new TestLogger();
            var          framework      = NuGetFramework.Parse("net45");
            var          token          = CancellationToken.None;
            var          edge           = new GraphEdge <RemoteResolveResult>(null, null, null);
            var          actualIdentity = new LibraryIdentity(packageX, NuGetVersion.Parse(version), LibraryType.Package);
            var          dependencies   = new[] { new LibraryDependency()
                                                  {
                                                      LibraryRange = new LibraryRange(packageY, VersionRange.All, LibraryDependencyTarget.Package)
                                                  } };
            var dependencyInfo = LibraryDependencyInfo.Create(actualIdentity, framework, dependencies);

            var downloadCount = 0;

            //package source mapping configuration
            Dictionary <string, IReadOnlyList <string> > patterns = new();

            patterns.Add(source2, new List <string>()
            {
                packageX
            });
            patterns.Add(source1, new List <string>()
            {
                packageY
            });
            PackageSourceMapping sourceMappingConfiguration = new(patterns);
            var context = new RemoteWalkContext(cacheContext, sourceMappingConfiguration, testLogger);

            // Source1 returns 1.0.0-beta.1
            var remoteProvider = new Mock <IRemoteDependencyProvider>();

            remoteProvider.Setup(e => e.FindLibraryAsync(range, It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(actualIdentity);
            remoteProvider.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider.SetupGet(e => e.Source).Returns(new PackageSource(source1));
            remoteProvider.Setup(e => e.GetDependenciesAsync(It.IsAny <LibraryIdentity>(), It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo)
            .Callback(() => ++ downloadCount);
            context.RemoteLibraryProviders.Add(remoteProvider.Object);

            // Source2 returns 1.0.0-beta.1
            var remoteProvider2 = new Mock <IRemoteDependencyProvider>();

            remoteProvider2.Setup(e => e.FindLibraryAsync(range, It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(actualIdentity);
            remoteProvider2.SetupGet(e => e.IsHttp).Returns(true);
            remoteProvider2.SetupGet(e => e.Source).Returns(new PackageSource(source2));
            remoteProvider2.Setup(e => e.GetDependenciesAsync(It.IsAny <LibraryIdentity>(), It.IsAny <NuGetFramework>(), It.IsAny <SourceCacheContext>(), testLogger, token))
            .ReturnsAsync(dependencyInfo)
            .Callback(() => ++ downloadCount);
            context.RemoteLibraryProviders.Add(remoteProvider2.Object);

            // Act
            var result = await ResolverUtility.FindLibraryEntryAsync(range, framework, null, context, token);

            // Assert
            // Verify only one download happened from the expected source i.e. source2
            Assert.Equal(1, downloadCount);
            Assert.Equal(1, testLogger.DebugMessages.Count);
            testLogger.DebugMessages.TryPeek(out string message);
            Assert.Equal($"Package source mapping matches found for package ID '{packageX}' are: '{source2}'.", message);
            Assert.Equal(version, result.Key.Version.ToString());
            Assert.Equal(source2, result.Data.Match.Provider.Source.Name);
        }
        private async Task <DownloadDependencyResolutionResult> ResolveDownloadDependencies(RemoteWalkContext context, ConcurrentDictionary <LibraryRange, Task <Tuple <LibraryRange, RemoteMatch> > > downloadDependenciesCache, TargetFrameworkInformation targetFrameworkInformation, CancellationToken token)
        {
            var packageDownloadTasks = targetFrameworkInformation.DownloadDependencies.Select(downloadDependency => ResolverUtility.FindPackageLibraryMatchCachedAsync(
                                                                                                  downloadDependenciesCache, downloadDependency, context.RemoteLibraryProviders, context.LocalLibraryProviders, context.CacheContext, _logger, token));

            var packageDownloadMatches = await Task.WhenAll(packageDownloadTasks);

            return(DownloadDependencyResolutionResult.Create(targetFrameworkInformation.FrameworkName, packageDownloadMatches, context.RemoteLibraryProviders));
        }
示例#30
0
        /// <summary>
        /// Resolve a package closure
        /// </summary>
        public IEnumerable <SourcePackageDependencyInfo> Resolve(PackageResolverContext context, CancellationToken token)
        {
            var stopWatch = new Stopwatch();

            token.ThrowIfCancellationRequested();

            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // validation
            foreach (var requiredId in context.RequiredPackageIds)
            {
                if (!context.AvailablePackages.Any(p => StringComparer.OrdinalIgnoreCase.Equals(p.Id, requiredId)))
                {
                    throw new NuGetResolverInputException(string.Format(CultureInfo.CurrentCulture, "Unable to find package '{0}'. Existing packages must be restored before performing an install or update.", requiredId));
                }
            }

            var invalidExistingPackages = new List <string>();

            var installedPackages = context.PackagesConfig.Select(p => p.PackageIdentity).ToArray();

            // validate existing package.config for any invalid dependency
            foreach (var package in installedPackages)
            {
                var existingPackage =
                    context.AvailablePackages.FirstOrDefault(
                        p =>
                        StringComparer.OrdinalIgnoreCase.Equals(p.Id, package.Id) &&
                        p.Version.Equals(package.Version));

                if (existingPackage is not null)
                {
                    // check if each dependency can be satisfied with existing packages
                    var brokenDependencies = GetBrokenDependencies(existingPackage, installedPackages);

                    if (brokenDependencies is not null && brokenDependencies.Any())
                    {
                        invalidExistingPackages.AddRange(brokenDependencies.Select(dependency => FormatDependencyConstraint(existingPackage, dependency)));
                    }
                }
                else
                {
                    // check same package is being updated and we've a higher version then
                    // ignore logging warning for that.
                    existingPackage =
                        context.AvailablePackages.FirstOrDefault(
                            p =>
                            StringComparer.OrdinalIgnoreCase.Equals(p.Id, package.Id) &&
                            VersionComparer.Default.Compare(p.Version, package.Version) > 0);

                    if (existingPackage is null)
                    {
                        var packageString = $"'{package.Id} {package.Version.ToNormalizedString()}'";
                        invalidExistingPackages.Add(packageString);
                    }
                }
            }
            // log warning message for all the invalid package dependencies
            if (invalidExistingPackages.Count > 0)
            {
                context.Log.LogWarning(
                    string.Format(
                        CultureInfo.CurrentCulture, "One or more unresolved package dependency constraints detected in the existing packages.config file. All dependency constraints must be resolved to add or update packages. If these packages are being updated this message may be ignored, if not the following error(s) may be blocking the current package operation: {0}",
                        string.Join(", ", invalidExistingPackages)));
            }

            // convert the available packages into ResolverPackages
            var resolverPackages = new List <ResolverPackage>();

            // pre-process the available packages to remove any packages that can't possibly form part of a solution
            var availablePackages = RemoveImpossiblePackages(context.AvailablePackages, context.RequiredPackageIds);

            foreach (var package in availablePackages)
            {
                IEnumerable <PackageDependency> dependencies = null;

                // clear out the dependencies if the behavior is set to ignore
                if (context.DependencyBehavior == DependencyBehavior.Ignore)
                {
                    dependencies = Enumerable.Empty <PackageDependency>();
                }
                else
                {
                    dependencies = package.Dependencies ?? Enumerable.Empty <PackageDependency>();
                }

                resolverPackages.Add(new ResolverPackage(package.Id, package.Version, dependencies, package.Listed, false));
            }

            // Sort the packages to make this process as deterministic as possible
            resolverPackages.Sort(PackageIdentityComparer.Default);

            // Keep track of the ids we have added
            var groupsAdded = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
            var grouped     = new List <List <ResolverPackage> >();

            // group the packages by id
            foreach (var group in resolverPackages.GroupBy(e => e.Id, StringComparer.OrdinalIgnoreCase))
            {
                groupsAdded.Add(group.Key);

                var curSet = group.ToList();

                // add an absent package for non-targets
                // being absent allows the resolver to throw it out if it is not needed
                if (!context.RequiredPackageIds.Contains(group.Key, StringComparer.OrdinalIgnoreCase))
                {
                    curSet.Add(new ResolverPackage(id: group.Key, version: null, dependencies: null, listed: true, absent: true));
                }

                grouped.Add(curSet);
            }

            // find all needed dependencies, excluding manually ignored dependencies
            var dependencyIds = resolverPackages.Where(e => e.Dependencies is not null)
                                .SelectMany(e => e.Dependencies.Select(d => d.Id)).Distinct(StringComparer.OrdinalIgnoreCase);

            //var ignoredDependencyIds = dependencyIds.

            foreach (string depId in dependencyIds)
            {
                // packages which are unavailable need to be added as absent packages
                // ex: if A -> B  and B is not found anywhere in the source repositories we add B as absent
                if (!groupsAdded.Contains(depId))
                {
                    groupsAdded.Add(depId);
                    grouped.Add(new List <ResolverPackage>()
                    {
                        new ResolverPackage(id: depId, version: null, dependencies: null, listed: true, absent: true)
                    });
                }
            }

            token.ThrowIfCancellationRequested();

            // keep track of the best partial solution
            var bestSolution = Enumerable.Empty <ResolverPackage>();

            Action <IEnumerable <ResolverPackage> > diagnosticOutput = (partialSolution) =>
            {
                // store each solution as they pass through.
                // the combination solver verifies that the last one returned is the best
                bestSolution = partialSolution;
            };

            // Run solver
            var comparer = new ResolverComparer(context.DependencyBehavior, context.PreferredVersions, context.TargetIds);

            var sortedGroups = ResolverInputSort.TreeFlatten(grouped, context);

            var solution = CombinationSolver <ResolverPackage> .FindSolution(
                groupedItems : sortedGroups,
                itemSorter : comparer,
                shouldRejectPairFunc : ShouldRejectPackagePair,
                diagnosticOutput : diagnosticOutput);

            // check if a solution was found
            if (solution is not null)
            {
                var nonAbsentCandidates = solution.Where(c => !c.Absent);

                if (nonAbsentCandidates.Any())
                {
                    // topologically sort non absent packages
                    var sortedSolution = ResolverUtility.TopologicalSort(nonAbsentCandidates);

                    // Find circular dependency for topologically sorted non absent packages since it will help maintain cache of
                    // already processed packages
                    var circularReferences = ResolverUtility.FindFirstCircularDependency(sortedSolution);

                    if (circularReferences.Any())
                    {
                        // the resolver is able to handle circular dependencies, however we should throw here to keep these from happening
                        throw new NuGetResolverConstraintException(
                                  string.Format(CultureInfo.CurrentCulture, "Circular dependency detected '{0}'.",
                                                string.Join(" => ", circularReferences.Select(package => $"{package.Id} {package.Version.ToNormalizedString()}"))));
                    }

                    // solution found!
                    stopWatch.Stop();
                    context.Log.LogMinimal(
                        string.Format("Resolving dependency information took {0}", DatetimeUtility.ToReadableTimeFormat(stopWatch.Elapsed)));
                    return(sortedSolution.Where(x => !context.IgnoredIds.Contains(x.Id)).ToArray());
                }
            }

            // no solution was found, throw an error with a diagnostic message
            var message = ResolverUtility.GetDiagnosticMessage(bestSolution, context.AvailablePackages, context.PackagesConfig, context.TargetIds, context.PackageSources);

            throw new NuGetResolverConstraintException(message);
        }