Exemple #1
0
        private async Task <RestoreTargetGraph> GenerateRestoreGraph(ILogger log, string projectName, string projectPath)
        {
            var dgFile = await VSProjectHelper.GenerateRestoreGraphFile(log, projectPath);

            var dgProvider = new DependencyGraphSpecRequestProvider(new RestoreCommandProvidersCache(), dgFile);

            using (var cacheContext = new SourceCacheContext())
            {
                var restoreContext = new RestoreArgs();
                restoreContext.CacheContext = cacheContext;
                restoreContext.Log          = new NuGet.Common.NullLogger();
                restoreContext.PreLoadedRequestProviders.Add(dgProvider);

                var request = (await dgProvider.CreateRequests(restoreContext)).Single();

                var restoreRequest    = request.Request;
                var collectorLogger   = new RestoreCollectorLogger(restoreRequest.Log, false);
                var contextForProject = CreateRemoteWalkContext(restoreRequest, collectorLogger);

                // Get external project references
                // If the top level project already exists, update the package spec provided
                // with the RestoreRequest spec.
                var updatedExternalProjects = GetProjectReferences(restoreRequest, contextForProject);

                // Load repositories
                // the external project provider is specific to the current restore project
                contextForProject.ProjectLibraryProviders.Add(new PackageSpecReferenceDependencyProvider(updatedExternalProjects, restoreRequest.Log));


                var walker = new RemoteDependencyWalker(contextForProject);

                var requestProject = request.Request.Project;

                var projectRange = new LibraryRange()
                {
                    Name           = projectName,
                    VersionRange   = new NuGet.Versioning.VersionRange(requestProject.Version),
                    TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject
                };

                var framework = requestProject.TargetFrameworks.First();
                var graphs    = new List <GraphNode <RemoteResolveResult> >
                {
                    await walker.WalkAsync(
                        projectRange,
                        framework.FrameworkName,
                        null,
                        RuntimeGraph.Empty,
                        recursive : true)
                };
                return(RestoreTargetGraph.Create(graphs, contextForProject, restoreRequest.Log, framework.FrameworkName));
            }
        }
Exemple #2
0
        public void IsGreaterThanEqualTo_ReturnsFalse_IfRightVersionIsLargerThanLeft(string leftVersionString, string rightVersionString)
        {
            // Arrange
            var leftVersion  = VersionRange.Parse(leftVersionString);
            var rightVersion = VersionRange.Parse(rightVersionString);

            // Act
            var isGreater = RemoteDependencyWalker.IsGreaterThanOrEqualTo(leftVersion, rightVersion);

            // Assert
            Assert.False(isGreater);
        }
Exemple #3
0
        public void IsGreaterThanEqualTo_ReturnsFalse_IfRightVersionIsUnbound()
        {
            // Arrange
            var leftVersion  = VersionRange.Parse("3.1.0-*");
            var rightVersion = VersionRange.All;

            // Act
            var isGreater = RemoteDependencyWalker.IsGreaterThanOrEqualTo(leftVersion, rightVersion);

            // Assert
            Assert.False(isGreater);
        }
Exemple #4
0
 private Task <RestoreTargetGraph> WalkDependenciesAsync(LibraryRange projectRange,
                                                         NuGetFramework framework,
                                                         RemoteDependencyWalker walker,
                                                         RemoteWalkContext context,
                                                         CancellationToken token)
 {
     return(WalkDependenciesAsync(projectRange,
                                  framework,
                                  runtimeIdentifier: null,
                                  runtimeGraph: RuntimeGraph.Empty,
                                  walker: walker,
                                  context: context,
                                  token: token));
 }
        public async Task DoubleDowngrade()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "0.7")
            .DependsOn("C", "1.0");

            provider.Package("B", "0.7");

            provider.Package("C", "1.0")
            .DependsOn("B", "0.8")
            .DependsOn("D", "1.0");

            provider.Package("B", "0.8");

            provider.Package("D", "1.0")
            .DependsOn("B", "1.0");

            provider.Package("B", "1.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var downgrades = new List <Tuple <GraphNode <RemoteResolveResult>, GraphNode <RemoteResolveResult> > >();
            var cycles     = new List <GraphNode <RemoteResolveResult> >();

            var result = node.Analyze();

            Assert.Equal(2, result.Downgrades.Count);


            var d0   = result.Downgrades[0];
            var d0To = d0.DowngradedFrom;
            var d0By = d0.DowngradedTo;

            AssertPath(d0To, "A 1.0", "C 1.0", "B 0.8");
            AssertPath(d0By, "A 1.0", "B 0.7");

            var d1   = result.Downgrades[1];
            var d1To = d1.DowngradedFrom;
            var d1By = d1.DowngradedTo;

            AssertPath(d1To, "A 1.0", "C 1.0", "D 1.0", "B 1.0");
            AssertPath(d1By, "A 1.0", "B 0.7");
        }
        public async Task ConflictAtDifferentLevel()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0")
            .DependsOn("C", "2.0")
            .DependsOn("F", "2.0");

            provider.Package("B", "2.0")
            .DependsOn("D", "2.0");

            provider.Package("C", "2.0")
            .DependsOn("D", "1.0");

            provider.Package("D", "1.0")
            .DependsOn("E", "[1.0]");

            provider.Package("D", "2.0")
            .DependsOn("E", "[2.0]");

            provider.Package("F", "2.0")
            .DependsOn("E", "[1.0]");

            provider.Package("E", "1.0");
            provider.Package("E", "2.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(1, result.VersionConflicts.Count);

            var conflict = result.VersionConflicts[0];
            var c1       = conflict.Selected;
            var c2       = conflict.Conflicting;

            AssertPath(c1, "A 1.0", "B 2.0", "D 2.0", "E 2.0");
            AssertPath(c2, "A 1.0", "F 2.0", "E 1.0");
        }
