public void FindRuntimeDependencies_VerifyCaching() { var graph = new RuntimeGraph(new[] { new RuntimeDescription("a", new[] { new RuntimeDependencySet("x", new[] { new RuntimePackageDependency("y", VersionRange.Parse("1.0.0")) }) }), new RuntimeDescription("b", new[] { "a" }), new RuntimeDescription("c", new[] { "b" }), new RuntimeDescription("d", new[] { "c" }), }); var dependenciesA = graph.FindRuntimeDependencies("d", "x"); var dependenciesB = graph.FindRuntimeDependencies("d", "x"); ReferenceEquals(dependenciesA, dependenciesB).Should().BeTrue(); }
public void FindRuntimeDependencies_VerifyPackageIdIsCaseInsensitive() { var graph = new RuntimeGraph(new[] { new RuntimeDescription("a", new[] { new RuntimeDependencySet("x", new[] { new RuntimePackageDependency("y", VersionRange.Parse("1.0.0")) }) }) }); var dependencies = graph.FindRuntimeDependencies("a", "X").ToList(); dependencies.Count.Should().Be(1); dependencies[0].Id.Should().Be("y"); dependencies[0].VersionRange.ToShortString().Should().Be("1.0.0"); }
public void FindRuntimeDependencies_VerifyDependencyOnCompatibleRID() { var graph = new RuntimeGraph(new[] { new RuntimeDescription("a", new[] { new RuntimeDependencySet("x", new[] { new RuntimePackageDependency("y", VersionRange.Parse("1.0.0")) }) }), new RuntimeDescription("b", new[] { "a" }), new RuntimeDescription("c", new[] { "b" }), new RuntimeDescription("d", new[] { "c" }), }); var dependencies = graph.FindRuntimeDependencies("d", "x").ToList(); dependencies.Count.Should().Be(1); dependencies[0].Id.Should().Be("y"); dependencies[0].VersionRange.ToShortString().Should().Be("1.0.0"); }
public void FindRuntimeDependencies_MultipleDependenciesWithTieVerifyResult() { // A -> B and A -> C where both have dependencies var graph = new RuntimeGraph(new[] { new RuntimeDescription("a", new[] { new RuntimeDependencySet("x", new[] { new RuntimePackageDependency("y", VersionRange.Parse("1.0.0")) }) }), new RuntimeDescription("b", new[] { new RuntimeDependencySet("x", new[] { new RuntimePackageDependency("z", VersionRange.Parse("1.0.0")) }) }), new RuntimeDescription("c", new[] { "a", "b" }), }); var dependencies = graph.FindRuntimeDependencies("c", "x").ToList(); dependencies.Count.Should().Be(1); dependencies[0].Id.Should().Be("y"); dependencies[0].VersionRange.ToShortString().Should().Be("1.0.0"); }
public void FindRuntimeDependencies_MultipleDependenciesWithTieInTreeVerifyResult2() { // C // - B // --- A // ----- AA -> Y 1.0.0 // - F // --- E -> Z 1.0.0 var graph = new RuntimeGraph(new[] { new RuntimeDescription("aa", new[] { new RuntimeDependencySet("x", new[] { new RuntimePackageDependency("y", VersionRange.Parse("1.0.0")) }) }), new RuntimeDescription("e", new[] { new RuntimeDependencySet("x", new[] { new RuntimePackageDependency("z", VersionRange.Parse("1.0.0")) }) }), new RuntimeDescription("a", new[] { "aa" }), new RuntimeDescription("b", new[] { "a" }), new RuntimeDescription("f", new[] { "e" }), new RuntimeDescription("c", new[] { "b", "f" }), }); var dependencies = graph.FindRuntimeDependencies("c", "x").ToList(); dependencies.Count.Should().Be(1); dependencies[0].Id.Should().Be("z"); dependencies[0].VersionRange.ToShortString().Should().Be("1.0.0"); }
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); }
private async Task <GraphNode <RemoteResolveResult> > CreateGraphNode(Dictionary <LibraryRange, Task <GraphItem <RemoteResolveResult> > > cache, LibraryRange libraryRange, NuGetFramework framework, string runtimeName, RuntimeGraph runtimeGraph, Func <string, bool> predicate) { var node = new GraphNode <RemoteResolveResult>(libraryRange) { Item = await FindLibraryCached(cache, libraryRange, framework), }; if (node.Item == null) { // Reject null items node.Disposition = Disposition.Rejected; } else { if (node.Key.VersionRange != null && node.Key.VersionRange.IsFloating) { lock (cache) { if (!cache.ContainsKey(node.Key)) { cache[node.Key] = Task.FromResult(node.Item); } } } var tasks = new List <Task <GraphNode <RemoteResolveResult> > >(); var dependencies = node.Item.Data.Dependencies ?? Enumerable.Empty <LibraryDependency>(); foreach (var dependency in dependencies) { if (predicate(dependency.Name)) { tasks.Add(CreateGraphNode(cache, dependency.LibraryRange, framework, runtimeName, runtimeGraph, ChainPredicate(predicate, node.Item, dependency))); if (!string.IsNullOrEmpty(runtimeName) && runtimeGraph != null) { // Look up any additional dependencies for this package foreach (var runtimeDependency in runtimeGraph.FindRuntimeDependencies(runtimeName, dependency.Name)) { // Add the dependency to the tasks var runtimeLibraryRange = new LibraryRange() { Name = runtimeDependency.Id, VersionRange = runtimeDependency.VersionRange }; tasks.Add(CreateGraphNode( cache, runtimeLibraryRange, framework, runtimeName, runtimeGraph, ChainPredicate(predicate, node.Item, dependency))); } } } } while (tasks.Any()) { var task = await Task.WhenAny(tasks); tasks.Remove(task); var dependencyNode = await task; // Not required for anything dependencyNode.OuterNode = node; node.InnerNodes.Add(dependencyNode); } } return(node); }
private async Task<GraphNode<RemoteResolveResult>> CreateGraphNode(Dictionary<LibraryRange, Task<GraphItem<RemoteResolveResult>>> cache, LibraryRange libraryRange, NuGetFramework framework, string runtimeName, RuntimeGraph runtimeGraph, Func<string, bool> predicate) { var node = new GraphNode<RemoteResolveResult>(libraryRange) { Item = await FindLibraryCached(cache, libraryRange, framework), }; if (node.Item == null) { // Reject null items node.Disposition = Disposition.Rejected; } else { if (node.Key.VersionRange != null && node.Key.VersionRange.IsFloating) { lock (cache) { if (!cache.ContainsKey(node.Key)) { cache[node.Key] = Task.FromResult(node.Item); } } } var tasks = new List<Task<GraphNode<RemoteResolveResult>>>(); var dependencies = node.Item.Data.Dependencies ?? Enumerable.Empty<LibraryDependency>(); foreach (var dependency in dependencies) { if (predicate(dependency.Name)) { tasks.Add(CreateGraphNode(cache, dependency.LibraryRange, framework, runtimeName, runtimeGraph, ChainPredicate(predicate, node.Item, dependency))); if (!string.IsNullOrEmpty(runtimeName) && runtimeGraph != null) { // Look up any additional dependencies for this package foreach (var runtimeDependency in runtimeGraph.FindRuntimeDependencies(runtimeName, dependency.Name)) { // Add the dependency to the tasks var runtimeLibraryRange = new LibraryRange() { Name = runtimeDependency.Id, VersionRange = runtimeDependency.VersionRange }; tasks.Add(CreateGraphNode( cache, runtimeLibraryRange, framework, runtimeName, runtimeGraph, ChainPredicate(predicate, node.Item, dependency))); } } } } while (tasks.Any()) { var task = await Task.WhenAny(tasks); tasks.Remove(task); var dependencyNode = await task; // Not required for anything dependencyNode.OuterNode = node; node.InnerNodes.Add(dependencyNode); } } return node; }