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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        /// <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);
        }
Пример #7
0
        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);
        }
Пример #9
0
        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));
        }