Exemple #7
0
        public async Task <GraphNode <RemoteResolveResult> > ResolvePackages(List <PackageId> packages)
        {
            var walkerContext = new RemoteWalkContext(_cache, _nuGetLogger);

            foreach (var sourceRepository in _repositoryProvider.Repositories)
            {
                var provider = new SourceRepositoryDependencyProvider(sourceRepository, _nuGetLogger, _cache, true, true);
                walkerContext.RemoteLibraryProviders.Add(provider);
            }

            walkerContext.ProjectLibraryProviders.Add(new ProjectLibraryProvider(packages));
            var localProvider = new SourceRepositoryDependencyProvider(_localRepository, _nuGetLogger, _cache, true, true);

            walkerContext.LocalLibraryProviders.Add(localProvider);

            var fakeLib = new LibraryRange("Dropcraft", VersionRange.Parse("1.0.0"), LibraryDependencyTarget.Project);
            var walker  = new RemoteDependencyWalker(walkerContext);

            return(await walker.WalkAsync(fakeLib, _framework, _framework.GetShortFolderName(), RuntimeGraph.Empty, true));
        }
        public async Task WalkAsync_CentralTransitiveDependencyList_DoesNotHaveDuplicates()
        {
            var framework = NuGetFramework.Parse("net45");
            var context   = new TestRemoteWalkContext();
            var provider  = new DependencyProvider();

            // A -> centralPackage1
            //   -> centralPackage2 -> centralPackage1
            provider.Package("A", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true);
            provider.Package("A", "1.0.0")
            .DependsOn("centralPackage2", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true);
            provider.Package("centralPackage2", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0");

            // A -> projectB -> projectC -> centralPackage1
            provider.Package("A", "1.0.0")
            .DependsOn("B", "1.0.0");

            provider.Package("B", "1.0.0")
            .DependsOn("C", "1.0.0");

            provider.Package("C", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true);

            // B ~> centralPackage1
            provider.Package("B", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true, libraryDependencyReferenceType: LibraryDependencyReferenceType.None);

            provider.Package("centralPackage1", "1.0.0");
            provider.Package("centralPackage2", "1.0.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);

            // Act
            var rootNode = await DoWalkAsync(walker, "A", framework);

            // Assert
            Assert.Equal(3, rootNode.InnerNodes.Count);
        }
Exemple #9
0
        public async Task SlowerFeedWinsIfBetterMatchExists()
        {
            // A
            var slowProvider = new TestProvider(TimeSpan.FromSeconds(2));

            slowProvider.AddLibrary(new LibraryIdentity
            {
                Name    = "A",
                Version = new NuGetVersion("1.0.0")
            });

            var fastProvider = new TestProvider(TimeSpan.Zero);

            fastProvider.AddLibrary(new LibraryIdentity
            {
                Name    = "A",
                Version = new NuGetVersion("1.1.0")
            });

            var context = new TestRemoteWalkContext();

            context.RemoteLibraryProviders.Add(slowProvider);
            context.RemoteLibraryProviders.Add(fastProvider);

            var walker = new RemoteDependencyWalker(context);
            var result = await walker.WalkAsync(new LibraryRange
            {
                Name         = "A",
                VersionRange = VersionRange.Parse("1.0.0"),
            },
                                                NuGetFramework.Parse("net45"),
                                                runtimeIdentifier : null,
                                                runtimeGraph : null,
                                                recursive : true);

            Assert.NotNull(result.Item.Data.Match);
            Assert.NotNull(result.Item.Data.Match.Library);
            Assert.Equal("A", result.Item.Data.Match.Library.Name);
            Assert.Equal(new NuGetVersion("1.0.0"), result.Item.Data.Match.Library.Version);
            Assert.Equal(slowProvider, result.Item.Data.Match.Provider);
        }
Exemple #10
0
        public async Task FasterProviderReturnsResultsBeforeSlowOnesIfExactMatchFound()
        {
            // A
            var slowProvider = new TestProvider(TimeSpan.FromSeconds(2));

            slowProvider.AddLibrary(new LibraryIdentity
            {
                Name    = "A",
                Version = new NuGetVersion("1.0.0")
            });

            var fastProvider = new TestProvider(TimeSpan.Zero);

            fastProvider.AddLibrary(new LibraryIdentity
            {
                Name    = "A",
                Version = new NuGetVersion("1.0.0")
            });

            var context = new RemoteWalkContext();

            context.RemoteLibraryProviders.Add(slowProvider);
            context.RemoteLibraryProviders.Add(fastProvider);

            var walker = new RemoteDependencyWalker(context);
            var result = await walker.WalkAsync(new LibraryRange
            {
                Name         = "A",
                VersionRange = VersionRange.Parse("1.0.0"),
            },
                                                NuGetFramework.Parse("net45"),
                                                runtimeIdentifier : null,
                                                runtimeGraph : null);

            Assert.NotNull(result.Item.Data.Match);
            Assert.NotNull(result.Item.Data.Match.Library);
            Assert.Equal("A", result.Item.Data.Match.Library.Name);
            Assert.Equal(new NuGetVersion("1.0.0"), result.Item.Data.Match.Library.Version);
            Assert.Equal(fastProvider, result.Item.Data.Match.Provider);
        }
Exemple #11
0
        private async Task <RestoreTargetGraph> WalkDependenciesAsync(LibraryRange projectRange,
                                                                      NuGetFramework framework,
                                                                      string runtimeIdentifier,
                                                                      RuntimeGraph runtimeGraph,
                                                                      RemoteDependencyWalker walker,
                                                                      RemoteWalkContext context,
                                                                      CancellationToken token)
        {
            var name   = FrameworkRuntimePair.GetName(framework, runtimeIdentifier);
            var graphs = new List <GraphNode <RemoteResolveResult> >();

            graphs.Add(await walker.WalkAsync(
                           projectRange,
                           framework,
                           runtimeIdentifier,
                           runtimeGraph,
                           recursive: true));

            // Resolve conflicts
            _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_ResolvingConflicts, name));

            // Flatten and create the RestoreTargetGraph to hold the packages
            var result = RestoreTargetGraph.Create(runtimeGraph, graphs, context, _logger, framework, runtimeIdentifier);

            // Check if the dependencies got bumped up
            if (_request.ExistingLockFile == null)
            {
                // No lock file, so check dependencies
                CheckDependencies(result, _request.Project.Dependencies);

                var fxInfo = _request.Project.GetTargetFramework(framework);
                if (fxInfo != null)
                {
                    CheckDependencies(result, fxInfo.Dependencies);
                }
            }

            return(result);
        }
        public async Task TryResolveConflicts_WorksWhenVersionRangeIsNotSpecified()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("Root", "1.0")
            .DependsOn("A", "1.0")
            .DependsOn("B", "2.0");

            provider.Package("A", "1.0")
            .DependsOn("C");

            provider.Package("B", "2.0")
            .DependsOn("C", "1.8");

            provider.Package("C", "1.8");
            provider.Package("C", "2.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "Root");

            // Restore doesn't actually support null versions so fake a resolved dependency
            var cNode = node.Path("A", "C");

            cNode.Key.TypeConstraint = LibraryDependencyTarget.Package;
            cNode.Item = new GraphItem <RemoteResolveResult>(new LibraryIdentity
            {
                Name    = "C",
                Version = new NuGetVersion("2.0")
            });

            var result = node.Analyze();

            Assert.Empty(result.VersionConflicts);

            Assert.Equal(Disposition.Accepted, cNode.Disposition);
            Assert.Equal(Disposition.Rejected, node.Path("B", "C").Disposition);
        }
        public async Task DowngradeSkippedIfEqual()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0")
            .DependsOn("C", "2.0");

            provider.Package("B", "2.0")
            .DependsOn("C", "2.0");

            provider.Package("C", "2.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(0, result.Downgrades.Count);
        }
        public async Task CyclesAreDetectedIf2VersionsOfTheSamePackageId()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0");

            provider.Package("B", "2.0")
            .DependsOn("A", "5.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(1, result.Cycles.Count);

            var cycle = result.Cycles[0];

            AssertPath(cycle, "A 1.0", "B 2.0", "A 5.0");
        }
Exemple #15
0
        public async Task SlowerFeedWinsIfBetterMatchExists()
        {
            // A 
            var slowProvider = new TestProvider(TimeSpan.FromSeconds(2));
            slowProvider.AddLibrary(new LibraryIdentity
            {
                Name = "A",
                Version = new NuGetVersion("1.0.0")
            });

            var fastProvider = new TestProvider(TimeSpan.Zero);
            fastProvider.AddLibrary(new LibraryIdentity
            {
                Name = "A",
                Version = new NuGetVersion("1.1.0")
            });

            var context = new RemoteWalkContext();
            context.RemoteLibraryProviders.Add(slowProvider);
            context.RemoteLibraryProviders.Add(fastProvider);

            var walker = new RemoteDependencyWalker(context);
            var result = await walker.WalkAsync(new LibraryRange
            {
                Name = "A",
                VersionRange = VersionRange.Parse("1.0.0"),
            },
            NuGetFramework.Parse("net45"),
            runtimeIdentifier: null,
            runtimeGraph: null);

            Assert.NotNull(result.Item.Data.Match);
            Assert.NotNull(result.Item.Data.Match.Library);
            Assert.Equal("A", result.Item.Data.Match.Library.Name);
            Assert.Equal(new NuGetVersion("1.0.0"), result.Item.Data.Match.Library.Version);
            Assert.Equal(slowProvider, result.Item.Data.Match.Provider);
        }
        public async Task <Tuple <bool, List <RestoreTargetGraph>, RuntimeGraph> > TryRestoreAsync(LibraryRange projectRange,
                                                                                                   IEnumerable <FrameworkRuntimePair> frameworkRuntimePairs,
                                                                                                   NuGetv3LocalRepository userPackageFolder,
                                                                                                   IReadOnlyList <NuGetv3LocalRepository> fallbackPackageFolders,
                                                                                                   RemoteDependencyWalker remoteWalker,
                                                                                                   RemoteWalkContext context,
                                                                                                   bool forceRuntimeGraphCreation,
                                                                                                   CancellationToken token,
                                                                                                   TelemetryActivity telemetryActivity)
        {
            var allRuntimes         = RuntimeGraph.Empty;
            var frameworkTasks      = new List <Task <RestoreTargetGraph> >();
            var graphs              = new List <RestoreTargetGraph>();
            var runtimesByFramework = frameworkRuntimePairs.ToLookup(p => p.Framework, p => p.RuntimeIdentifier);
            var success             = true;

            telemetryActivity.StartIntervalMeasure();

            foreach (var pair in runtimesByFramework)
            {
                _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, pair.Key.DotNetFrameworkName));

                frameworkTasks.Add(WalkDependenciesAsync(projectRange,
                                                         pair.Key,
                                                         remoteWalker,
                                                         context,
                                                         token: token));
            }

            var frameworkGraphs = await Task.WhenAll(frameworkTasks);

            graphs.AddRange(frameworkGraphs);

            telemetryActivity.EndIntervalMeasure(WalkFrameworkDependencyDuration);

            telemetryActivity.StartIntervalMeasure();

            var downloadDependencyResolutionTasks = new List <Task <DownloadDependencyResolutionResult> >();
            var ddLibraryRangeToRemoteMatchCache  = new ConcurrentDictionary <LibraryRange, Task <Tuple <LibraryRange, RemoteMatch> > >();

            foreach (var targetFrameworkInformation in _request.Project.TargetFrameworks)
            {
                downloadDependencyResolutionTasks.Add(ResolveDownloadDependencies(
                                                          context,
                                                          ddLibraryRangeToRemoteMatchCache,
                                                          targetFrameworkInformation,
                                                          token));
            }

            var downloadDependencyResolutionResults = await Task.WhenAll(downloadDependencyResolutionTasks);

            telemetryActivity.EndIntervalMeasure(EvaluateDownloadDependenciesDuration);

            var uniquePackages = new HashSet <LibraryIdentity>();

            success &= await InstallPackagesAsync(
                uniquePackages,
                graphs,
                downloadDependencyResolutionResults,
                userPackageFolder,
                token);

            // Check if any non-empty RIDs exist before reading the runtime graph (runtime.json).
            // Searching all packages for runtime.json and building the graph can be expensive.
            var hasNonEmptyRIDs = frameworkRuntimePairs.Any(
                tfmRidPair => !string.IsNullOrEmpty(tfmRidPair.RuntimeIdentifier));

            // The runtime graph needs to be created for scenarios with supports, forceRuntimeGraphCreation allows this.
            // Resolve runtime dependencies
            if (hasNonEmptyRIDs || forceRuntimeGraphCreation)
            {
                telemetryActivity.StartIntervalMeasure();

                var localRepositories = new List <NuGetv3LocalRepository>();
                localRepositories.Add(userPackageFolder);
                localRepositories.AddRange(fallbackPackageFolders);

                var runtimeGraphs = new List <RestoreTargetGraph>();
                var runtimeTasks  = new List <Task <RestoreTargetGraph[]> >();
                var projectProvidedRuntimeIdentifierGraphs = new SortedList <string, RuntimeGraph>();
                foreach (var graph in graphs)
                {
                    // PCL Projects with Supports have a runtime graph but no matching framework.
                    var runtimeGraphPath = _request.Project.TargetFrameworks.
                                           FirstOrDefault(e => NuGetFramework.Comparer.Equals(e.FrameworkName, graph.Framework))?.RuntimeIdentifierGraphPath;

                    RuntimeGraph projectProviderRuntimeGraph = null;
                    if (runtimeGraphPath != null &&
                        !projectProvidedRuntimeIdentifierGraphs.TryGetValue(runtimeGraphPath, out projectProviderRuntimeGraph))
                    {
                        projectProviderRuntimeGraph = GetRuntimeGraph(runtimeGraphPath);
                        success &= projectProviderRuntimeGraph != null;
                        projectProvidedRuntimeIdentifierGraphs.Add(runtimeGraphPath, projectProviderRuntimeGraph);
                    }


                    var runtimeGraph = GetRuntimeGraph(graph, localRepositories, projectRuntimeGraph: projectProviderRuntimeGraph);
                    var runtimeIds   = runtimesByFramework[graph.Framework];

                    // Merge all runtimes for the output
                    allRuntimes = RuntimeGraph.Merge(allRuntimes, runtimeGraph);

                    runtimeTasks.Add(WalkRuntimeDependenciesAsync(projectRange,
                                                                  graph,
                                                                  runtimeIds.Where(rid => !string.IsNullOrEmpty(rid)),
                                                                  remoteWalker,
                                                                  context,
                                                                  runtimeGraph,
                                                                  token: token));
                }

                foreach (var runtimeSpecificGraph in (await Task.WhenAll(runtimeTasks)).SelectMany(g => g))
                {
                    runtimeGraphs.Add(runtimeSpecificGraph);
                }

                graphs.AddRange(runtimeGraphs);

                telemetryActivity.EndIntervalMeasure(WalkRuntimeDependencyDuration);

                // Install runtime-specific packages
                success &= await InstallPackagesAsync(
                    uniquePackages,
                    runtimeGraphs,
                    Array.Empty <DownloadDependencyResolutionResult>(),
                    userPackageFolder,
                    token);
            }

            // Update the logger with the restore target graphs
            // This allows lazy initialization for the Transitive Warning Properties
            _logger.ApplyRestoreOutput(graphs);

            // Warn for all dependencies that do not have exact matches or
            // versions that have been bumped up unexpectedly.
            // TODO https://github.com/NuGet/Home/issues/7709: When ranges are implemented for download dependencies the bumped up dependencies need to be handled.
            await UnexpectedDependencyMessages.LogAsync(graphs, _request.Project, _logger);

            success &= (await ResolutionSucceeded(graphs, downloadDependencyResolutionResults, context, token));

            return(Tuple.Create(success, graphs, allRuntimes));
        }
