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)); }
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)); }