private Task <GraphItem <RemoteResolveResult> > FindLibraryCached( ConcurrentDictionary <LibraryRangeCacheKey, Task <GraphItem <RemoteResolveResult> > > cache, LibraryRange libraryRange, NuGetFramework framework, GraphEdge <RemoteResolveResult> outerEdge, CancellationToken cancellationToken) { var key = new LibraryRangeCacheKey(libraryRange, framework); return(cache.GetOrAdd(key, (cacheKey) => FindLibraryEntry(cacheKey.LibraryRange, framework, outerEdge, cancellationToken))); }
public static Task <GraphItem <RemoteResolveResult> > FindLibraryCachedAsync( ConcurrentDictionary <LibraryRangeCacheKey, Task <GraphItem <RemoteResolveResult> > > cache, LibraryRange libraryRange, NuGetFramework framework, string runtimeIdentifier, RemoteWalkContext context, CancellationToken cancellationToken) { var key = new LibraryRangeCacheKey(libraryRange, framework); return(cache.GetOrAdd(key, (cacheKey) => FindLibraryEntryAsync(cacheKey.LibraryRange, framework, runtimeIdentifier, context, cancellationToken))); }
private async Task <GraphNode <RemoteResolveResult> > CreateGraphNode( LibraryRange libraryRange, NuGetFramework framework, string runtimeName, RuntimeGraph runtimeGraph, Func <LibraryRange, DependencyResult> predicate, GraphEdge <RemoteResolveResult> outerEdge) { var dependencies = new List <LibraryDependency>(); var runtimeDependencies = new HashSet <string>(); if (!string.IsNullOrEmpty(runtimeName) && runtimeGraph != null) { // HACK(davidfowl): This is making runtime.json support package redirects // Look up any additional dependencies for this package foreach (var runtimeDependency in runtimeGraph.FindRuntimeDependencies(runtimeName, libraryRange.Name)) { var libraryDependency = new LibraryDependency { LibraryRange = new LibraryRange() { Name = runtimeDependency.Id, VersionRange = runtimeDependency.VersionRange, TypeConstraint = LibraryDependencyTarget.PackageProjectExternal } }; if (StringComparer.OrdinalIgnoreCase.Equals(runtimeDependency.Id, libraryRange.Name)) { if (libraryRange.VersionRange != null && runtimeDependency.VersionRange != null && libraryRange.VersionRange.MinVersion < runtimeDependency.VersionRange.MinVersion) { libraryRange = libraryDependency.LibraryRange; } } else { // Otherwise it's a dependency of this node dependencies.Add(libraryDependency); runtimeDependencies.Add(libraryDependency.Name); } } } var node = new GraphNode <RemoteResolveResult>(libraryRange) { // Resolve the dependency from the cache or sources Item = await FindLibraryCached( _context.FindLibraryEntryCache, libraryRange, framework, outerEdge, CancellationToken.None) }; Debug.Assert(node.Item != null, "FindLibraryCached should return an unresolved item instead of null"); if (node.Key.VersionRange != null && node.Key.VersionRange.IsFloating) { var cacheKey = new LibraryRangeCacheKey(node.Key, framework); _context.FindLibraryEntryCache.TryAdd(cacheKey, Task.FromResult(node.Item)); } var tasks = new List <Task <GraphNode <RemoteResolveResult> > >(); if (dependencies.Count > 0) { // Create a new item on this node so that we can update it with the new dependencies from // runtime.json files // We need to clone the item since they can be shared across multiple nodes node.Item = new GraphItem <RemoteResolveResult>(node.Item.Key) { Data = new RemoteResolveResult() { Dependencies = dependencies.Concat(node.Item.Data.Dependencies.Where(d => !runtimeDependencies.Contains(d.Name))).ToList(), Match = node.Item.Data.Match } }; } foreach (var dependency in node.Item.Data.Dependencies) { // Skip dependencies if the dependency edge has 'all' excluded and // the node is not a direct dependency. if (outerEdge == null || dependency.SuppressParent != LibraryIncludeFlags.All) { var result = predicate(dependency.LibraryRange); if (result == DependencyResult.Acceptable) { // Dependency edge from the current node to the dependency var innerEdge = new GraphEdge <RemoteResolveResult>(outerEdge, node.Item, dependency); tasks.Add(CreateGraphNode( dependency.LibraryRange, framework, runtimeName, runtimeGraph, ChainPredicate(predicate, node, dependency), innerEdge)); } else { // Keep the node in the tree if we need to look at it later if (result == DependencyResult.PotentiallyDowngraded || result == DependencyResult.Cycle) { var dependencyNode = new GraphNode <RemoteResolveResult>(dependency.LibraryRange) { Disposition = result == DependencyResult.Cycle ? Disposition.Cycle : Disposition.PotentiallyDowngraded }; dependencyNode.OuterNode = node; node.InnerNodes.Add(dependencyNode); } } } } while (tasks.Any()) { // Wait for any node to finish resolving var task = await Task.WhenAny(tasks); // Extract the resolved node tasks.Remove(task); var dependencyNode = await task; dependencyNode.OuterNode = node; node.InnerNodes.Add(dependencyNode); } return(node); }