Exemple #17
0
        public async Task <Tuple <bool, List <RestoreTargetGraph>, RuntimeGraph> > TryRestore(LibraryRange projectRange,
                                                                                              IEnumerable <FrameworkRuntimePair> frameworkRuntimePairs,
                                                                                              HashSet <LibraryIdentity> allInstalledPackages,
                                                                                              NuGetv3LocalRepository localRepository,
                                                                                              RemoteDependencyWalker remoteWalker,
                                                                                              RemoteWalkContext context,
                                                                                              bool writeToLockFile,
                                                                                              CancellationToken token)
        {
            var allRuntimes         = RuntimeGraph.Empty;
            var frameworkTasks      = new List <Task <RestoreTargetGraph> >();
            var graphs              = new List <RestoreTargetGraph>();
            var runtimesByFramework = frameworkRuntimePairs.ToLookup(p => p.Framework, p => p.RuntimeIdentifier);

            foreach (var pair in runtimesByFramework)
            {
                _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, pair.Key.DotNetFrameworkName));

                frameworkTasks.Add(WalkDependenciesAsync(projectRange,
                                                         pair.Key,
                                                         remoteWalker,
                                                         context,
                                                         writeToLockFile: writeToLockFile,
                                                         token: token));
            }

            var frameworkGraphs = await Task.WhenAll(frameworkTasks);

            graphs.AddRange(frameworkGraphs);

            if (!ResolutionSucceeded(frameworkGraphs))
            {
                return(Tuple.Create(false, graphs, allRuntimes));
            }

            await InstallPackagesAsync(graphs,
                                       _request.PackagesDirectory,
                                       allInstalledPackages,
                                       _request.MaxDegreeOfConcurrency,
                                       token);

            // Clear the in-memory cache for newly installed packages
            localRepository.ClearCacheForIds(allInstalledPackages.Select(package => package.Name));

            // Resolve runtime dependencies
            var runtimeGraphs = new List <RestoreTargetGraph>();

            if (runtimesByFramework.Count > 0)
            {
                var runtimeTasks = new List <Task <RestoreTargetGraph[]> >();
                foreach (var graph in graphs)
                {
                    // Get the runtime graph for this specific tfm graph
                    var runtimeGraph = GetRuntimeGraph(graph, localRepository);
                    var runtimeIds   = runtimesByFramework[graph.Framework];

                    // Merge all runtimes for the output
                    allRuntimes = RuntimeGraph.Merge(allRuntimes, runtimeGraph);

                    runtimeTasks.Add(WalkRuntimeDependenciesAsync(projectRange,
                                                                  graph,
                                                                  runtimeIds.Where(rid => !string.IsNullOrEmpty(rid)),
                                                                  remoteWalker,
                                                                  context,
                                                                  localRepository,
                                                                  runtimeGraph,
                                                                  writeToLockFile: writeToLockFile,
                                                                  token: token));
                }

                foreach (var runtimeSpecificGraph in (await Task.WhenAll(runtimeTasks)).SelectMany(g => g))
                {
                    runtimeGraphs.Add(runtimeSpecificGraph);
                }

                graphs.AddRange(runtimeGraphs);

                if (!ResolutionSucceeded(runtimeGraphs))
                {
                    return(Tuple.Create(false, graphs, allRuntimes));
                }

                // Install runtime-specific packages
                await InstallPackagesAsync(runtimeGraphs,
                                           _request.PackagesDirectory,
                                           allInstalledPackages,
                                           _request.MaxDegreeOfConcurrency,
                                           token);

                // Clear the in-memory cache for newly installed packages
                localRepository.ClearCacheForIds(allInstalledPackages.Select(package => package.Name));
            }

            return(Tuple.Create(true, graphs, allRuntimes));
        }
        private async Task <IEnumerable <RestoreTargetGraph> > ExecuteRestoreAsync(NuGetv3LocalRepository localRepository,
                                                                                   RemoteWalkContext context,
                                                                                   CancellationToken token)
        {
            if (_request.Project.TargetFrameworks.Count == 0)
            {
                _logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectDoesNotSpecifyTargetFrameworks, _request.Project.Name, _request.Project.FilePath));
                _success = false;
                return(Enumerable.Empty <RestoreTargetGraph>());
            }

            _logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, _request.Project.FilePath));

            // External references
            var updatedExternalProjects = new List <ExternalProjectReference>(_request.ExternalProjects);

            if (_request.ExternalProjects.Count > 0)
            {
                // There should be at most one match in the external projects.
                var rootProjectMatches = _request.ExternalProjects.Where(proj =>
                                                                         string.Equals(
                                                                             _request.Project.Name,
                                                                             proj.PackageSpecProjectName,
                                                                             StringComparison.OrdinalIgnoreCase))
                                         .ToList();

                if (rootProjectMatches.Count > 1)
                {
                    throw new InvalidOperationException($"Ambiguous project name '{_request.Project.Name}'.");
                }

                var rootProject = rootProjectMatches.SingleOrDefault();

                if (rootProject != null)
                {
                    // Replace the project spec with the passed in package spec,
                    // for installs which are done in memory first this will be
                    // different from the one on disk
                    updatedExternalProjects.RemoveAll(project =>
                                                      project.UniqueName.Equals(rootProject.UniqueName, StringComparison.Ordinal));

                    var updatedReference = new ExternalProjectReference(
                        rootProject.UniqueName,
                        _request.Project,
                        rootProject.MSBuildProjectPath,
                        rootProject.ExternalProjectReferences);

                    updatedExternalProjects.Add(updatedReference);

                    // Determine if the targets and props files should be written out.
                    context.IsMsBuildBased = XProjUtility.IsMSBuildBasedProject(rootProject.MSBuildProjectPath);
                }
                else
                {
                    Debug.Fail("RestoreRequest.ExternaProjects contains references, but does not contain the top level references. Add the project we are restoring for.");
                    throw new InvalidOperationException($"Missing external reference metadata for {_request.Project.Name}");
                }
            }

            // Load repositories

            // the external project provider is specific to the current restore project
            var projectResolver = new PackageSpecResolver(_request.Project);

            context.ProjectLibraryProviders.Add(
                new PackageSpecReferenceDependencyProvider(projectResolver, updatedExternalProjects, _logger));

            var remoteWalker = new RemoteDependencyWalker(context);

            var projectRange = new LibraryRange()
            {
                Name           = _request.Project.Name,
                VersionRange   = new VersionRange(_request.Project.Version),
                TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject
            };

            // Resolve dependency graphs
            var allInstalledPackages         = new HashSet <LibraryIdentity>();
            var allGraphs                    = new List <RestoreTargetGraph>();
            var runtimeIds                   = RequestRuntimeUtility.GetRestoreRuntimes(_request);
            var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(_request.Project, runtimeIds);

            var projectRestoreRequest = new ProjectRestoreRequest(
                _request,
                _request.Project,
                _request.ExistingLockFile,
                _runtimeGraphCache,
                _runtimeGraphCacheByPackage);
            var projectRestoreCommand = new ProjectRestoreCommand(_logger, projectRestoreRequest);
            var result = await projectRestoreCommand.TryRestore(
                projectRange,
                projectFrameworkRuntimePairs,
                allInstalledPackages,
                localRepository,
                remoteWalker,
                context,
                writeToLockFile : true,
                token : token);

            var success  = result.Item1;
            var runtimes = result.Item3;

            allGraphs.AddRange(result.Item2);

            _success = success;

            // Calculate compatibility profiles to check by merging those defined in the project with any from the command line
            foreach (var profile in _request.Project.RuntimeGraph.Supports)
            {
                CompatibilityProfile compatProfile;
                if (profile.Value.RestoreContexts.Any())
                {
                    // Just use the contexts from the project definition
                    compatProfile = profile.Value;
                }
                else if (!runtimes.Supports.TryGetValue(profile.Value.Name, out compatProfile))
                {
                    // No definition of this profile found, so just continue to the next one
                    _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Log_UnknownCompatibilityProfile, profile.Key));
                    continue;
                }

                foreach (var pair in compatProfile.RestoreContexts)
                {
                    _logger.LogDebug($" {profile.Value.Name} -> +{pair}");
                    _request.CompatibilityProfiles.Add(pair);
                }
            }

            // Walk additional runtime graphs for supports checks
            if (_success && _request.CompatibilityProfiles.Any())
            {
                var compatibilityResult = await projectRestoreCommand.TryRestore(projectRange,
                                                                                 _request.CompatibilityProfiles,
                                                                                 allInstalledPackages,
                                                                                 localRepository,
                                                                                 remoteWalker,
                                                                                 context,
                                                                                 writeToLockFile : false,
                                                                                 token : token);

                _success = compatibilityResult.Item1;

                // TryRestore may contain graphs that are already in allGraphs if the
                // supports section contains the same TxM as the project framework.
                var currentGraphs = new HashSet <KeyValuePair <NuGetFramework, string> >(
                    allGraphs.Select(graph => new KeyValuePair <NuGetFramework, string>(
                                         graph.Framework,
                                         graph.RuntimeIdentifier))
                    );

                foreach (var graph in compatibilityResult.Item2)
                {
                    var key = new KeyValuePair <NuGetFramework, string>(
                        graph.Framework,
                        graph.RuntimeIdentifier);

                    if (currentGraphs.Add(key))
                    {
                        allGraphs.Add(graph);
                    }
                }
            }

            return(allGraphs);
        }
        private async Task <IEnumerable <ToolRestoreResult> > ExecuteToolRestoresAsync(
            NuGetv3LocalRepository localRepository,
            CancellationToken token)
        {
            var toolPathResolver = new ToolPathResolver(_request.PackagesDirectory);
            var results          = new List <ToolRestoreResult>();

            foreach (var tool in _request.Project.Tools)
            {
                _logger.LogMinimal(string.Format(
                                       CultureInfo.CurrentCulture,
                                       Strings.Log_RestoringToolPackages,
                                       tool.LibraryRange.Name,
                                       _request.Project.FilePath));

                // Build the fallback framework (which uses the "imports").
                var framework = LockFile.ToolFramework;
                if (tool.Imports.Any())
                {
                    framework = new FallbackFramework(framework, tool.Imports);
                }

                // Build a package spec in memory to execute the tool restore as if it were
                // its own project. For now, we always restore for a null runtime and a single
                // constant framework.
                var toolPackageSpec = new PackageSpec(new JObject())
                {
                    Name             = Guid.NewGuid().ToString(), // make sure this package never collides with a dependency
                    Dependencies     = new List <LibraryDependency>(),
                    Tools            = new List <ToolDependency>(),
                    TargetFrameworks =
                    {
                        new TargetFrameworkInformation
                        {
                            FrameworkName = framework,
                            Dependencies  = new List <LibraryDependency>
                            {
                                new LibraryDependency
                                {
                                    LibraryRange = tool.LibraryRange
                                }
                            }
                        }
                    }
                };

                // Try to find the existing lock file. Since the existing lock file is pathed under
                // a folder that includes the resolved tool's version, this is a bit of a chicken
                // and egg problem. That is, we need to run the restore operation in order to resolve
                // a tool version, but we need the tool version to find the existing project.lock.json
                // file which is required before executing the restore! Fortunately, this is solved by
                // looking at the tool's consuming project's lock file to see if the tool has been
                // restored before.
                LockFile existingToolLockFile = null;
                if (_request.ExistingLockFile != null)
                {
                    var existingTarget = _request
                                         .ExistingLockFile
                                         .Tools
                                         .Where(t => t.RuntimeIdentifier == null)
                                         .Where(t => t.TargetFramework.Equals(LockFile.ToolFramework))
                                         .FirstOrDefault();

                    var existingLibrary = existingTarget?.Libraries
                                          .Where(l => StringComparer.OrdinalIgnoreCase.Equals(l.Name, tool.LibraryRange.Name))
                                          .Where(l => tool.LibraryRange.VersionRange.Satisfies(l.Version))
                                          .FirstOrDefault();

                    if (existingLibrary != null)
                    {
                        var existingLockFilePath = toolPathResolver.GetLockFilePath(
                            existingLibrary.Name,
                            existingLibrary.Version,
                            existingTarget.TargetFramework);

                        existingToolLockFile = LockFileUtilities.GetLockFile(existingLockFilePath, _logger);
                    }
                }

                // Execute the restore.
                var toolSuccess = true; // success for this individual tool restore
                var runtimeIds  = new HashSet <string>();
                var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(toolPackageSpec, runtimeIds);
                var allInstalledPackages         = new HashSet <LibraryIdentity>();
                var contextForTool        = CreateRemoteWalkContext(_request);
                var walker                = new RemoteDependencyWalker(contextForTool);
                var projectRestoreRequest = new ProjectRestoreRequest(
                    _request,
                    toolPackageSpec,
                    existingToolLockFile,
                    new Dictionary <NuGetFramework, RuntimeGraph>(),
                    _runtimeGraphCacheByPackage);
                var projectRestoreCommand = new ProjectRestoreCommand(_logger, projectRestoreRequest);
                var result = await projectRestoreCommand.TryRestore(
                    tool.LibraryRange,
                    projectFrameworkRuntimePairs,
                    allInstalledPackages,
                    localRepository,
                    walker,
                    contextForTool,
                    writeToLockFile : true,
                    token : token);

                var graphs = result.Item2;
                if (!result.Item1)
                {
                    toolSuccess = false;
                    _success    = false;
                }

                // Create the lock file (in memory).
                var toolLockFile = BuildLockFile(
                    existingToolLockFile,
                    toolPackageSpec,
                    graphs,
                    localRepository,
                    contextForTool,
                    Enumerable.Empty <ToolRestoreResult>(),
                    false);

                // Build the path based off of the resolved tool. For now, we assume there is only
                // ever one target.
                var target            = toolLockFile.Targets.Single();
                var fileTargetLibrary = target
                                        .Libraries
                                        .FirstOrDefault(l => StringComparer.OrdinalIgnoreCase.Equals(tool.LibraryRange.Name, l.Name));
                string toolLockFilePath = null;
                if (fileTargetLibrary != null)
                {
                    toolLockFilePath = toolPathResolver.GetLockFilePath(
                        fileTargetLibrary.Name,
                        fileTargetLibrary.Version,
                        target.TargetFramework);
                }

                // Validate the results.
                if (!ValidateRestoreGraphs(graphs, _logger))
                {
                    toolSuccess = false;
                    _success    = false;
                }

                var checkResults = VerifyCompatibility(
                    toolPackageSpec,
                    new Dictionary <RestoreTargetGraph, Dictionary <string, LibraryIncludeFlags> >(),
                    localRepository,
                    toolLockFile,
                    graphs,
                    _logger);

                if (checkResults.Any(r => !r.Success))
                {
                    toolSuccess = false;
                    _success    = false;
                }

                results.Add(new ToolRestoreResult(
                                tool.LibraryRange.Name,
                                toolSuccess,
                                target,
                                fileTargetLibrary,
                                toolLockFilePath,
                                toolLockFile,
                                existingToolLockFile));
            }

            return(results);
        }
