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));
        }
Ejemplo n.º 2
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));
        }