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