/// <summary> /// Runs GenerateRuntimeGraph task specifying AdditionalRuntimeIdentifiers then asserts that the /// generated runtime.json has the expected additions (and no more). /// </summary> /// <param name="additionalRIDs">additional RIDs</param> /// <param name="expectedAdditions">entries that are expected to be added to the RuntimeGraph</param> /// <param name="additionalRIDParent">parent to use when adding a new RID</param> /// <param name="runtimeFilePrefix">a unique prefix to use for the generated </param> private void AssertRuntimeGraphAdditions(string[] additionalRIDs, RuntimeDescription[] expectedAdditions, string additionalRIDParent = null, [CallerMemberName] string runtimeFilePrefix = null) { string runtimeFile = Path.Combine(defaultRootPath, runtimeFilePrefix + ".runtime.json"); GenerateRuntimeGraph task = new GenerateRuntimeGraph() { BuildEngine = _engine, RuntimeGroups = DefaultRuntimeGroupItems, RuntimeJson = runtimeFile, AdditionalRuntimeIdentifiers = additionalRIDs, AdditionalRuntimeIdentifierParent = additionalRIDParent, UpdateRuntimeFiles = true }; _log.Reset(); task.Execute(); _log.AssertNoErrorsOrWarnings(); RuntimeGraph expected = RuntimeGraph.Merge( JsonRuntimeFormat.ReadRuntimeGraph(defaultRuntimeFile), new RuntimeGraph(expectedAdditions)); RuntimeGraph actual = JsonRuntimeFormat.ReadRuntimeGraph(runtimeFile); // Should this assert fail, it's helpful to diff defaultRuntimeFile and runtimeFile to see the additions. Assert.Equal(expected, actual); }
public void MergingCombinesDependencySetsInRuntimesDefinedInBoth() { var leftGraph = new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any", "win7" }, new[] { new RuntimeDependencySet("Foo"), }) }); var rightGraph = new RuntimeGraph(new[] { new RuntimeDescription("win8", new[] { new RuntimeDependencySet("Bar") }) }); var graph = RuntimeGraph.Merge(leftGraph, rightGraph); Assert.Equal(new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any", "win7" }, new[] { new RuntimeDependencySet("Foo"), new RuntimeDependencySet("Bar") }), }), graph); }
public void MergingCombinesDependenciesInDependencySetsDefinedInBoth() { var leftGraph = new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any", "win7" }, new [] { new RuntimeDependencySet("Foo", new [] { new RuntimePackageDependency("Foo.win8", new VersionRange(new NuGetVersion(1, 2, 3))) }), }) }); var rightGraph = new RuntimeGraph(new[] { new RuntimeDescription("win8", new[] { new RuntimeDependencySet("Foo", new [] { new RuntimePackageDependency("Foo.more.win8", new VersionRange(new NuGetVersion(4, 5, 6))) }), }) }); var graph = RuntimeGraph.Merge(leftGraph, rightGraph); Assert.Equal(new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any", "win7" }, new [] { new RuntimeDependencySet("Foo", new [] { new RuntimePackageDependency("Foo.win8", new VersionRange(new NuGetVersion(1, 2, 3))), new RuntimePackageDependency("Foo.more.win8", new VersionRange(new NuGetVersion(4, 5, 6))) }), }), }), leftGraph); }
/// <summary> /// Merge all runtime.json found in the flattened graph. /// </summary> private RuntimeGraph GetRuntimeGraph(RestoreTargetGraph graph, IReadOnlyList <NuGetv3LocalRepository> localRepositories, RuntimeGraph projectRuntimeGraph) { _logger.LogVerbose(Strings.Log_ScanningForRuntimeJson); var runtimeGraph = projectRuntimeGraph ?? RuntimeGraph.Empty; // Find runtime.json files using the flattened graph which is unique per id. // Using the flattened graph ensures that only accepted packages will be used. foreach (var node in graph.Flattened) { var match = node.Data?.Match; if (match == null || match.Library.Type != LibraryType.Package) { // runtime.json can only exist in packages continue; } // Locate the package in the local repository var info = NuGetv3LocalRepositoryUtility.GetPackage(localRepositories, match.Library.Name, match.Library.Version); // Unresolved packages may not exist. if (info != null) { var nextGraph = info.Package.RuntimeGraph; if (nextGraph != null) { _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_MergingRuntimes, match.Library)); runtimeGraph = RuntimeGraph.Merge(runtimeGraph, nextGraph); } } } return(runtimeGraph); }
private RuntimeGraph GetRuntimeGraph(RestoreTargetGraph graph, IReadOnlyList <NuGetv3LocalRepository> localRepositories) { // TODO: Caching! RuntimeGraph runtimeGraph; if (_request.RuntimeGraphCache.TryGetValue(graph.Framework, out runtimeGraph)) { return(runtimeGraph); } _logger.LogVerbose(Strings.Log_ScanningForRuntimeJson); runtimeGraph = RuntimeGraph.Empty; // maintain visited nodes to avoid duplicate runtime graph for the same node var visitedNodes = new HashSet <string>(StringComparer.OrdinalIgnoreCase); graph.Graphs.ForEach(node => { var match = node?.Item?.Data?.Match; if (match == null) { return; } // Ignore runtime.json from rejected nodes if (node.Disposition == Disposition.Rejected) { return; } // ignore the same node again if (!visitedNodes.Add(match.Library.Name)) { return; } // runtime.json can only exist in packages if (match.Library.Type != LibraryType.Package) { return; } // Locate the package in the local repository var info = NuGetv3LocalRepositoryUtility.GetPackage(localRepositories, match.Library.Name, match.Library.Version); if (info != null) { var package = info.Package; var nextGraph = LoadRuntimeGraph(package); if (nextGraph != null) { _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_MergingRuntimes, match.Library)); runtimeGraph = RuntimeGraph.Merge(runtimeGraph, nextGraph); } } }); _request.RuntimeGraphCache[graph.Framework] = runtimeGraph; return(runtimeGraph); }
public void MergingInEmptyGraphHasNoEffect() { var graph = new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any" }) }); var newGraph = RuntimeGraph.Merge(graph, RuntimeGraph.Empty); Assert.Equal(new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any" }) }), newGraph); }
public void MergeReplacesCompatibilityProfilesDefinedInRightIntoLeftIfLeftIsEmpty() { var leftGraph = new RuntimeGraph(new[] { new CompatibilityProfile("frob") }); var rightGraph = new RuntimeGraph(new[] { new CompatibilityProfile("frob", new [] { new FrameworkRuntimePair(FrameworkConstants.CommonFrameworks.DnxCore50, "blob") }) }); var graph = RuntimeGraph.Merge(leftGraph, rightGraph); Assert.Equal(rightGraph, graph); }
public void MergingAddsCompletelyNewRuntimes() { var leftGraph = new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any", "win7" }) }); var rightGraph = new RuntimeGraph(new[] { new RuntimeDescription("win7") }); var graph = RuntimeGraph.Merge(leftGraph, rightGraph); Assert.Equal(new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any", "win7" }), new RuntimeDescription("win7") }), graph); }
public static RuntimeGraph Collect(IEnumerable <LibraryDescription> libraries) { var graph = RuntimeGraph.Empty; foreach (var library in libraries) { if (library.Identity.Type == LibraryType.Package) { var runtimeJson = ((PackageDescription)library).PackageLibrary.Files.FirstOrDefault(f => f == RuntimeJsonFileName); if (runtimeJson != null) { var runtimeJsonFullName = Path.Combine(library.Path, runtimeJson); graph = RuntimeGraph.Merge(graph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonFullName)); } } } return(graph); }
public NuGet.RuntimeModel.RuntimeGraph Collect(IEnumerable <LibraryExport> exports) { var graph = RuntimeGraph.Empty; foreach (var export in exports) { if (export.Library.Identity.Type == LibraryType.Package) { var runtimeJson = ((PackageDescription)export.Library).PackageLibrary.Files.FirstOrDefault(f => f == RuntimeJsonFileName); if (runtimeJson != null) { var runtimeJsonFullName = Path.Combine(export.Library.Path, runtimeJson); graph = RuntimeGraph.Merge(graph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonFullName)); } } } return(graph); }
private RuntimeGraph GetRuntimeGraph(RestoreTargetGraph graph, IReadOnlyList <NuGetv3LocalRepository> localRepositories) { // TODO: Caching! RuntimeGraph runtimeGraph; if (_request.RuntimeGraphCache.TryGetValue(graph.Framework, out runtimeGraph)) { return(runtimeGraph); } _logger.LogVerbose(Strings.Log_ScanningForRuntimeJson); runtimeGraph = RuntimeGraph.Empty; graph.Graphs.ForEach(node => { var match = node?.Item?.Data?.Match; if (match == null) { return; } // Ignore runtime.json from rejected nodes if (node.Disposition == Disposition.Rejected) { return; } // Locate the package in the local repository var info = NuGetv3LocalRepositoryUtility.GetPackage(localRepositories, match.Library.Name, match.Library.Version); if (info != null) { var package = info.Package; var nextGraph = LoadRuntimeGraph(package); if (nextGraph != null) { _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_MergingRuntimes, match.Library)); runtimeGraph = RuntimeGraph.Merge(runtimeGraph, nextGraph); } } }); _request.RuntimeGraphCache[graph.Framework] = runtimeGraph; return(runtimeGraph); }
private static IEnumerable <RuntimeFallbacks> GetRuntimeFallbacks(string[] runtimeGraphFiles, string runtime) { RuntimeGraph runtimeGraph = RuntimeGraph.Empty; foreach (string runtimeGraphFile in runtimeGraphFiles) { runtimeGraph = RuntimeGraph.Merge(runtimeGraph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeGraphFile)); } foreach (string rid in runtimeGraph.Runtimes.Select(p => p.Key)) { IEnumerable <string> ridFallback = runtimeGraph.ExpandRuntime(rid); if (ridFallback.Contains(runtime)) { // ExpandRuntime return runtime itself as first item so we are skiping it yield return(new RuntimeFallbacks(rid, ridFallback.Skip(1))); } } }
public void AreCompatible_VerifyCaseSensitiveCheck() { var leftGraph = new RuntimeGraph(new[] { new RuntimeDescription("win7"), new RuntimeDescription("win8", new[] { "win7" }) }); var rightGraph = new RuntimeGraph(new[] { new RuntimeDescription("WIN7"), new RuntimeDescription("WIN8", new[] { "WIN7" }) }); // Merge var graph = RuntimeGraph.Merge(leftGraph, rightGraph); graph.AreCompatible("WIN8", "win7").Should().BeFalse(); graph.AreCompatible("win8", "WIN7").Should().BeFalse(); }
private RuntimeGraph SafeMerge(RuntimeGraph existingGraph, RuntimeGroup runtimeGroup) { var runtimeGraph = runtimeGroup.GetRuntimeGraph(); foreach (var existingRuntimeDescription in existingGraph.Runtimes.Values) { RuntimeDescription newRuntimeDescription; if (runtimeGraph.Runtimes.TryGetValue(existingRuntimeDescription.RuntimeIdentifier, out newRuntimeDescription)) { // overlapping RID, ensure that the imports match (same ordering and content) if (!existingRuntimeDescription.InheritedRuntimes.SequenceEqual(newRuntimeDescription.InheritedRuntimes)) { Log.LogError($"RuntimeGroup {runtimeGroup.BaseRID} defines RID {newRuntimeDescription.RuntimeIdentifier} with imports {String.Join(";", newRuntimeDescription.InheritedRuntimes)} which differ from existing imports {String.Join(";", existingRuntimeDescription.InheritedRuntimes)}. You may avoid this by specifying {nameof(RuntimeGroup.OmitRIDDefinitions)} metadata with {newRuntimeDescription.RuntimeIdentifier}."); } } } return(RuntimeGraph.Merge(existingGraph, runtimeGraph)); }
public void GivenDifferentCasingsVerifyMergeKeepsBoth() { var leftGraph = new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("win8", new[] { "any" }) }); var rightGraph = new RuntimeGraph(new[] { new RuntimeDescription("any"), new RuntimeDescription("WIN8", new[] { "any" }) }); // Merge var graph = RuntimeGraph.Merge(leftGraph, rightGraph); graph.Runtimes.Keys.Should().BeEquivalentTo(new List <string>() { "any", "win8", "WIN8" }); }
public RuntimeGraph Collect(LockFile lockFile) { string userPackageFolder = lockFile.PackageFolders.FirstOrDefault()?.Path; var fallBackFolders = lockFile.PackageFolders.Skip(1).Select(f => f.Path); var packageResolver = new FallbackPackagePathResolver(userPackageFolder, fallBackFolders); var graph = RuntimeGraph.Empty; foreach (var library in lockFile.Libraries) { if (string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase)) { var runtimeJson = library.Files.FirstOrDefault(f => f == RuntimeJsonFileName); if (runtimeJson != null) { var libraryPath = packageResolver.GetPackageDirectory(library.Name, library.Version); var runtimeJsonFullName = Path.Combine(libraryPath, runtimeJson); graph = RuntimeGraph.Merge(graph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonFullName)); } } } return(graph); }
public NuGet.RuntimeModel.RuntimeGraph Collect(IEnumerable <LibraryExport> exports) { var graph = RuntimeGraph.Empty; foreach (var export in exports) { if (export.Library.Identity.Type == LibraryType.Package) { PackageDescription description = (PackageDescription)export.Library; var runtimeJson = description.PackageLibrary.Files.FirstOrDefault(f => f == RuntimeJsonFileName); if (runtimeJson != null) { // Convert the package-name to lower-case in the path to lookup runtime.json string lowercasedPackageName = description.Identity.Name.ToLower(); string pathToPackage = export.Library.Path.Replace(description.Identity.Name, lowercasedPackageName); var runtimeJsonFullName = Path.Combine(pathToPackage, runtimeJson); graph = RuntimeGraph.Merge(graph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonFullName)); } } } return(graph); }
private Task <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 <Task <RestoreTargetGraph> >(); foreach (var runtimeName in projectRuntimeGraph.Runtimes.Keys) { _log.LogInformation($"Restoring packages for {graph.Framework} on {runtimeName}"); resultGraphs.Add(WalkDependencies(projectRange, graph.Framework, runtimeName, runtimeGraph, walker, context)); } return(Task.WhenAll(resultGraphs)); }
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)); }
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)); }
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)); }
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 override bool Execute() { if (Dependencies == null || Dependencies.Length == 0) { Log.LogError("Dependencies argument must be specified"); return(false); } if (String.IsNullOrEmpty(PackageId)) { Log.LogError("PackageID argument must be specified"); return(false); } if (RuntimeJson == null) { Log.LogError("RuntimeJson argument must be specified"); return(false); } string sourceRuntimeFilePath = null; if (RuntimeJsonTemplate != null) { sourceRuntimeFilePath = RuntimeJsonTemplate.GetMetadata("FullPath"); } string destRuntimeFilePath = RuntimeJson.GetMetadata("FullPath"); Dictionary <string, string> packageAliases = new Dictionary <string, string>(); foreach (var dependency in Dependencies) { string alias = dependency.GetMetadata("PackageAlias"); if (String.IsNullOrEmpty(alias)) { continue; } Log.LogMessage(LogImportance.Low, "Aliasing {0} -> {1}", alias, dependency.ItemSpec); packageAliases[alias] = dependency.ItemSpec; } var runtimeGroups = Dependencies.GroupBy(d => d.GetMetadata("TargetRuntime")); List <RuntimeDescription> runtimes = new List <RuntimeDescription>(); foreach (var runtimeGroup in runtimeGroups) { string targetRuntimeId = runtimeGroup.Key; if (String.IsNullOrEmpty(targetRuntimeId)) { Log.LogMessage(LogImportance.Low, "Skipping dependencies {0} since they don't have a TargetRuntime.", String.Join(", ", runtimeGroup.Select(d => d.ItemSpec))); continue; } if (runtimeGroup.Any(d => d.ItemSpec == c_emptyDependency)) { runtimes.Add(new RuntimeDescription(targetRuntimeId)); continue; } List <RuntimeDependencySet> runtimeDependencySets = new List <RuntimeDependencySet>(); var targetPackageGroups = runtimeGroup.GroupBy(d => GetTargetPackageId(d, packageAliases)); foreach (var targetPackageGroup in targetPackageGroups) { string targetPackageId = targetPackageGroup.Key; List <RuntimePackageDependency> runtimePackageDependencies = new List <RuntimePackageDependency>(); var dependencyGroups = targetPackageGroup.GroupBy(d => d.ItemSpec); foreach (var dependencyGroup in dependencyGroups) { string dependencyId = dependencyGroup.Key; var dependencyVersions = dependencyGroup.Select(d => GetDependencyVersion(d)); var maxDependencyVersion = dependencyVersions.Max(); runtimePackageDependencies.Add(new RuntimePackageDependency(dependencyId, new VersionRange(maxDependencyVersion))); } runtimeDependencySets.Add(new RuntimeDependencySet(targetPackageId, runtimePackageDependencies)); } runtimes.Add(new RuntimeDescription(targetRuntimeId, runtimeDependencySets)); } RuntimeGraph runtimeGraph = new RuntimeGraph(runtimes); // read in existing JSON, if it was provided so that we preserve any // hand authored #imports or dependencies if (!String.IsNullOrEmpty(sourceRuntimeFilePath)) { RuntimeGraph existingGraph = JsonRuntimeFormat.ReadRuntimeGraph(sourceRuntimeFilePath); runtimeGraph = RuntimeGraph.Merge(existingGraph, runtimeGraph); } string destRuntimeFileDir = Path.GetDirectoryName(destRuntimeFilePath); if (!String.IsNullOrEmpty(destRuntimeFileDir) && !Directory.Exists(destRuntimeFileDir)) { Directory.CreateDirectory(destRuntimeFileDir); } JsonRuntimeFormat.WriteRuntimeGraph(destRuntimeFilePath, runtimeGraph); return(true); }