Exemple #20
0
        private async Task <bool> RestoreForProject(string projectJsonPath, string rootDirectory, string packagesDirectory)
        {
            var success = true;

            Logger.WriteInformation(string.Format("Restoring packages for {0}", projectJsonPath.Bold()));

            var sw = new Stopwatch();

            sw.Start();

            NuGetProject project;

            if (!ProjectReader.TryReadProject(projectJsonPath, out project))
            {
                throw new Exception("Unable to locate project.json");
            }

            var projectDirectory    = project.ProjectDirectory;
            var projectLockFilePath = Path.Combine(projectDirectory, LockFileFormat.LockFileName);

            var properties = new Dictionary <string, string>
            {
                { "DesignTimeBuild", "true" },
                { "BuildProjectReferences", "false" },
                { "_ResolveReferenceDependencies", "true" },
                { "SolutionDir", rootDirectory + Path.DirectorySeparatorChar }
            };

            var projectCollection = new ProjectCollection();

            foreach (var projectFile in Directory.EnumerateFiles(projectDirectory, "*.csproj"))
            {
                projectCollection.LoadProject(projectFile);
            }

            foreach (var projectFile in Directory.EnumerateFiles(projectDirectory, "*.vbproj"))
            {
                projectCollection.LoadProject(projectFile);
            }

            foreach (var projectFile in Directory.EnumerateFiles(projectDirectory, "*.fsproj"))
            {
                projectCollection.LoadProject(projectFile);
            }

            var context = new RemoteWalkContext();

            var nugetRepository = new NuGetv3LocalRepository(packagesDirectory, checkPackageIdCase: true);

            context.ProjectLibraryProviders.Add(new LocalDependencyProvider(
                                                    new MSBuildDependencyProvider(projectCollection)));

            context.ProjectLibraryProviders.Add(
                new LocalDependencyProvider(
                    new ProjectReferenceDependencyProvider(
                        new ProjectResolver(
                            projectDirectory,
                            rootDirectory))));

            context.LocalLibraryProviders.Add(
                new LocalDependencyProvider(
                    new NuGetDependencyResolver(nugetRepository)));

            var effectiveSources = PackageSourceUtils.GetEffectivePackageSources(SourceProvider,
                                                                                 Sources, FallbackSources);

            AddRemoteProvidersFromSources(context.RemoteLibraryProviders, effectiveSources);

            var remoteWalker = new RemoteDependencyWalker(context);

            var tasks = new List <Task <GraphNode <RemoteResolveResult> > >();

            var msbuildProject = projectCollection.LoadedProjects.FirstOrDefault();

            if (msbuildProject != null)
            {
                var name = msbuildProject.GetPropertyValue("AssemblyName");
                var targetFrameworkMoniker = msbuildProject.GetPropertyValue("TargetFrameworkMoniker");

                // This is so that we have a unique cache per target framework
                tasks.Add(remoteWalker.Walk(name, new NuGetVersion(new Version()), NuGetFramework.Parse(targetFrameworkMoniker)));
            }
            else
            {
                foreach (var framework in project.TargetFrameworks)
                {
                    tasks.Add(remoteWalker.Walk(project.Name, project.Version, framework.FrameworkName));
                }
            }

            var graphs = await Task.WhenAll(tasks);

            Logger.WriteInformation(string.Format("{0}, {1}ms elapsed", "Resolving complete".Green(), sw.ElapsedMilliseconds));

            var libraries    = new HashSet <Library>();
            var installItems = new List <GraphItem <RemoteResolveResult> >();
            var missingItems = new HashSet <LibraryRange>();

            foreach (var g in graphs)
            {
                g.Dump(s => Logger.WriteInformation(s));

                g.ForEach(node =>
                {
                    if (node == null || node.Key == null)
                    {
                        return;
                    }

                    if (node.Item == null || node.Item.Data.Match == null)
                    {
                        if (!node.Key.IsGacOrFrameworkReference &&
                            node.Key.VersionRange != null &&
                            missingItems.Add(node.Key))
                        {
                            Logger.WriteError(string.Format("Unable to locate {0} {1}", node.Key.Name.Red().Bold(), node.Key.VersionRange));
                            success = false;
                        }

                        return;
                    }

                    var isRemote = context.RemoteLibraryProviders.Contains(node.Item.Data.Match.Provider);
                    var isAdded  = installItems.Any(item => item.Data.Match.Library == node.Item.Data.Match.Library);

                    if (!isAdded && isRemote)
                    {
                        installItems.Add(node.Item);
                    }

                    libraries.Add(node.Item.Key);
                });
            }

            await InstallPackages(installItems, packagesDirectory, packageFilter : (library, nupkgSHA) => true);

            if (success)
            {
                Logger.WriteInformation(string.Format("Writing lock file {0}", projectLockFilePath.White().Bold()));
                WriteLockFile(projectLockFilePath, libraries, nugetRepository);
            }

            //if (!ScriptExecutor.Execute(project, "postrestore", getVariable))
            //{
            //    Reports.Error.WriteLine(ScriptExecutor.ErrorMessage);
            //    return false;
            //}

            //if (!ScriptExecutor.Execute(project, "prepare", getVariable))
            //{
            //    Reports.Error.WriteLine(ScriptExecutor.ErrorMessage);
            //    return false;
            //}

            Logger.WriteInformation(string.Format("{0}, {1}ms elapsed", "Restore complete".Green().Bold(), sw.ElapsedMilliseconds));

            //for (int i = 0; i < contexts.Count; i++)
            //{
            //    PrintDependencyGraph(graphs[i], contexts[i].FrameworkName);
            //}

            return(success);
        }
