private async Task <RestoreTargetGraph> GenerateRestoreGraph(ILogger log, string projectName, string projectPath) { var dgFile = await VSProjectHelper.GenerateRestoreGraphFile(log, projectPath); var dgProvider = new DependencyGraphSpecRequestProvider(new RestoreCommandProvidersCache(), dgFile); using (var cacheContext = new SourceCacheContext()) { var restoreContext = new RestoreArgs(); restoreContext.CacheContext = cacheContext; restoreContext.Log = new NuGet.Common.NullLogger(); restoreContext.PreLoadedRequestProviders.Add(dgProvider); var request = (await dgProvider.CreateRequests(restoreContext)).Single(); var restoreRequest = request.Request; var collectorLogger = new RestoreCollectorLogger(restoreRequest.Log, false); var contextForProject = CreateRemoteWalkContext(restoreRequest, collectorLogger); // Get external project references // If the top level project already exists, update the package spec provided // with the RestoreRequest spec. var updatedExternalProjects = GetProjectReferences(restoreRequest, contextForProject); // Load repositories // the external project provider is specific to the current restore project contextForProject.ProjectLibraryProviders.Add(new PackageSpecReferenceDependencyProvider(updatedExternalProjects, restoreRequest.Log)); var walker = new RemoteDependencyWalker(contextForProject); var requestProject = request.Request.Project; var projectRange = new LibraryRange() { Name = projectName, VersionRange = new NuGet.Versioning.VersionRange(requestProject.Version), TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject }; var framework = requestProject.TargetFrameworks.First(); var graphs = new List <GraphNode <RemoteResolveResult> > { await walker.WalkAsync( projectRange, framework.FrameworkName, null, RuntimeGraph.Empty, recursive : true) }; return(RestoreTargetGraph.Create(graphs, contextForProject, restoreRequest.Log, framework.FrameworkName)); } }
public void IsGreaterThanEqualTo_ReturnsFalse_IfRightVersionIsLargerThanLeft(string leftVersionString, string rightVersionString) { // Arrange var leftVersion = VersionRange.Parse(leftVersionString); var rightVersion = VersionRange.Parse(rightVersionString); // Act var isGreater = RemoteDependencyWalker.IsGreaterThanOrEqualTo(leftVersion, rightVersion); // Assert Assert.False(isGreater); }
public void IsGreaterThanEqualTo_ReturnsFalse_IfRightVersionIsUnbound() { // Arrange var leftVersion = VersionRange.Parse("3.1.0-*"); var rightVersion = VersionRange.All; // Act var isGreater = RemoteDependencyWalker.IsGreaterThanOrEqualTo(leftVersion, rightVersion); // Assert Assert.False(isGreater); }
private Task <RestoreTargetGraph> WalkDependenciesAsync(LibraryRange projectRange, NuGetFramework framework, RemoteDependencyWalker walker, RemoteWalkContext context, CancellationToken token) { return(WalkDependenciesAsync(projectRange, framework, runtimeIdentifier: null, runtimeGraph: RuntimeGraph.Empty, walker: walker, context: context, token: token)); }
public async Task DoubleDowngrade() { var context = new TestRemoteWalkContext(); var provider = new DependencyProvider(); provider.Package("A", "1.0") .DependsOn("B", "0.7") .DependsOn("C", "1.0"); provider.Package("B", "0.7"); provider.Package("C", "1.0") .DependsOn("B", "0.8") .DependsOn("D", "1.0"); provider.Package("B", "0.8"); provider.Package("D", "1.0") .DependsOn("B", "1.0"); provider.Package("B", "1.0"); context.LocalLibraryProviders.Add(provider); var walker = new RemoteDependencyWalker(context); var node = await DoWalkAsync(walker, "A"); var downgrades = new List <Tuple <GraphNode <RemoteResolveResult>, GraphNode <RemoteResolveResult> > >(); var cycles = new List <GraphNode <RemoteResolveResult> >(); var result = node.Analyze(); Assert.Equal(2, result.Downgrades.Count); var d0 = result.Downgrades[0]; var d0To = d0.DowngradedFrom; var d0By = d0.DowngradedTo; AssertPath(d0To, "A 1.0", "C 1.0", "B 0.8"); AssertPath(d0By, "A 1.0", "B 0.7"); var d1 = result.Downgrades[1]; var d1To = d1.DowngradedFrom; var d1By = d1.DowngradedTo; AssertPath(d1To, "A 1.0", "C 1.0", "D 1.0", "B 1.0"); AssertPath(d1By, "A 1.0", "B 0.7"); }
public async Task ConflictAtDifferentLevel() { var context = new TestRemoteWalkContext(); var provider = new DependencyProvider(); provider.Package("A", "1.0") .DependsOn("B", "2.0") .DependsOn("C", "2.0") .DependsOn("F", "2.0"); provider.Package("B", "2.0") .DependsOn("D", "2.0"); provider.Package("C", "2.0") .DependsOn("D", "1.0"); provider.Package("D", "1.0") .DependsOn("E", "[1.0]"); provider.Package("D", "2.0") .DependsOn("E", "[2.0]"); provider.Package("F", "2.0") .DependsOn("E", "[1.0]"); provider.Package("E", "1.0"); provider.Package("E", "2.0"); context.LocalLibraryProviders.Add(provider); var walker = new RemoteDependencyWalker(context); var node = await DoWalkAsync(walker, "A"); var result = node.Analyze(); Assert.Equal(1, result.VersionConflicts.Count); var conflict = result.VersionConflicts[0]; var c1 = conflict.Selected; var c2 = conflict.Conflicting; AssertPath(c1, "A 1.0", "B 2.0", "D 2.0", "E 2.0"); AssertPath(c2, "A 1.0", "F 2.0", "E 1.0"); }
public async Task <GraphNode <RemoteResolveResult> > ResolvePackages(List <PackageId> packages) { var walkerContext = new RemoteWalkContext(_cache, _nuGetLogger); foreach (var sourceRepository in _repositoryProvider.Repositories) { var provider = new SourceRepositoryDependencyProvider(sourceRepository, _nuGetLogger, _cache, true, true); walkerContext.RemoteLibraryProviders.Add(provider); } walkerContext.ProjectLibraryProviders.Add(new ProjectLibraryProvider(packages)); var localProvider = new SourceRepositoryDependencyProvider(_localRepository, _nuGetLogger, _cache, true, true); walkerContext.LocalLibraryProviders.Add(localProvider); var fakeLib = new LibraryRange("Dropcraft", VersionRange.Parse("1.0.0"), LibraryDependencyTarget.Project); var walker = new RemoteDependencyWalker(walkerContext); return(await walker.WalkAsync(fakeLib, _framework, _framework.GetShortFolderName(), RuntimeGraph.Empty, true)); }
public async Task WalkAsync_CentralTransitiveDependencyList_DoesNotHaveDuplicates() { var framework = NuGetFramework.Parse("net45"); var context = new TestRemoteWalkContext(); var provider = new DependencyProvider(); // A -> centralPackage1 // -> centralPackage2 -> centralPackage1 provider.Package("A", "1.0.0") .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true); provider.Package("A", "1.0.0") .DependsOn("centralPackage2", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true); provider.Package("centralPackage2", "1.0.0") .DependsOn("centralPackage1", "1.0.0"); // A -> projectB -> projectC -> centralPackage1 provider.Package("A", "1.0.0") .DependsOn("B", "1.0.0"); provider.Package("B", "1.0.0") .DependsOn("C", "1.0.0"); provider.Package("C", "1.0.0") .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true); // B ~> centralPackage1 provider.Package("B", "1.0.0") .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true, libraryDependencyReferenceType: LibraryDependencyReferenceType.None); provider.Package("centralPackage1", "1.0.0"); provider.Package("centralPackage2", "1.0.0"); context.LocalLibraryProviders.Add(provider); var walker = new RemoteDependencyWalker(context); // Act var rootNode = await DoWalkAsync(walker, "A", framework); // Assert Assert.Equal(3, rootNode.InnerNodes.Count); }
public async Task SlowerFeedWinsIfBetterMatchExists() { // A var slowProvider = new TestProvider(TimeSpan.FromSeconds(2)); slowProvider.AddLibrary(new LibraryIdentity { Name = "A", Version = new NuGetVersion("1.0.0") }); var fastProvider = new TestProvider(TimeSpan.Zero); fastProvider.AddLibrary(new LibraryIdentity { Name = "A", Version = new NuGetVersion("1.1.0") }); var context = new TestRemoteWalkContext(); context.RemoteLibraryProviders.Add(slowProvider); context.RemoteLibraryProviders.Add(fastProvider); var walker = new RemoteDependencyWalker(context); var result = await walker.WalkAsync(new LibraryRange { Name = "A", VersionRange = VersionRange.Parse("1.0.0"), }, NuGetFramework.Parse("net45"), runtimeIdentifier : null, runtimeGraph : null, recursive : true); Assert.NotNull(result.Item.Data.Match); Assert.NotNull(result.Item.Data.Match.Library); Assert.Equal("A", result.Item.Data.Match.Library.Name); Assert.Equal(new NuGetVersion("1.0.0"), result.Item.Data.Match.Library.Version); Assert.Equal(slowProvider, result.Item.Data.Match.Provider); }
public async Task FasterProviderReturnsResultsBeforeSlowOnesIfExactMatchFound() { // A var slowProvider = new TestProvider(TimeSpan.FromSeconds(2)); slowProvider.AddLibrary(new LibraryIdentity { Name = "A", Version = new NuGetVersion("1.0.0") }); var fastProvider = new TestProvider(TimeSpan.Zero); fastProvider.AddLibrary(new LibraryIdentity { Name = "A", Version = new NuGetVersion("1.0.0") }); var context = new RemoteWalkContext(); context.RemoteLibraryProviders.Add(slowProvider); context.RemoteLibraryProviders.Add(fastProvider); var walker = new RemoteDependencyWalker(context); var result = await walker.WalkAsync(new LibraryRange { Name = "A", VersionRange = VersionRange.Parse("1.0.0"), }, NuGetFramework.Parse("net45"), runtimeIdentifier : null, runtimeGraph : null); Assert.NotNull(result.Item.Data.Match); Assert.NotNull(result.Item.Data.Match.Library); Assert.Equal("A", result.Item.Data.Match.Library.Name); Assert.Equal(new NuGetVersion("1.0.0"), result.Item.Data.Match.Library.Version); Assert.Equal(fastProvider, result.Item.Data.Match.Provider); }
private async Task <RestoreTargetGraph> WalkDependenciesAsync(LibraryRange projectRange, NuGetFramework framework, string runtimeIdentifier, RuntimeGraph runtimeGraph, RemoteDependencyWalker walker, RemoteWalkContext context, CancellationToken token) { var name = FrameworkRuntimePair.GetName(framework, runtimeIdentifier); var graphs = new List <GraphNode <RemoteResolveResult> >(); graphs.Add(await walker.WalkAsync( projectRange, framework, runtimeIdentifier, runtimeGraph, recursive: true)); // Resolve conflicts _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_ResolvingConflicts, name)); // Flatten and create the RestoreTargetGraph to hold the packages var result = RestoreTargetGraph.Create(runtimeGraph, graphs, context, _logger, framework, runtimeIdentifier); // Check if the dependencies got bumped up if (_request.ExistingLockFile == null) { // No lock file, so check dependencies CheckDependencies(result, _request.Project.Dependencies); var fxInfo = _request.Project.GetTargetFramework(framework); if (fxInfo != null) { CheckDependencies(result, fxInfo.Dependencies); } } return(result); }
public async Task TryResolveConflicts_WorksWhenVersionRangeIsNotSpecified() { var context = new TestRemoteWalkContext(); var provider = new DependencyProvider(); provider.Package("Root", "1.0") .DependsOn("A", "1.0") .DependsOn("B", "2.0"); provider.Package("A", "1.0") .DependsOn("C"); provider.Package("B", "2.0") .DependsOn("C", "1.8"); provider.Package("C", "1.8"); provider.Package("C", "2.0"); context.LocalLibraryProviders.Add(provider); var walker = new RemoteDependencyWalker(context); var node = await DoWalkAsync(walker, "Root"); // Restore doesn't actually support null versions so fake a resolved dependency var cNode = node.Path("A", "C"); cNode.Key.TypeConstraint = LibraryDependencyTarget.Package; cNode.Item = new GraphItem <RemoteResolveResult>(new LibraryIdentity { Name = "C", Version = new NuGetVersion("2.0") }); var result = node.Analyze(); Assert.Empty(result.VersionConflicts); Assert.Equal(Disposition.Accepted, cNode.Disposition); Assert.Equal(Disposition.Rejected, node.Path("B", "C").Disposition); }
public async Task DowngradeSkippedIfEqual() { var context = new TestRemoteWalkContext(); var provider = new DependencyProvider(); provider.Package("A", "1.0") .DependsOn("B", "2.0") .DependsOn("C", "2.0"); provider.Package("B", "2.0") .DependsOn("C", "2.0"); provider.Package("C", "2.0"); context.LocalLibraryProviders.Add(provider); var walker = new RemoteDependencyWalker(context); var node = await DoWalkAsync(walker, "A"); var result = node.Analyze(); Assert.Equal(0, result.Downgrades.Count); }
public async Task CyclesAreDetectedIf2VersionsOfTheSamePackageId() { var context = new TestRemoteWalkContext(); var provider = new DependencyProvider(); provider.Package("A", "1.0") .DependsOn("B", "2.0"); provider.Package("B", "2.0") .DependsOn("A", "5.0"); context.LocalLibraryProviders.Add(provider); var walker = new RemoteDependencyWalker(context); var node = await DoWalkAsync(walker, "A"); var result = node.Analyze(); Assert.Equal(1, result.Cycles.Count); var cycle = result.Cycles[0]; AssertPath(cycle, "A 1.0", "B 2.0", "A 5.0"); }
public async Task SlowerFeedWinsIfBetterMatchExists() { // A var slowProvider = new TestProvider(TimeSpan.FromSeconds(2)); slowProvider.AddLibrary(new LibraryIdentity { Name = "A", Version = new NuGetVersion("1.0.0") }); var fastProvider = new TestProvider(TimeSpan.Zero); fastProvider.AddLibrary(new LibraryIdentity { Name = "A", Version = new NuGetVersion("1.1.0") }); var context = new RemoteWalkContext(); context.RemoteLibraryProviders.Add(slowProvider); context.RemoteLibraryProviders.Add(fastProvider); var walker = new RemoteDependencyWalker(context); var result = await walker.WalkAsync(new LibraryRange { Name = "A", VersionRange = VersionRange.Parse("1.0.0"), }, NuGetFramework.Parse("net45"), runtimeIdentifier: null, runtimeGraph: null); Assert.NotNull(result.Item.Data.Match); Assert.NotNull(result.Item.Data.Match.Library); Assert.Equal("A", result.Item.Data.Match.Library.Name); Assert.Equal(new NuGetVersion("1.0.0"), result.Item.Data.Match.Library.Version); Assert.Equal(slowProvider, result.Item.Data.Match.Provider); }
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> > 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)); }
private async Task <IEnumerable <RestoreTargetGraph> > ExecuteRestoreAsync(NuGetv3LocalRepository localRepository, RemoteWalkContext context, CancellationToken token) { if (_request.Project.TargetFrameworks.Count == 0) { _logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectDoesNotSpecifyTargetFrameworks, _request.Project.Name, _request.Project.FilePath)); _success = false; return(Enumerable.Empty <RestoreTargetGraph>()); } _logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, _request.Project.FilePath)); // External references var updatedExternalProjects = new List <ExternalProjectReference>(_request.ExternalProjects); if (_request.ExternalProjects.Count > 0) { // There should be at most one match in the external projects. var rootProjectMatches = _request.ExternalProjects.Where(proj => string.Equals( _request.Project.Name, proj.PackageSpecProjectName, StringComparison.OrdinalIgnoreCase)) .ToList(); if (rootProjectMatches.Count > 1) { throw new InvalidOperationException($"Ambiguous project name '{_request.Project.Name}'."); } var rootProject = rootProjectMatches.SingleOrDefault(); if (rootProject != null) { // Replace the project spec with the passed in package spec, // for installs which are done in memory first this will be // different from the one on disk updatedExternalProjects.RemoveAll(project => project.UniqueName.Equals(rootProject.UniqueName, StringComparison.Ordinal)); var updatedReference = new ExternalProjectReference( rootProject.UniqueName, _request.Project, rootProject.MSBuildProjectPath, rootProject.ExternalProjectReferences); updatedExternalProjects.Add(updatedReference); // Determine if the targets and props files should be written out. context.IsMsBuildBased = XProjUtility.IsMSBuildBasedProject(rootProject.MSBuildProjectPath); } else { Debug.Fail("RestoreRequest.ExternaProjects contains references, but does not contain the top level references. Add the project we are restoring for."); throw new InvalidOperationException($"Missing external reference metadata for {_request.Project.Name}"); } } // Load repositories // the external project provider is specific to the current restore project var projectResolver = new PackageSpecResolver(_request.Project); context.ProjectLibraryProviders.Add( new PackageSpecReferenceDependencyProvider(projectResolver, updatedExternalProjects, _logger)); var remoteWalker = new RemoteDependencyWalker(context); var projectRange = new LibraryRange() { Name = _request.Project.Name, VersionRange = new VersionRange(_request.Project.Version), TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject }; // Resolve dependency graphs var allInstalledPackages = new HashSet <LibraryIdentity>(); var allGraphs = new List <RestoreTargetGraph>(); var runtimeIds = RequestRuntimeUtility.GetRestoreRuntimes(_request); var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(_request.Project, runtimeIds); var projectRestoreRequest = new ProjectRestoreRequest( _request, _request.Project, _request.ExistingLockFile, _runtimeGraphCache, _runtimeGraphCacheByPackage); var projectRestoreCommand = new ProjectRestoreCommand(_logger, projectRestoreRequest); var result = await projectRestoreCommand.TryRestore( projectRange, projectFrameworkRuntimePairs, allInstalledPackages, localRepository, remoteWalker, context, writeToLockFile : true, token : token); var success = result.Item1; var runtimes = result.Item3; allGraphs.AddRange(result.Item2); _success = success; // Calculate compatibility profiles to check by merging those defined in the project with any from the command line foreach (var profile in _request.Project.RuntimeGraph.Supports) { CompatibilityProfile compatProfile; if (profile.Value.RestoreContexts.Any()) { // Just use the contexts from the project definition compatProfile = profile.Value; } else if (!runtimes.Supports.TryGetValue(profile.Value.Name, out compatProfile)) { // No definition of this profile found, so just continue to the next one _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Log_UnknownCompatibilityProfile, profile.Key)); continue; } foreach (var pair in compatProfile.RestoreContexts) { _logger.LogDebug($" {profile.Value.Name} -> +{pair}"); _request.CompatibilityProfiles.Add(pair); } } // Walk additional runtime graphs for supports checks if (_success && _request.CompatibilityProfiles.Any()) { var compatibilityResult = await projectRestoreCommand.TryRestore(projectRange, _request.CompatibilityProfiles, allInstalledPackages, localRepository, remoteWalker, context, writeToLockFile : false, token : token); _success = compatibilityResult.Item1; // TryRestore may contain graphs that are already in allGraphs if the // supports section contains the same TxM as the project framework. var currentGraphs = new HashSet <KeyValuePair <NuGetFramework, string> >( allGraphs.Select(graph => new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier)) ); foreach (var graph in compatibilityResult.Item2) { var key = new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier); if (currentGraphs.Add(key)) { allGraphs.Add(graph); } } } return(allGraphs); }
private async Task <IEnumerable <ToolRestoreResult> > ExecuteToolRestoresAsync( NuGetv3LocalRepository localRepository, CancellationToken token) { var toolPathResolver = new ToolPathResolver(_request.PackagesDirectory); var results = new List <ToolRestoreResult>(); foreach (var tool in _request.Project.Tools) { _logger.LogMinimal(string.Format( CultureInfo.CurrentCulture, Strings.Log_RestoringToolPackages, tool.LibraryRange.Name, _request.Project.FilePath)); // Build the fallback framework (which uses the "imports"). var framework = LockFile.ToolFramework; if (tool.Imports.Any()) { framework = new FallbackFramework(framework, tool.Imports); } // Build a package spec in memory to execute the tool restore as if it were // its own project. For now, we always restore for a null runtime and a single // constant framework. var toolPackageSpec = new PackageSpec(new JObject()) { Name = Guid.NewGuid().ToString(), // make sure this package never collides with a dependency Dependencies = new List <LibraryDependency>(), Tools = new List <ToolDependency>(), TargetFrameworks = { new TargetFrameworkInformation { FrameworkName = framework, Dependencies = new List <LibraryDependency> { new LibraryDependency { LibraryRange = tool.LibraryRange } } } } }; // Try to find the existing lock file. Since the existing lock file is pathed under // a folder that includes the resolved tool's version, this is a bit of a chicken // and egg problem. That is, we need to run the restore operation in order to resolve // a tool version, but we need the tool version to find the existing project.lock.json // file which is required before executing the restore! Fortunately, this is solved by // looking at the tool's consuming project's lock file to see if the tool has been // restored before. LockFile existingToolLockFile = null; if (_request.ExistingLockFile != null) { var existingTarget = _request .ExistingLockFile .Tools .Where(t => t.RuntimeIdentifier == null) .Where(t => t.TargetFramework.Equals(LockFile.ToolFramework)) .FirstOrDefault(); var existingLibrary = existingTarget?.Libraries .Where(l => StringComparer.OrdinalIgnoreCase.Equals(l.Name, tool.LibraryRange.Name)) .Where(l => tool.LibraryRange.VersionRange.Satisfies(l.Version)) .FirstOrDefault(); if (existingLibrary != null) { var existingLockFilePath = toolPathResolver.GetLockFilePath( existingLibrary.Name, existingLibrary.Version, existingTarget.TargetFramework); existingToolLockFile = LockFileUtilities.GetLockFile(existingLockFilePath, _logger); } } // Execute the restore. var toolSuccess = true; // success for this individual tool restore var runtimeIds = new HashSet <string>(); var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(toolPackageSpec, runtimeIds); var allInstalledPackages = new HashSet <LibraryIdentity>(); var contextForTool = CreateRemoteWalkContext(_request); var walker = new RemoteDependencyWalker(contextForTool); var projectRestoreRequest = new ProjectRestoreRequest( _request, toolPackageSpec, existingToolLockFile, new Dictionary <NuGetFramework, RuntimeGraph>(), _runtimeGraphCacheByPackage); var projectRestoreCommand = new ProjectRestoreCommand(_logger, projectRestoreRequest); var result = await projectRestoreCommand.TryRestore( tool.LibraryRange, projectFrameworkRuntimePairs, allInstalledPackages, localRepository, walker, contextForTool, writeToLockFile : true, token : token); var graphs = result.Item2; if (!result.Item1) { toolSuccess = false; _success = false; } // Create the lock file (in memory). var toolLockFile = BuildLockFile( existingToolLockFile, toolPackageSpec, graphs, localRepository, contextForTool, Enumerable.Empty <ToolRestoreResult>(), false); // Build the path based off of the resolved tool. For now, we assume there is only // ever one target. var target = toolLockFile.Targets.Single(); var fileTargetLibrary = target .Libraries .FirstOrDefault(l => StringComparer.OrdinalIgnoreCase.Equals(tool.LibraryRange.Name, l.Name)); string toolLockFilePath = null; if (fileTargetLibrary != null) { toolLockFilePath = toolPathResolver.GetLockFilePath( fileTargetLibrary.Name, fileTargetLibrary.Version, target.TargetFramework); } // Validate the results. if (!ValidateRestoreGraphs(graphs, _logger)) { toolSuccess = false; _success = false; } var checkResults = VerifyCompatibility( toolPackageSpec, new Dictionary <RestoreTargetGraph, Dictionary <string, LibraryIncludeFlags> >(), localRepository, toolLockFile, graphs, _logger); if (checkResults.Any(r => !r.Success)) { toolSuccess = false; _success = false; } results.Add(new ToolRestoreResult( tool.LibraryRange.Name, toolSuccess, target, fileTargetLibrary, toolLockFilePath, toolLockFile, existingToolLockFile)); } return(results); }
private async Task <bool> RestoreForProject(string projectJsonPath, string rootDirectory, string packagesDirectory) { var success = true; Logger.WriteInformation(string.Format("Restoring packages for {0}", projectJsonPath.Bold())); var sw = new Stopwatch(); sw.Start(); NuGetProject project; if (!ProjectReader.TryReadProject(projectJsonPath, out project)) { throw new Exception("Unable to locate project.json"); } var projectDirectory = project.ProjectDirectory; var projectLockFilePath = Path.Combine(projectDirectory, LockFileFormat.LockFileName); var properties = new Dictionary <string, string> { { "DesignTimeBuild", "true" }, { "BuildProjectReferences", "false" }, { "_ResolveReferenceDependencies", "true" }, { "SolutionDir", rootDirectory + Path.DirectorySeparatorChar } }; var projectCollection = new ProjectCollection(); foreach (var projectFile in Directory.EnumerateFiles(projectDirectory, "*.csproj")) { projectCollection.LoadProject(projectFile); } foreach (var projectFile in Directory.EnumerateFiles(projectDirectory, "*.vbproj")) { projectCollection.LoadProject(projectFile); } foreach (var projectFile in Directory.EnumerateFiles(projectDirectory, "*.fsproj")) { projectCollection.LoadProject(projectFile); } var context = new RemoteWalkContext(); var nugetRepository = new NuGetv3LocalRepository(packagesDirectory, checkPackageIdCase: true); context.ProjectLibraryProviders.Add(new LocalDependencyProvider( new MSBuildDependencyProvider(projectCollection))); context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new ProjectReferenceDependencyProvider( new ProjectResolver( projectDirectory, rootDirectory)))); context.LocalLibraryProviders.Add( new LocalDependencyProvider( new NuGetDependencyResolver(nugetRepository))); var effectiveSources = PackageSourceUtils.GetEffectivePackageSources(SourceProvider, Sources, FallbackSources); AddRemoteProvidersFromSources(context.RemoteLibraryProviders, effectiveSources); var remoteWalker = new RemoteDependencyWalker(context); var tasks = new List <Task <GraphNode <RemoteResolveResult> > >(); var msbuildProject = projectCollection.LoadedProjects.FirstOrDefault(); if (msbuildProject != null) { var name = msbuildProject.GetPropertyValue("AssemblyName"); var targetFrameworkMoniker = msbuildProject.GetPropertyValue("TargetFrameworkMoniker"); // This is so that we have a unique cache per target framework tasks.Add(remoteWalker.Walk(name, new NuGetVersion(new Version()), NuGetFramework.Parse(targetFrameworkMoniker))); } else { foreach (var framework in project.TargetFrameworks) { tasks.Add(remoteWalker.Walk(project.Name, project.Version, framework.FrameworkName)); } } var graphs = await Task.WhenAll(tasks); Logger.WriteInformation(string.Format("{0}, {1}ms elapsed", "Resolving complete".Green(), sw.ElapsedMilliseconds)); var libraries = new HashSet <Library>(); var installItems = new List <GraphItem <RemoteResolveResult> >(); var missingItems = new HashSet <LibraryRange>(); foreach (var g in graphs) { g.Dump(s => Logger.WriteInformation(s)); g.ForEach(node => { if (node == null || node.Key == null) { return; } if (node.Item == null || node.Item.Data.Match == null) { if (!node.Key.IsGacOrFrameworkReference && node.Key.VersionRange != null && missingItems.Add(node.Key)) { Logger.WriteError(string.Format("Unable to locate {0} {1}", node.Key.Name.Red().Bold(), node.Key.VersionRange)); success = false; } return; } var isRemote = context.RemoteLibraryProviders.Contains(node.Item.Data.Match.Provider); var isAdded = installItems.Any(item => item.Data.Match.Library == node.Item.Data.Match.Library); if (!isAdded && isRemote) { installItems.Add(node.Item); } libraries.Add(node.Item.Key); }); } await InstallPackages(installItems, packagesDirectory, packageFilter : (library, nupkgSHA) => true); if (success) { Logger.WriteInformation(string.Format("Writing lock file {0}", projectLockFilePath.White().Bold())); WriteLockFile(projectLockFilePath, libraries, nugetRepository); } //if (!ScriptExecutor.Execute(project, "postrestore", getVariable)) //{ // Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); // return false; //} //if (!ScriptExecutor.Execute(project, "prepare", getVariable)) //{ // Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); // return false; //} Logger.WriteInformation(string.Format("{0}, {1}ms elapsed", "Restore complete".Green().Bold(), sw.ElapsedMilliseconds)); //for (int i = 0; i < contexts.Count; i++) //{ // PrintDependencyGraph(graphs[i], contexts[i].FrameworkName); //} return(success); }
private async Task <List <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 <RestoreTargetGraph>(); foreach (var runtimeName in projectRuntimeGraph.Runtimes.Keys) { _log.LogInformation($"Restoring packages for {graph.Framework} on {runtimeName}"); resultGraphs.Add(await WalkDependencies(projectRange, graph.Framework, runtimeName, runtimeGraph, walker, context)); } return(resultGraphs); }
public static void InstallPackage(IReadOnlyList <string> packages, bool quiet) { Init(); RemoteWalkContext context = new RemoteWalkContext(); ILogger logger = new NullLogger(); SourceCacheContext cacheContext = new SourceCacheContext { IgnoreFailedSources = true }; foreach (SourceRepository repo in Repos) { if (!repo.PackageSource.IsLocal) { context.RemoteLibraryProviders.Add(new SourceRepositoryDependencyProvider(repo, logger, cacheContext)); } else { context.LocalLibraryProviders.Add(new SourceRepositoryDependencyProvider(repo, logger, cacheContext)); } } Paths.User.Content.CreateDirectory(); RemoteDependencyWalker walker = new RemoteDependencyWalker(context); HashSet <Package> remainingPackages = new HashSet <Package>(packages.Select(x => new Package(x, VersionRange.All))); HashSet <Package> encounteredPackages = new HashSet <Package>(); List <string> templateRoots = new List <string>(); List <KeyValuePair <string, string> > componentRoots = new List <KeyValuePair <string, string> >(); while (remainingPackages.Count > 0) { HashSet <Package> nextRound = new HashSet <Package>(); foreach (Package package in remainingPackages) { string name = package.PackageId; GraphNode <RemoteResolveResult> result = walker.WalkAsync(new LibraryRange(name, package.Version, LibraryDependencyTarget.All), NuGetFramework.AnyFramework, "", RuntimeGraph.Empty, true).Result; RemoteMatch match = result.Item.Data.Match; PackageIdentity packageIdentity = new PackageIdentity(match.Library.Name, match.Library.Version); nextRound.UnionWith(result.Item.Data.Dependencies.Select(x => new Package(x.Name, x.LibraryRange.VersionRange))); VersionFolderPathContext versionFolderPathContext = new VersionFolderPathContext( packageIdentity, Paths.User.PackageCache, new NullLogger(), packageSaveMode: PackageSaveMode.Defaultv3, xmlDocFileSaveMode: XmlDocFileSaveMode.Skip, fixNuspecIdCasing: true, normalizeFileNames: true); if (match.Library.Version == null) { if (!quiet) { throw new Exception($"Package '{package.PackageId}' version {package.Version} could not be located."); } else { continue; } } string source = Path.Combine(Paths.User.PackageCache, match.Library.Name, match.Library.Version.ToString()); if (!source.Exists() && match.Provider != null) { PackageExtractor.InstallFromSourceAsync( stream => match.Provider.CopyToAsync(match.Library, stream, CancellationToken.None), versionFolderPathContext, CancellationToken.None).Wait(); string target = Path.Combine(Paths.User.Content, match.Library.Name); target.CreateDirectory(); target = Path.Combine(target, match.Library.Version.ToString()); target.CreateDirectory(); Paths.Copy(source, target); target.Delete("*.nupkg", "*.nupkg.*"); string nuspec = target.EnumerateFiles("*.nuspec").FirstOrDefault(); //If there's a nuspec, figure out whether this package is a template and walk the dependency graph if (nuspec?.Exists() ?? false) { XDocument doc = XDocument.Load(nuspec); IReadOnlyList <PackageType> types = NuspecUtility.GetPackageTypes(doc.Root.Element(XName.Get("metadata", "http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd")), false); //If the thing we got is a template... if (types.Any(x => string.Equals(x.Name, "template", StringComparison.OrdinalIgnoreCase))) { templateRoots.Add(target); } else { componentRoots.Add(new KeyValuePair <string, string>(match.Library.Name, match.Library.Version.ToString())); } } } } encounteredPackages.UnionWith(remainingPackages); nextRound.ExceptWith(encounteredPackages); remainingPackages = nextRound; } foreach (KeyValuePair <string, string> package in componentRoots) { foreach (string path in Path.Combine(Paths.User.Content, package.Key, package.Value).EnumerateFiles($"{package.Key}.dll", SearchOption.AllDirectories)) { if (path.IndexOf($"{Path.DirectorySeparatorChar}lib{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) < 0 || (path.IndexOf($"{Path.DirectorySeparatorChar}netstandard1.", StringComparison.OrdinalIgnoreCase) < 0 && path.IndexOf($"{Path.DirectorySeparatorChar}netcoreapp1.", StringComparison.OrdinalIgnoreCase) < 0)) { continue; } #if !NET451 Assembly asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); #else Assembly asm = Assembly.LoadFile(path); #endif foreach (Type type in asm.GetTypes()) { SettingsLoader.Components.Register(type); } } } TemplateCache.Scan(templateRoots); }
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)); }
private Task <RestoreTargetGraph> WalkDependencies(LibraryRange projectRange, NuGetFramework framework, RemoteDependencyWalker walker, RemoteWalkContext context) { return(WalkDependencies(projectRange, framework, null, RuntimeGraph.Empty, walker, context)); }
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 <RestoreResult> ExecuteAsync(RestoreRequest request) { if (request.Project.TargetFrameworks.Count == 0) { _log.LogError("The project does not specify any target frameworks!"); return(new RestoreResult(success: false, restoreGraphs: Enumerable.Empty <RestoreTargetGraph>())); } var projectLockFilePath = string.IsNullOrEmpty(request.LockFilePath) ? Path.Combine(request.Project.BaseDirectory, LockFileFormat.LockFileName) : request.LockFilePath; _log.LogInformation($"Restoring packages for '{request.Project.FilePath}'"); _log.LogWarning("TODO: Read and use lock file"); // Load repositories var projectResolver = new PackageSpecResolver(request.Project.BaseDirectory); var nugetRepository = Repository.Factory.GetCoreV3(request.PackagesDirectory); var context = new RemoteWalkContext(); context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new PackageSpecReferenceDependencyProvider(projectResolver))); if (request.ExternalProjects != null) { context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new ExternalProjectReferenceDependencyProvider(request.ExternalProjects))); } context.LocalLibraryProviders.Add( new SourceRepositoryDependencyProvider(nugetRepository, _log)); foreach (var provider in request.Sources.Select(s => CreateProviderFromSource(s, request.NoCache))) { context.RemoteLibraryProviders.Add(provider); } var remoteWalker = new RemoteDependencyWalker(context); var projectRange = new LibraryRange() { Name = request.Project.Name, VersionRange = new VersionRange(request.Project.Version), TypeConstraint = LibraryTypes.Project }; // Resolve dependency graphs var frameworks = request.Project.TargetFrameworks.Select(f => f.FrameworkName).ToList(); var graphs = new List <RestoreTargetGraph>(); foreach (var framework in frameworks) { graphs.Add(await WalkDependencies(projectRange, framework, remoteWalker, context)); } if (graphs.Any(g => g.InConflict)) { _log.LogError("Failed to resolve conflicts"); return(new RestoreResult(success: false, restoreGraphs: graphs)); } // Install the runtime-agnostic packages var allInstalledPackages = new HashSet <LibraryIdentity>(); var localRepository = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false); await InstallPackages(graphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency); // Resolve runtime dependencies var runtimeGraphs = new List <RestoreTargetGraph>(); if (request.Project.RuntimeGraph.Runtimes.Count > 0) { foreach (var graph in graphs) { var runtimeSpecificGraphs = await WalkRuntimeDependencies(projectRange, graph, request.Project.RuntimeGraph, remoteWalker, context, localRepository); runtimeGraphs.AddRange(runtimeSpecificGraphs); } graphs.AddRange(runtimeGraphs); if (runtimeGraphs.Any(g => g.InConflict)) { _log.LogError("Failed to resolve conflicts"); return(new RestoreResult(success: false, restoreGraphs: graphs)); } // Install runtime-specific packages await InstallPackages(runtimeGraphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency); } else { _log.LogVerbose("Skipping runtime dependency walk, no runtimes defined in project.json"); } // Build the lock file var repository = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false); var lockFile = CreateLockFile(request.Project, graphs, repository); var lockFileFormat = new LockFileFormat(); lockFileFormat.Write(projectLockFilePath, lockFile); return(new RestoreResult(true, graphs, lockFile)); }
private async Task <RestoreTargetGraph> WalkDependenciesAsync(LibraryRange projectRange, NuGetFramework framework, string runtimeIdentifier, RuntimeGraph runtimeGraph, RemoteDependencyWalker walker, RemoteWalkContext context, bool writeToLockFile, CancellationToken token) { var name = FrameworkRuntimePair.GetName(framework, runtimeIdentifier); var graphs = new List <GraphNode <RemoteResolveResult> >(); if (_request.ExistingLockFile != null && _request.ExistingLockFile.IsLocked) { // Walk all the items in the lock file target and just synthesize the outer graph var target = _request.ExistingLockFile.GetTarget(framework, runtimeIdentifier); token.ThrowIfCancellationRequested(); if (target != null) { foreach (var targetLibrary in target.Libraries) { token.ThrowIfCancellationRequested(); var library = _request.ExistingLockFile.GetLibrary(targetLibrary.Name, targetLibrary.Version); if (library == null) { _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Log_LockFileMissingLibraryForTargetLibrary, targetLibrary.Name, targetLibrary.Version, target.Name)); continue; // This library is not in the main lockfile? } var range = new LibraryRange() { Name = library.Name, TypeConstraint = LibraryDependencyTargetUtils.Parse(library.Type), VersionRange = new VersionRange( minVersion: library.Version, includeMinVersion: true, maxVersion: library.Version, includeMaxVersion: true) }; graphs.Add(await walker.WalkAsync( range, framework, runtimeIdentifier, runtimeGraph, recursive: false)); } } } else { graphs.Add(await walker.WalkAsync( projectRange, framework, runtimeIdentifier, runtimeGraph, recursive: true)); } // Resolve conflicts _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_ResolvingConflicts, name)); // Flatten and create the RestoreTargetGraph to hold the packages var result = RestoreTargetGraph.Create(writeToLockFile, runtimeGraph, graphs, context, _logger, framework, runtimeIdentifier); // Check if the dependencies got bumped up // ...but not if there is an existing locked lock file. if (_request.ExistingLockFile == null || !_request.ExistingLockFile.IsLocked) { // No lock file, OR the lock file is unlocked, so check dependencies CheckDependencies(result, _request.Project.Dependencies); var fxInfo = _request.Project.GetTargetFramework(framework); if (fxInfo != null) { CheckDependencies(result, fxInfo.Dependencies); } } return(result); }
private Task <GraphNode <RemoteResolveResult> > DoWalkAsync(RemoteDependencyWalker walker, string name) { return(DoWalkAsync(walker, name, NuGetFramework.Parse("net45"))); }
private async Task <RestoreTargetGraph> WalkDependencies(LibraryRange projectRange, NuGetFramework framework, string runtimeIdentifier, RuntimeGraph runtimeGraph, RemoteDependencyWalker walker, RemoteWalkContext context) { _log.LogInformation($"Restoring packages for {framework}"); var graph = await walker.Walk( projectRange, framework, runtimeIdentifier, runtimeGraph); // Resolve conflicts _log.LogVerbose($"Resolving Conflicts for {framework}"); bool inConflict = !graph.TryResolveConflicts(); // Flatten and create the RestoreTargetGraph to hold the packages return(RestoreTargetGraph.Create(inConflict, framework, runtimeIdentifier, runtimeGraph, graph, context, _loggerFactory)); }
private async Task <IEnumerable <RestoreTargetGraph> > ExecuteRestoreAsync( NuGetv3LocalRepository userPackageFolder, IReadOnlyList <NuGetv3LocalRepository> fallbackPackageFolders, RemoteWalkContext context, CancellationToken token) { if (_request.Project.TargetFrameworks.Count == 0) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectDoesNotSpecifyTargetFrameworks, _request.Project.Name, _request.Project.FilePath); await _logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1001, message)); _success = false; return(Enumerable.Empty <RestoreTargetGraph>()); } _logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, _request.Project.FilePath)); // Get external project references // If the top level project already exists, update the package spec provided // with the RestoreRequest spec. var updatedExternalProjects = GetProjectReferences(context); // Determine if the targets and props files should be written out. context.IsMsBuildBased = _request.ProjectStyle != ProjectStyle.DotnetCliTool; // Load repositories // the external project provider is specific to the current restore project context.ProjectLibraryProviders.Add( new PackageSpecReferenceDependencyProvider(updatedExternalProjects, _logger)); var remoteWalker = new RemoteDependencyWalker(context); var projectRange = new LibraryRange() { Name = _request.Project.Name, VersionRange = new VersionRange(_request.Project.Version), TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject }; // Resolve dependency graphs var allInstalledPackages = new HashSet <LibraryIdentity>(); var allGraphs = new List <RestoreTargetGraph>(); var runtimeIds = RequestRuntimeUtility.GetRestoreRuntimes(_request); var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(_request.Project, runtimeIds); var hasSupports = _request.Project.RuntimeGraph.Supports.Count > 0; var projectRestoreRequest = new ProjectRestoreRequest( _request, _request.Project, _request.ExistingLockFile, _runtimeGraphCache, _runtimeGraphCacheByPackage, _logger); var projectRestoreCommand = new ProjectRestoreCommand(projectRestoreRequest); var result = await projectRestoreCommand.TryRestore( projectRange, projectFrameworkRuntimePairs, allInstalledPackages, userPackageFolder, fallbackPackageFolders, remoteWalker, context, forceRuntimeGraphCreation : hasSupports, token : token); var success = result.Item1; allGraphs.AddRange(result.Item2); _success = success; // Calculate compatibility profiles to check by merging those defined in the project with any from the command line foreach (var profile in _request.Project.RuntimeGraph.Supports) { var runtimes = result.Item3; CompatibilityProfile compatProfile; if (profile.Value.RestoreContexts.Any()) { // Just use the contexts from the project definition compatProfile = profile.Value; } else if (!runtimes.Supports.TryGetValue(profile.Value.Name, out compatProfile)) { // No definition of this profile found, so just continue to the next one var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_UnknownCompatibilityProfile, profile.Key); await _logger.LogAsync(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1502, message)); continue; } foreach (var pair in compatProfile.RestoreContexts) { _logger.LogDebug($" {profile.Value.Name} -> +{pair}"); _request.CompatibilityProfiles.Add(pair); } } // Walk additional runtime graphs for supports checks if (_success && _request.CompatibilityProfiles.Any()) { var compatibilityResult = await projectRestoreCommand.TryRestore( projectRange, _request.CompatibilityProfiles, allInstalledPackages, userPackageFolder, fallbackPackageFolders, remoteWalker, context, forceRuntimeGraphCreation : true, token : token); _success = compatibilityResult.Item1; // TryRestore may contain graphs that are already in allGraphs if the // supports section contains the same TxM as the project framework. var currentGraphs = new HashSet <KeyValuePair <NuGetFramework, string> >( allGraphs.Select(graph => new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier)) ); foreach (var graph in compatibilityResult.Item2) { var key = new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier); if (currentGraphs.Add(key)) { allGraphs.Add(graph); } } } return(allGraphs); }
public async Task WalkAsyncAddsTransitiveCentralDependency(string centralPackageVersion, string otherVersion) { var centralPackageName = "D"; var framework = NuGetFramework.Parse("net45"); var context = new TestRemoteWalkContext(); var provider = new DependencyProvider(); // D is a transitive dependency for package A through package B -> C -> D // D is defined as a Central Package Version // In this context Package D with version centralPackageVersion will be added as inner node of Node A, next to B // Input // A -> B (version = otherVersion) -> C (version = otherVersion) -> D (version = otherVersion) // A ~> D (the version 2.0.0 or as defined by "centralPackageVersion" argument // the dependency is not direct, // it simulates the fact that there is a centrally defined "D" package // the information is added to the provider) // The expected output graph // -> B (version = otherVersion) -> C (version = otherVersion) // A // -> D (version = 2.0.0) provider.Package("A", otherVersion) .DependsOn("B", otherVersion); provider.Package("B", otherVersion) .DependsOn("C", otherVersion); provider.Package("C", otherVersion) .DependsOn(centralPackageName, otherVersion); // Simulates the existence of a D centrally defined package that is not direct dependency provider.Package("A", otherVersion) .DependsOn(centralPackageName, centralPackageVersion, LibraryDependencyTarget.Package, versionCentrallyManaged: true, libraryDependencyReferenceType: LibraryDependencyReferenceType.None); // Add central package to the source with multiple versions provider.Package(centralPackageName, "1.0.0"); provider.Package(centralPackageName, centralPackageVersion); provider.Package(centralPackageName, "3.0.0"); context.LocalLibraryProviders.Add(provider); var walker = new RemoteDependencyWalker(context); // Act var rootNode = await DoWalkAsync(walker, "A", framework); // Assert Assert.Equal(2, rootNode.InnerNodes.Count); var centralVersionInGraphNode = rootNode.InnerNodes.Where(n => n.Item.Key.Name == centralPackageName).FirstOrDefault(); Assert.NotNull(centralVersionInGraphNode); Assert.Equal(centralPackageVersion, centralVersionInGraphNode.Item.Key.Version.ToNormalizedString()); Assert.True(centralVersionInGraphNode.Item.IsCentralTransitive); var BNode = rootNode.InnerNodes.Where(n => n.Item.Key.Name == "B").FirstOrDefault(); Assert.NotNull(BNode); Assert.Equal(1, BNode.InnerNodes.Count); Assert.Equal(otherVersion, BNode.Item.Key.Version.ToNormalizedString()); Assert.False(BNode.Item.IsCentralTransitive); var CNode = BNode.InnerNodes.Where(n => n.Item.Key.Name == "C").FirstOrDefault(); Assert.NotNull(CNode); Assert.Equal(otherVersion, CNode.Item.Key.Version.ToNormalizedString()); Assert.Equal(0, CNode.InnerNodes.Count); Assert.False(CNode.Item.IsCentralTransitive); }