private RestoreSummaryRequest Create( string projectNameToRestore, ExternalProjectReference project, HashSet <ExternalProjectReference> projectReferenceClosure, RestoreArgs restoreArgs, DependencyGraphSpec projectDgSpec) { var projectPackageSpec = projectDgSpec.GetProjectSpec(projectNameToRestore); //fallback paths, global packages path and sources need to all be passed in the dg spec var fallbackPaths = projectPackageSpec.RestoreMetadata.FallbackFolders; var globalPath = GetPackagesPath(restoreArgs, projectPackageSpec); var settings = Settings.LoadSettingsGivenConfigPaths(projectPackageSpec.RestoreMetadata.ConfigFilePaths); var sources = restoreArgs.GetEffectiveSources(settings, projectPackageSpec.RestoreMetadata.Sources); var clientPolicyContext = ClientPolicyContext.GetClientPolicy(settings, restoreArgs.Log); var sharedCache = _providerCache.GetOrCreate( globalPath, fallbackPaths.AsList(), sources, restoreArgs.CacheContext, restoreArgs.Log); var rootPath = Path.GetDirectoryName(project.PackageSpec.FilePath); // Create request var request = new RestoreRequest( project.PackageSpec, sharedCache, restoreArgs.CacheContext, clientPolicyContext, restoreArgs.Log) { // Set properties from the restore metadata ProjectStyle = project.PackageSpec.RestoreMetadata.ProjectStyle, // Project.json is special cased to put assets file and generated .props and targets in the project folder RestoreOutputPath = project.PackageSpec.RestoreMetadata.ProjectStyle == ProjectStyle.ProjectJson ? rootPath : project.PackageSpec.RestoreMetadata.OutputPath, DependencyGraphSpec = projectDgSpec, MSBuildProjectExtensionsPath = projectPackageSpec.RestoreMetadata.OutputPath }; var restoreLegacyPackagesDirectory = project.PackageSpec?.RestoreMetadata?.LegacyPackagesDirectory ?? DefaultRestoreLegacyPackagesDirectory; request.IsLowercasePackagesDirectory = !restoreLegacyPackagesDirectory; // Standard properties restoreArgs.ApplyStandardProperties(request); // Add project references request.ExternalProjects = projectReferenceClosure.ToList(); // The lock file is loaded later since this is an expensive operation var summaryRequest = new RestoreSummaryRequest( request, project.MSBuildProjectPath, settings.GetConfigFilePaths(), sources); return(summaryRequest); }
protected virtual RestoreSummaryRequest Create( ExternalProjectReference project, MSBuildProjectReferenceProvider msbuildProvider, RestoreArgs restoreContext, ISettings settingsOverride) { // Get settings relative to the input file var rootPath = Path.GetDirectoryName(project.PackageSpecPath); var settings = settingsOverride; if (settings == null) { settings = restoreContext.GetSettings(rootPath); } var globalPath = restoreContext.GetEffectiveGlobalPackagesFolder(rootPath, settings); var fallbackPaths = restoreContext.GetEffectiveFallbackPackageFolders(settings); var sources = restoreContext.GetEffectiveSources(settings); var sharedCache = _providerCache.GetOrCreate( globalPath, fallbackPaths, sources, restoreContext.CacheContext, restoreContext.Log); var request = new RestoreRequest( project.PackageSpec, sharedCache, restoreContext.Log, disposeProviders: false); restoreContext.ApplyStandardProperties(request); // Find all external references var externalReferences = msbuildProvider.GetReferences(project.MSBuildProjectPath).ToList(); request.ExternalProjects = externalReferences; // Determine if this needs to fall back to an older lock file format // Skip this if the arguments override the lock file version if (restoreContext.LockFileVersion == null) { request.LockFileVersion = LockFileUtilities.GetLockFileVersion(externalReferences); } // The lock file is loaded later since this is an expensive operation var summaryRequest = new RestoreSummaryRequest( request, project.MSBuildProjectPath, settings, sources); return(summaryRequest); }
private RestoreSummaryRequest Create( ExternalProjectReference project, HashSet <ExternalProjectReference> projectReferenceClosure, RestoreArgs restoreContext, ISettings settingsOverride) { // Get settings relative to the input file var rootPath = Path.GetDirectoryName(project.PackageSpec.FilePath); var settings = settingsOverride; if (settings == null) { settings = restoreContext.GetSettings(rootPath); } var globalPath = restoreContext.GetEffectiveGlobalPackagesFolder(rootPath, settings); var fallbackPaths = restoreContext.GetEffectiveFallbackPackageFolders(settings); var sources = restoreContext.GetEffectiveSources(settings); var sharedCache = _providerCache.GetOrCreate( globalPath, fallbackPaths, sources, restoreContext.CacheContext, restoreContext.Log); // Create request var request = new RestoreRequest( project.PackageSpec, sharedCache, restoreContext.CacheContext, restoreContext.Log); // Set properties from the restore metadata request.ProjectStyle = project.PackageSpec?.RestoreMetadata?.ProjectStyle ?? ProjectStyle.Unknown; request.RestoreOutputPath = project.PackageSpec?.RestoreMetadata?.OutputPath ?? rootPath; var restoreLegacyPackagesDirectory = project.PackageSpec?.RestoreMetadata?.LegacyPackagesDirectory ?? DefaultRestoreLegacyPackagesDirectory; request.IsLowercasePackagesDirectory = !restoreLegacyPackagesDirectory; // Standard properties restoreContext.ApplyStandardProperties(request); // Add project references request.ExternalProjects = projectReferenceClosure.ToList(); // The lock file is loaded later since this is an expensive operation var summaryRequest = new RestoreSummaryRequest( request, project.MSBuildProjectPath, settings, sources); return(summaryRequest); }
private List <ExternalProjectReference> GetProjectReferences(RemoteWalkContext context) { // External references var updatedExternalProjects = new List <ExternalProjectReference>(); if (_request.ExternalProjects.Count == 0) { // If no projects exist add the current project.json file to the project // list so that it can be resolved. updatedExternalProjects.Add(ToExternalProjectReference(_request.Project)); } else 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.AddRange(_request.ExternalProjects .Where(project => !project.UniqueName.Equals(rootProject.UniqueName, StringComparison.Ordinal))); var updatedReference = new ExternalProjectReference( rootProject.UniqueName, _request.Project, rootProject.MSBuildProjectPath, rootProject.ExternalProjectReferences); updatedExternalProjects.Add(updatedReference); } } else { // External references were passed, but the top level project wasn't found. // This is always due to an internal issue and typically caused by errors // building the project closure. Debug.Fail("RestoreRequest.ExternalProjects 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}"); } return(updatedExternalProjects); }
/// <summary> /// Return all references for a given project path. /// References is modified by this method. /// This includes the root project. /// </summary> private static void CollectReferences( ExternalProjectReference root, Dictionary <string, ExternalProjectReference> allProjects, HashSet <ExternalProjectReference> references) { if (references.Add(root)) { foreach (var child in root.ExternalProjectReferences) { ExternalProjectReference childProject; if (!allProjects.TryGetValue(child, out childProject)) { // Let the resolver handle this later Debug.Fail($"Missing project {childProject}"); } // Recurse down CollectReferences(childProject, allProjects, references); } } }
/// <summary> /// MSBuild project -> ExternalProjectReference /// </summary> private Dictionary <string, ExternalProjectReference> GetExternalProjectReferences( string entryPoint, Dictionary <string, HashSet <string> > projectReferences) { var results = new Dictionary <string, ExternalProjectReference>(StringComparer.OrdinalIgnoreCase); // Get the set of all possible projects var allProjects = new HashSet <string>(StringComparer.OrdinalIgnoreCase); allProjects.Add(entryPoint); allProjects.UnionWith(projectReferences.Keys); allProjects.UnionWith(projectReferences.Values.SelectMany(children => children)); // Load up all package specs foreach (var projectPath in allProjects) { var projectJson = GetPackageSpec(projectPath); var childProjectNames = new List <string>(); HashSet <string> children; if (projectReferences.TryGetValue(projectPath, out children)) { childProjectNames.AddRange(children); } var projectReference = new ExternalProjectReference( projectPath, projectJson, projectPath, childProjectNames); Debug.Assert(!results.ContainsKey(projectPath), "dupe: " + projectPath); results.Add(projectPath, projectReference); } return(results); }
private IReadOnlyList <RestoreSummaryRequest> GetRequestsFromItems(RestoreArgs restoreContext, DependencyGraphSpec dgFile) { if (restoreContext == null) { throw new ArgumentNullException(nameof(restoreContext)); } if (dgFile == null) { throw new ArgumentNullException(nameof(dgFile)); } // Validate the dg file input, this throws if errors are found. SpecValidationUtility.ValidateDependencySpec(dgFile); // Create requests var requests = new ConcurrentBag <RestoreSummaryRequest>(); var toolRequests = new ConcurrentBag <RestoreSummaryRequest>(); var parallelOptions = new ParallelOptions { // By default, max degree of parallelism is -1 which means no upper bound. // Limiting to processor count reduces task context switching which is better MaxDegreeOfParallelism = Environment.ProcessorCount }; using (var settingsLoadingContext = new SettingsLoadingContext()) { // Parallel.Foreach has an optimization for Arrays, so calling .ToArray() is better and adds almost no overhead Parallel.ForEach(dgFile.Restore.ToArray(), parallelOptions, projectNameToRestore => { IReadOnlyList <PackageSpec> closure = dgFile.GetClosure(projectNameToRestore); DependencyGraphSpec projectDependencyGraphSpec = dgFile.CreateFromClosure(projectNameToRestore, closure); var externalClosure = new HashSet <ExternalProjectReference>(closure.Select(GetExternalProject)); ExternalProjectReference rootProject = externalClosure.Single(p => StringComparer.Ordinal.Equals(projectNameToRestore, p.UniqueName)); RestoreSummaryRequest request = Create( projectNameToRestore, rootProject, externalClosure, restoreContext, projectDependencyGraphSpec, settingsLoadingContext); if (request.Request.ProjectStyle == ProjectStyle.DotnetCliTool) { // Store tool requests to be filtered later toolRequests.Add(request); } else { requests.Add(request); } }); } // Filter out duplicate tool restore requests foreach (RestoreSummaryRequest subSetRequest in ToolRestoreUtility.GetSubSetRequests(toolRequests)) { requests.Add(subSetRequest); } return(requests.ToArray()); }
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); }
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); var nugetRepository = Repository.Factory.GetCoreV3(request.PackagesDirectory); var context = new RemoteWalkContext(); ExternalProjectReference exterenalProjectReference = null; if (request.ExternalProjects.Any()) { exterenalProjectReference = new ExternalProjectReference( request.Project.Name, request.Project.FilePath, request.ExternalProjects.Select(p => p.Name)); } context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new PackageSpecReferenceDependencyProvider(projectResolver, exterenalProjectReference))); 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>(); var frameworkTasks = new List <Task <RestoreTargetGraph> >(); foreach (var framework in frameworks) { frameworkTasks.Add(WalkDependencies(projectRange, framework, remoteWalker, context)); } graphs.AddRange(await Task.WhenAll(frameworkTasks)); 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) { var runtimeTasks = new List <Task <RestoreTargetGraph[]> >(); foreach (var graph in graphs) { runtimeTasks.Add(WalkRuntimeDependencies(projectRange, graph, request.Project.RuntimeGraph, remoteWalker, context, localRepository)); } foreach (var runtimeSpecificGraphs in await Task.WhenAll(runtimeTasks)) { 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); // Generate Targets/Props files WriteTargetsAndProps(request.Project, graphs, repository); return(new RestoreResult(true, graphs, lockFile)); }