Exemple #21
0
        private async Task <List <RestoreTargetGraph> > WalkRuntimeDependencies(LibraryRange projectRange, RestoreTargetGraph graph, RuntimeGraph projectRuntimeGraph, RemoteDependencyWalker walker, RemoteWalkContext context, NuGetv3LocalRepository localRepository)
        {
            // Load runtime specs
            _log.LogVerbose("Scanning packages for runtime.json files...");
            var runtimeGraph = projectRuntimeGraph;

            graph.Graph.ForEach(node =>
            {
                var match = node?.Item?.Data?.Match;
                if (match == null)
                {
                    return;
                }

                // Locate the package in the local repository
                var package = localRepository.FindPackagesById(match.Library.Name).FirstOrDefault(p => p.Version == match.Library.Version);
                if (package != null)
                {
                    var nextGraph = LoadRuntimeGraph(package);
                    if (nextGraph != null)
                    {
                        _log.LogVerbose($"Merging in runtimes defined in {match.Library}");
                        runtimeGraph = RuntimeGraph.Merge(runtimeGraph, nextGraph);
                    }
                }
            });

            var resultGraphs = new List <RestoreTargetGraph>();

            foreach (var runtimeName in projectRuntimeGraph.Runtimes.Keys)
            {
                _log.LogInformation($"Restoring packages for {graph.Framework} on {runtimeName}");
                resultGraphs.Add(await WalkDependencies(projectRange, graph.Framework, runtimeName, runtimeGraph, walker, context));
            }
            return(resultGraphs);
        }
Exemple #22
0
        public static void InstallPackage(IReadOnlyList <string> packages, bool quiet)
        {
            Init();
            RemoteWalkContext context = new RemoteWalkContext();

            ILogger            logger       = new NullLogger();
            SourceCacheContext cacheContext = new SourceCacheContext
            {
                IgnoreFailedSources = true
            };

            foreach (SourceRepository repo in Repos)
            {
                if (!repo.PackageSource.IsLocal)
                {
                    context.RemoteLibraryProviders.Add(new SourceRepositoryDependencyProvider(repo, logger, cacheContext));
                }
                else
                {
                    context.LocalLibraryProviders.Add(new SourceRepositoryDependencyProvider(repo, logger, cacheContext));
                }
            }

            Paths.User.Content.CreateDirectory();
            RemoteDependencyWalker walker                        = new RemoteDependencyWalker(context);
            HashSet <Package>      remainingPackages             = new HashSet <Package>(packages.Select(x => new Package(x, VersionRange.All)));
            HashSet <Package>      encounteredPackages           = new HashSet <Package>();
            List <string>          templateRoots                 = new List <string>();
            List <KeyValuePair <string, string> > componentRoots = new List <KeyValuePair <string, string> >();

            while (remainingPackages.Count > 0)
            {
                HashSet <Package> nextRound = new HashSet <Package>();

                foreach (Package package in remainingPackages)
                {
                    string name = package.PackageId;
                    GraphNode <RemoteResolveResult> result = walker.WalkAsync(new LibraryRange(name, package.Version, LibraryDependencyTarget.All), NuGetFramework.AnyFramework, "", RuntimeGraph.Empty, true).Result;
                    RemoteMatch     match           = result.Item.Data.Match;
                    PackageIdentity packageIdentity = new PackageIdentity(match.Library.Name, match.Library.Version);

                    nextRound.UnionWith(result.Item.Data.Dependencies.Select(x => new Package(x.Name, x.LibraryRange.VersionRange)));

                    VersionFolderPathContext versionFolderPathContext = new VersionFolderPathContext(
                        packageIdentity,
                        Paths.User.PackageCache,
                        new NullLogger(),
                        packageSaveMode: PackageSaveMode.Defaultv3,
                        xmlDocFileSaveMode: XmlDocFileSaveMode.Skip,
                        fixNuspecIdCasing: true,
                        normalizeFileNames: true);

                    if (match.Library.Version == null)
                    {
                        if (!quiet)
                        {
                            throw new Exception($"Package '{package.PackageId}' version {package.Version} could not be located.");
                        }
                        else
                        {
                            continue;
                        }
                    }

                    string source = Path.Combine(Paths.User.PackageCache, match.Library.Name, match.Library.Version.ToString());

                    if (!source.Exists() && match.Provider != null)
                    {
                        PackageExtractor.InstallFromSourceAsync(
                            stream => match.Provider.CopyToAsync(match.Library, stream, CancellationToken.None),
                            versionFolderPathContext,
                            CancellationToken.None).Wait();

                        string target = Path.Combine(Paths.User.Content, match.Library.Name);
                        target.CreateDirectory();
                        target = Path.Combine(target, match.Library.Version.ToString());
                        target.CreateDirectory();
                        Paths.Copy(source, target);
                        target.Delete("*.nupkg", "*.nupkg.*");

                        string nuspec = target.EnumerateFiles("*.nuspec").FirstOrDefault();

                        //If there's a nuspec, figure out whether this package is a template and walk the dependency graph
                        if (nuspec?.Exists() ?? false)
                        {
                            XDocument doc = XDocument.Load(nuspec);
                            IReadOnlyList <PackageType> types = NuspecUtility.GetPackageTypes(doc.Root.Element(XName.Get("metadata", "http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd")), false);
                            //If the thing we got is a template...
                            if (types.Any(x => string.Equals(x.Name, "template", StringComparison.OrdinalIgnoreCase)))
                            {
                                templateRoots.Add(target);
                            }
                            else
                            {
                                componentRoots.Add(new KeyValuePair <string, string>(match.Library.Name, match.Library.Version.ToString()));
                            }
                        }
                    }
                }

                encounteredPackages.UnionWith(remainingPackages);
                nextRound.ExceptWith(encounteredPackages);
                remainingPackages = nextRound;
            }

            foreach (KeyValuePair <string, string> package in componentRoots)
            {
                foreach (string path in Path.Combine(Paths.User.Content, package.Key, package.Value).EnumerateFiles($"{package.Key}.dll", SearchOption.AllDirectories))
                {
                    if (path.IndexOf($"{Path.DirectorySeparatorChar}lib{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) < 0 ||
                        (path.IndexOf($"{Path.DirectorySeparatorChar}netstandard1.", StringComparison.OrdinalIgnoreCase) < 0 &&
                         path.IndexOf($"{Path.DirectorySeparatorChar}netcoreapp1.", StringComparison.OrdinalIgnoreCase) < 0))
                    {
                        continue;
                    }

#if !NET451
                    Assembly asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
#else
                    Assembly asm = Assembly.LoadFile(path);
#endif
                    foreach (Type type in asm.GetTypes())
                    {
                        SettingsLoader.Components.Register(type);
                    }
                }
            }

            TemplateCache.Scan(templateRoots);
        }
Exemple #23
0
        public async Task <Tuple <bool, List <RestoreTargetGraph>, RuntimeGraph> > TryRestoreAsync(LibraryRange projectRange,
                                                                                                   IEnumerable <FrameworkRuntimePair> frameworkRuntimePairs,
                                                                                                   NuGetv3LocalRepository userPackageFolder,
                                                                                                   IReadOnlyList <NuGetv3LocalRepository> fallbackPackageFolders,
                                                                                                   RemoteDependencyWalker remoteWalker,
                                                                                                   RemoteWalkContext context,
                                                                                                   bool forceRuntimeGraphCreation,
                                                                                                   CancellationToken token)
        {
            var allRuntimes         = RuntimeGraph.Empty;
            var frameworkTasks      = new List <Task <RestoreTargetGraph> >();
            var graphs              = new List <RestoreTargetGraph>();
            var runtimesByFramework = frameworkRuntimePairs.ToLookup(p => p.Framework, p => p.RuntimeIdentifier);

            foreach (var pair in runtimesByFramework)
            {
                _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, pair.Key.DotNetFrameworkName));

                frameworkTasks.Add(WalkDependenciesAsync(projectRange,
                                                         pair.Key,
                                                         remoteWalker,
                                                         context,
                                                         token: token));
            }

            var frameworkGraphs = await Task.WhenAll(frameworkTasks);

            graphs.AddRange(frameworkGraphs);

            await InstallPackagesAsync(graphs,
                                       userPackageFolder,
                                       token);

            var localRepositories = new List <NuGetv3LocalRepository>();

            localRepositories.Add(userPackageFolder);
            localRepositories.AddRange(fallbackPackageFolders);

            // Check if any non-empty RIDs exist before reading the runtime graph (runtime.json).
            // Searching all packages for runtime.json and building the graph can be expensive.
            var hasNonEmptyRIDs = frameworkRuntimePairs.Any(
                tfmRidPair => !string.IsNullOrEmpty(tfmRidPair.RuntimeIdentifier));

            // The runtime graph needs to be created for scenarios with supports, forceRuntimeGraphCreation allows this.
            // Resolve runtime dependencies
            if (hasNonEmptyRIDs || forceRuntimeGraphCreation)
            {
                var runtimeGraphs = new List <RestoreTargetGraph>();

                var runtimeTasks = new List <Task <RestoreTargetGraph[]> >();
                foreach (var graph in graphs)
                {
                    // Get the runtime graph for this specific tfm graph
                    var runtimeGraph = GetRuntimeGraph(graph, localRepositories);
                    var runtimeIds   = runtimesByFramework[graph.Framework];

                    // Merge all runtimes for the output
                    allRuntimes = RuntimeGraph.Merge(allRuntimes, runtimeGraph);

                    runtimeTasks.Add(WalkRuntimeDependenciesAsync(projectRange,
                                                                  graph,
                                                                  runtimeIds.Where(rid => !string.IsNullOrEmpty(rid)),
                                                                  remoteWalker,
                                                                  context,
                                                                  runtimeGraph,
                                                                  token: token));
                }

                foreach (var runtimeSpecificGraph in (await Task.WhenAll(runtimeTasks)).SelectMany(g => g))
                {
                    runtimeGraphs.Add(runtimeSpecificGraph);
                }

                graphs.AddRange(runtimeGraphs);

                // Install runtime-specific packages
                await InstallPackagesAsync(runtimeGraphs,
                                           userPackageFolder,
                                           token);
            }

            // Update the logger with the restore target graphs
            // This allows lazy initialization for the Transitive Warning Properties
            _logger.ApplyRestoreOutput(graphs);

            // Warn for all dependencies that do not have exact matches or
            // versions that have been bumped up unexpectedly.
            await UnexpectedDependencyMessages.LogAsync(graphs, _request.Project, _logger);

            var success = await ResolutionSucceeded(graphs, context, token);

            return(Tuple.Create(success, graphs, allRuntimes));
        }
Exemple #24
0
 private Task <RestoreTargetGraph> WalkDependencies(LibraryRange projectRange, NuGetFramework framework, RemoteDependencyWalker walker, RemoteWalkContext context)
 {
     return(WalkDependencies(projectRange, framework, null, RuntimeGraph.Empty, walker, context));
 }
Exemple #25
0
        public async Task <Tuple <bool, List <RestoreTargetGraph>, RuntimeGraph> > TryRestore(LibraryRange projectRange,
                                                                                              IEnumerable <FrameworkRuntimePair> frameworkRuntimePairs,
                                                                                              HashSet <LibraryIdentity> allInstalledPackages,
                                                                                              NuGetv3LocalRepository userPackageFolder,
                                                                                              IReadOnlyList <NuGetv3LocalRepository> fallbackPackageFolders,
                                                                                              RemoteDependencyWalker remoteWalker,
                                                                                              RemoteWalkContext context,
                                                                                              bool forceRuntimeGraphCreation,
                                                                                              CancellationToken token)
        {
            var allRuntimes         = RuntimeGraph.Empty;
            var frameworkTasks      = new List <Task <RestoreTargetGraph> >();
            var graphs              = new List <RestoreTargetGraph>();
            var runtimesByFramework = frameworkRuntimePairs.ToLookup(p => p.Framework, p => p.RuntimeIdentifier);

            foreach (var pair in runtimesByFramework)
            {
                _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, pair.Key.DotNetFrameworkName));

                frameworkTasks.Add(WalkDependenciesAsync(projectRange,
                                                         pair.Key,
                                                         remoteWalker,
                                                         context,
                                                         token: token));
            }

            var frameworkGraphs = await Task.WhenAll(frameworkTasks);

            graphs.AddRange(frameworkGraphs);

            if (!ResolutionSucceeded(frameworkGraphs))
            {
                return(Tuple.Create(false, graphs, allRuntimes));
            }

            await InstallPackagesAsync(graphs,
                                       _request.PackagesDirectory,
                                       allInstalledPackages,
                                       _request.MaxDegreeOfConcurrency,
                                       token);

            // Clear the in-memory cache for newly installed packages
            userPackageFolder.ClearCacheForIds(allInstalledPackages.Select(package => package.Name));

            var localRepositories = new List <NuGetv3LocalRepository>();

            localRepositories.Add(userPackageFolder);
            localRepositories.AddRange(fallbackPackageFolders);

            // Check if any non-empty RIDs exist before reading the runtime graph (runtime.json).
            // Searching all packages for runtime.json and building the graph can be expensive.
            var hasNonEmptyRIDs = frameworkRuntimePairs.Any(
                tfmRidPair => !string.IsNullOrEmpty(tfmRidPair.RuntimeIdentifier));

            // The runtime graph needs to be created for scenarios with supports, forceRuntimeGraphCreation allows this.
            // Resolve runtime dependencies
            if (hasNonEmptyRIDs || forceRuntimeGraphCreation)
            {
                var runtimeGraphs = new List <RestoreTargetGraph>();

                var runtimeTasks = new List <Task <RestoreTargetGraph[]> >();
                foreach (var graph in graphs)
                {
                    // Get the runtime graph for this specific tfm graph
                    var runtimeGraph = GetRuntimeGraph(graph, localRepositories);
                    var runtimeIds   = runtimesByFramework[graph.Framework];

                    // Merge all runtimes for the output
                    allRuntimes = RuntimeGraph.Merge(allRuntimes, runtimeGraph);

                    runtimeTasks.Add(WalkRuntimeDependenciesAsync(projectRange,
                                                                  graph,
                                                                  runtimeIds.Where(rid => !string.IsNullOrEmpty(rid)),
                                                                  remoteWalker,
                                                                  context,
                                                                  runtimeGraph,
                                                                  token: token));
                }

                foreach (var runtimeSpecificGraph in (await Task.WhenAll(runtimeTasks)).SelectMany(g => g))
                {
                    runtimeGraphs.Add(runtimeSpecificGraph);
                }

                graphs.AddRange(runtimeGraphs);

                if (!ResolutionSucceeded(runtimeGraphs))
                {
                    return(Tuple.Create(false, graphs, allRuntimes));
                }

                // Install runtime-specific packages
                await InstallPackagesAsync(runtimeGraphs,
                                           _request.PackagesDirectory,
                                           allInstalledPackages,
                                           _request.MaxDegreeOfConcurrency,
                                           token);

                // Clear the in-memory cache for newly installed packages
                userPackageFolder.ClearCacheForIds(allInstalledPackages.Select(package => package.Name));
            }

            return(Tuple.Create(true, graphs, allRuntimes));
        }
Exemple #26
0
        public async Task <RestoreResult> ExecuteAsync(RestoreRequest request)
        {
            if (request.Project.TargetFrameworks.Count == 0)
            {
                _log.LogError("The project does not specify any target frameworks!");
                return(new RestoreResult(success: false, restoreGraphs: Enumerable.Empty <RestoreTargetGraph>()));
            }

            var projectLockFilePath = string.IsNullOrEmpty(request.LockFilePath) ?
                                      Path.Combine(request.Project.BaseDirectory, LockFileFormat.LockFileName) :
                                      request.LockFilePath;

            _log.LogInformation($"Restoring packages for '{request.Project.FilePath}'");

            _log.LogWarning("TODO: Read and use lock file");

            // Load repositories
            var projectResolver = new PackageSpecResolver(request.Project.BaseDirectory);
            var nugetRepository = Repository.Factory.GetCoreV3(request.PackagesDirectory);

            var context = new RemoteWalkContext();

            context.ProjectLibraryProviders.Add(
                new LocalDependencyProvider(
                    new PackageSpecReferenceDependencyProvider(projectResolver)));

            if (request.ExternalProjects != null)
            {
                context.ProjectLibraryProviders.Add(
                    new LocalDependencyProvider(
                        new ExternalProjectReferenceDependencyProvider(request.ExternalProjects)));
            }

            context.LocalLibraryProviders.Add(
                new SourceRepositoryDependencyProvider(nugetRepository, _log));

            foreach (var provider in request.Sources.Select(s => CreateProviderFromSource(s, request.NoCache)))
            {
                context.RemoteLibraryProviders.Add(provider);
            }

            var remoteWalker = new RemoteDependencyWalker(context);

            var projectRange = new LibraryRange()
            {
                Name           = request.Project.Name,
                VersionRange   = new VersionRange(request.Project.Version),
                TypeConstraint = LibraryTypes.Project
            };

            // Resolve dependency graphs
            var frameworks = request.Project.TargetFrameworks.Select(f => f.FrameworkName).ToList();
            var graphs     = new List <RestoreTargetGraph>();

            foreach (var framework in frameworks)
            {
                graphs.Add(await WalkDependencies(projectRange, framework, remoteWalker, context));
            }

            if (graphs.Any(g => g.InConflict))
            {
                _log.LogError("Failed to resolve conflicts");
                return(new RestoreResult(success: false, restoreGraphs: graphs));
            }

            // Install the runtime-agnostic packages
            var allInstalledPackages = new HashSet <LibraryIdentity>();
            var localRepository      = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false);

            await InstallPackages(graphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency);

            // Resolve runtime dependencies
            var runtimeGraphs = new List <RestoreTargetGraph>();

            if (request.Project.RuntimeGraph.Runtimes.Count > 0)
            {
                foreach (var graph in graphs)
                {
                    var runtimeSpecificGraphs = await WalkRuntimeDependencies(projectRange, graph, request.Project.RuntimeGraph, remoteWalker, context, localRepository);

                    runtimeGraphs.AddRange(runtimeSpecificGraphs);
                }

                graphs.AddRange(runtimeGraphs);

                if (runtimeGraphs.Any(g => g.InConflict))
                {
                    _log.LogError("Failed to resolve conflicts");
                    return(new RestoreResult(success: false, restoreGraphs: graphs));
                }

                // Install runtime-specific packages
                await InstallPackages(runtimeGraphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency);
            }
            else
            {
                _log.LogVerbose("Skipping runtime dependency walk, no runtimes defined in project.json");
            }

            // Build the lock file
            var repository     = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false);
            var lockFile       = CreateLockFile(request.Project, graphs, repository);
            var lockFileFormat = new LockFileFormat();

            lockFileFormat.Write(projectLockFilePath, lockFile);

            return(new RestoreResult(true, graphs, lockFile));
        }
Exemple #27
0
        private async Task <RestoreTargetGraph> WalkDependenciesAsync(LibraryRange projectRange,
                                                                      NuGetFramework framework,
                                                                      string runtimeIdentifier,
                                                                      RuntimeGraph runtimeGraph,
                                                                      RemoteDependencyWalker walker,
                                                                      RemoteWalkContext context,
                                                                      bool writeToLockFile,
                                                                      CancellationToken token)
        {
            var name   = FrameworkRuntimePair.GetName(framework, runtimeIdentifier);
            var graphs = new List <GraphNode <RemoteResolveResult> >();

            if (_request.ExistingLockFile != null && _request.ExistingLockFile.IsLocked)
            {
                // Walk all the items in the lock file target and just synthesize the outer graph
                var target = _request.ExistingLockFile.GetTarget(framework, runtimeIdentifier);

                token.ThrowIfCancellationRequested();
                if (target != null)
                {
                    foreach (var targetLibrary in target.Libraries)
                    {
                        token.ThrowIfCancellationRequested();

                        var library = _request.ExistingLockFile.GetLibrary(targetLibrary.Name, targetLibrary.Version);
                        if (library == null)
                        {
                            _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Log_LockFileMissingLibraryForTargetLibrary,
                                                             targetLibrary.Name,
                                                             targetLibrary.Version,
                                                             target.Name));
                            continue; // This library is not in the main lockfile?
                        }

                        var range = new LibraryRange()
                        {
                            Name           = library.Name,
                            TypeConstraint = LibraryDependencyTargetUtils.Parse(library.Type),
                            VersionRange   = new VersionRange(
                                minVersion: library.Version,
                                includeMinVersion: true,
                                maxVersion: library.Version,
                                includeMaxVersion: true)
                        };
                        graphs.Add(await walker.WalkAsync(
                                       range,
                                       framework,
                                       runtimeIdentifier,
                                       runtimeGraph,
                                       recursive: false));
                    }
                }
            }
            else
            {
                graphs.Add(await walker.WalkAsync(
                               projectRange,
                               framework,
                               runtimeIdentifier,
                               runtimeGraph,
                               recursive: true));
            }

            // Resolve conflicts
            _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_ResolvingConflicts, name));

            // Flatten and create the RestoreTargetGraph to hold the packages
            var result = RestoreTargetGraph.Create(writeToLockFile, runtimeGraph, graphs, context, _logger, framework, runtimeIdentifier);

            // Check if the dependencies got bumped up
            // ...but not if there is an existing locked lock file.
            if (_request.ExistingLockFile == null || !_request.ExistingLockFile.IsLocked)
            {
                // No lock file, OR the lock file is unlocked, so check dependencies
                CheckDependencies(result, _request.Project.Dependencies);

                var fxInfo = _request.Project.GetTargetFramework(framework);
                if (fxInfo != null)
                {
                    CheckDependencies(result, fxInfo.Dependencies);
                }
            }

            return(result);
        }
 private Task <GraphNode <RemoteResolveResult> > DoWalkAsync(RemoteDependencyWalker walker, string name)
 {
     return(DoWalkAsync(walker, name, NuGetFramework.Parse("net45")));
 }
Exemple #29
0
        private async Task <RestoreTargetGraph> WalkDependencies(LibraryRange projectRange, NuGetFramework framework, string runtimeIdentifier, RuntimeGraph runtimeGraph, RemoteDependencyWalker walker, RemoteWalkContext context)
        {
            _log.LogInformation($"Restoring packages for {framework}");
            var graph = await walker.Walk(
                projectRange,
                framework,
                runtimeIdentifier,
                runtimeGraph);

            // Resolve conflicts
            _log.LogVerbose($"Resolving Conflicts for {framework}");
            bool inConflict = !graph.TryResolveConflicts();

            // Flatten and create the RestoreTargetGraph to hold the packages
            return(RestoreTargetGraph.Create(inConflict, framework, runtimeIdentifier, runtimeGraph, graph, context, _loggerFactory));
        }
Exemple #30
0
        private async Task <IEnumerable <RestoreTargetGraph> > ExecuteRestoreAsync(
            NuGetv3LocalRepository userPackageFolder,
            IReadOnlyList <NuGetv3LocalRepository> fallbackPackageFolders,
            RemoteWalkContext context,
            CancellationToken token)
        {
            if (_request.Project.TargetFrameworks.Count == 0)
            {
                var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectDoesNotSpecifyTargetFrameworks, _request.Project.Name, _request.Project.FilePath);
                await _logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1001, message));

                _success = false;
                return(Enumerable.Empty <RestoreTargetGraph>());
            }

            _logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, _request.Project.FilePath));

            // Get external project references
            // If the top level project already exists, update the package spec provided
            // with the RestoreRequest spec.
            var updatedExternalProjects = GetProjectReferences(context);

            // Determine if the targets and props files should be written out.
            context.IsMsBuildBased = _request.ProjectStyle != ProjectStyle.DotnetCliTool;

            // Load repositories
            // the external project provider is specific to the current restore project
            context.ProjectLibraryProviders.Add(
                new PackageSpecReferenceDependencyProvider(updatedExternalProjects, _logger));

            var remoteWalker = new RemoteDependencyWalker(context);

            var projectRange = new LibraryRange()
            {
                Name           = _request.Project.Name,
                VersionRange   = new VersionRange(_request.Project.Version),
                TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject
            };

            // Resolve dependency graphs
            var allInstalledPackages         = new HashSet <LibraryIdentity>();
            var allGraphs                    = new List <RestoreTargetGraph>();
            var runtimeIds                   = RequestRuntimeUtility.GetRestoreRuntimes(_request);
            var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(_request.Project, runtimeIds);
            var hasSupports                  = _request.Project.RuntimeGraph.Supports.Count > 0;

            var projectRestoreRequest = new ProjectRestoreRequest(
                _request,
                _request.Project,
                _request.ExistingLockFile,
                _runtimeGraphCache,
                _runtimeGraphCacheByPackage,
                _logger);

            var projectRestoreCommand = new ProjectRestoreCommand(projectRestoreRequest);

            var result = await projectRestoreCommand.TryRestore(
                projectRange,
                projectFrameworkRuntimePairs,
                allInstalledPackages,
                userPackageFolder,
                fallbackPackageFolders,
                remoteWalker,
                context,
                forceRuntimeGraphCreation : hasSupports,
                token : token);

            var success = result.Item1;

            allGraphs.AddRange(result.Item2);

            _success = success;

            // Calculate compatibility profiles to check by merging those defined in the project with any from the command line
            foreach (var profile in _request.Project.RuntimeGraph.Supports)
            {
                var runtimes = result.Item3;

                CompatibilityProfile compatProfile;
                if (profile.Value.RestoreContexts.Any())
                {
                    // Just use the contexts from the project definition
                    compatProfile = profile.Value;
                }
                else if (!runtimes.Supports.TryGetValue(profile.Value.Name, out compatProfile))
                {
                    // No definition of this profile found, so just continue to the next one
                    var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_UnknownCompatibilityProfile, profile.Key);

                    await _logger.LogAsync(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1502, message));

                    continue;
                }

                foreach (var pair in compatProfile.RestoreContexts)
                {
                    _logger.LogDebug($" {profile.Value.Name} -> +{pair}");
                    _request.CompatibilityProfiles.Add(pair);
                }
            }

            // Walk additional runtime graphs for supports checks
            if (_success && _request.CompatibilityProfiles.Any())
            {
                var compatibilityResult = await projectRestoreCommand.TryRestore(
                    projectRange,
                    _request.CompatibilityProfiles,
                    allInstalledPackages,
                    userPackageFolder,
                    fallbackPackageFolders,
                    remoteWalker,
                    context,
                    forceRuntimeGraphCreation : true,
                    token : token);

                _success = compatibilityResult.Item1;

                // TryRestore may contain graphs that are already in allGraphs if the
                // supports section contains the same TxM as the project framework.
                var currentGraphs = new HashSet <KeyValuePair <NuGetFramework, string> >(
                    allGraphs.Select(graph => new KeyValuePair <NuGetFramework, string>(
                                         graph.Framework,
                                         graph.RuntimeIdentifier))
                    );

                foreach (var graph in compatibilityResult.Item2)
                {
                    var key = new KeyValuePair <NuGetFramework, string>(
                        graph.Framework,
                        graph.RuntimeIdentifier);

                    if (currentGraphs.Add(key))
                    {
                        allGraphs.Add(graph);
                    }
                }
            }


            return(allGraphs);
        }
        public async Task WalkAsyncAddsTransitiveCentralDependency(string centralPackageVersion, string otherVersion)
        {
            var centralPackageName = "D";
            var framework          = NuGetFramework.Parse("net45");

            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            // D is a transitive dependency for package A through package B -> C -> D
            // D is defined as a Central Package Version
            // In this context Package D with version centralPackageVersion will be added as inner node of Node A, next to B

            // Input
            // A -> B (version = otherVersion) -> C (version = otherVersion) -> D (version = otherVersion)
            // A ~> D (the version 2.0.0 or as defined by "centralPackageVersion" argument
            //         the dependency is not direct,
            //         it simulates the fact that there is a centrally defined "D" package
            //         the information is added to the provider)

            // The expected output graph
            //    -> B (version = otherVersion) -> C (version = otherVersion)
            // A
            //    -> D (version = 2.0.0)

            provider.Package("A", otherVersion)
            .DependsOn("B", otherVersion);

            provider.Package("B", otherVersion)
            .DependsOn("C", otherVersion);

            provider.Package("C", otherVersion)
            .DependsOn(centralPackageName, otherVersion);

            // Simulates the existence of a D centrally defined package that is not direct dependency
            provider.Package("A", otherVersion)
            .DependsOn(centralPackageName, centralPackageVersion, LibraryDependencyTarget.Package, versionCentrallyManaged: true, libraryDependencyReferenceType: LibraryDependencyReferenceType.None);

            // Add central package to the source with multiple versions
            provider.Package(centralPackageName, "1.0.0");
            provider.Package(centralPackageName, centralPackageVersion);
            provider.Package(centralPackageName, "3.0.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);

            // Act
            var rootNode = await DoWalkAsync(walker, "A", framework);

            // Assert
            Assert.Equal(2, rootNode.InnerNodes.Count);
            var centralVersionInGraphNode = rootNode.InnerNodes.Where(n => n.Item.Key.Name == centralPackageName).FirstOrDefault();

            Assert.NotNull(centralVersionInGraphNode);
            Assert.Equal(centralPackageVersion, centralVersionInGraphNode.Item.Key.Version.ToNormalizedString());
            Assert.True(centralVersionInGraphNode.Item.IsCentralTransitive);

            var BNode = rootNode.InnerNodes.Where(n => n.Item.Key.Name == "B").FirstOrDefault();

            Assert.NotNull(BNode);
            Assert.Equal(1, BNode.InnerNodes.Count);
            Assert.Equal(otherVersion, BNode.Item.Key.Version.ToNormalizedString());
            Assert.False(BNode.Item.IsCentralTransitive);

            var CNode = BNode.InnerNodes.Where(n => n.Item.Key.Name == "C").FirstOrDefault();

            Assert.NotNull(CNode);
            Assert.Equal(otherVersion, CNode.Item.Key.Version.ToNormalizedString());
            Assert.Equal(0, CNode.InnerNodes.Count);
            Assert.False(CNode.Item.IsCentralTransitive);
        }