예제 #1
0
        /// <summary>
        /// Accounts for using the restore commands on 2 projects living in the same path
        /// </summary>
        private bool VerifyAssetsFileMatchesProject()
        {
            if (_request.Project.RestoreMetadata.ProjectStyle == ProjectStyle.DotnetCliTool)
            {
                return(true);
            }
            var pathComparer = PathUtility.GetStringComparerBasedOnOS();

            return(_request.ExistingLockFile != null && pathComparer.Equals(_request.ExistingLockFile.PackageSpec.FilePath, _request.Project.FilePath));
        }
예제 #2
0
        /// <summary>
        /// Create restore requests but do not execute them.
        /// </summary>
        public static async Task <IReadOnlyList <RestoreSummaryRequest> > GetRequests(RestoreArgs restoreContext)
        {
            // Get requests
            var requests = new List <RestoreSummaryRequest>();

            var inputs = new List <string>(restoreContext.Inputs);

            // If there are no inputs, use the current directory
            if (restoreContext.PreLoadedRequestProviders.Count < 1 && !inputs.Any())
            {
                inputs.Add(Path.GetFullPath("."));
            }

            var uniqueRequest = new HashSet <string>(PathUtility.GetStringComparerBasedOnOS());

            // Create requests
            // Pre-loaded requests
            foreach (var request in await CreatePreLoadedRequests(restoreContext))
            {
                // De-dupe requests
                if (request.Request.LockFilePath == null ||
                    uniqueRequest.Add(request.Request.LockFilePath))
                {
                    requests.Add(request);
                }
            }

            // Input based requests
            foreach (var input in inputs)
            {
                var inputRequests = await CreateRequests(input, restoreContext);

                if (inputRequests.Count == 0)
                {
                    // No need to throw here - the situation is harmless, and we want to report all possible
                    // inputs that don't resolve to a project.
                    var message = string.Format(
                        CultureInfo.CurrentCulture,
                        Strings.Error_UnableToLocateRestoreTarget,
                        Path.GetFullPath(input));

                    await restoreContext.Log.LogAsync(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1501, message));
                }
                foreach (var request in inputRequests)
                {
                    // De-dupe requests
                    if (uniqueRequest.Add(request.Request.LockFilePath))
                    {
                        requests.Add(request);
                    }
                }
            }

            return(requests);
        }
예제 #3
0
        private static void AddProjectReferences(PackageSpec spec, IEnumerable <IMSBuildItem> items)
        {
            // Add groups for each spec framework
            var aliasGroups = new Dictionary <string, List <ProjectRestoreReference> >();

            foreach (string alias in spec.TargetFrameworks.Select(e => e.TargetAlias).Distinct())
            {
                aliasGroups.Add(alias, new List <ProjectRestoreReference>());
            }

            var flatReferences = GetItemByType(items, "ProjectReference")
                                 .Select(GetProjectRestoreReference);

            var comparer = PathUtility.GetStringComparerBasedOnOS();

            // Add project paths
            foreach (var frameworkPair in flatReferences)
            {
                // If no frameworks were given, apply to all
                var addToFrameworks = frameworkPair.Item1.Count == 0
                    ? aliasGroups.Keys.ToList()
                    : frameworkPair.Item1;

                foreach (var framework in addToFrameworks)
                {
                    List <ProjectRestoreReference> references;
                    if (aliasGroups.TryGetValue(framework, out references))
                    {
                        // Ensure unique
                        if (!references.Any(e => comparer.Equals(e.ProjectUniqueName, frameworkPair.Item2.ProjectUniqueName)))
                        {
                            references.Add(frameworkPair.Item2);
                        }
                    }
                }
            }

            // Add groups to spec
            foreach (KeyValuePair <string, List <ProjectRestoreReference> > frameworkPair in aliasGroups)
            {
                TargetFrameworkInformation targetFrameworkInformation = spec.TargetFrameworks.Single(e => e.TargetAlias.Equals(frameworkPair.Key, StringComparison.Ordinal));
                spec.RestoreMetadata.TargetFrameworks.Add(new ProjectRestoreMetadataFrameworkInfo(targetFrameworkInformation.FrameworkName)
                {
                    ProjectReferences = frameworkPair.Value,
                    TargetAlias       = targetFrameworkInformation.TargetAlias
                });
            }
        }
        /// <summary>
        /// Remove missing project dependencies. These are typically caused by
        /// non-NuGet projects which are missing the targets needed to walk them.
        /// Visual Studio ignores these projects so from the command line we should
        /// also. Build will fail with the appropriate errors for missing projects
        /// restore should not warn or message for this.
        /// </summary>
        public static void RemoveMissingProjects(DependencyGraphSpec graphSpec)
        {
            var existingProjects = new HashSet <string>(
                graphSpec.Projects.Select(e => e.RestoreMetadata.ProjectPath),
                PathUtility.GetStringComparerBasedOnOS());

            foreach (var project in graphSpec.Projects)
            {
                foreach (var framework in project.RestoreMetadata.TargetFrameworks)
                {
                    foreach (var projectReference in framework.ProjectReferences.ToArray())
                    {
                        if (!existingProjects.Contains(projectReference.ProjectPath))
                        {
                            framework.ProjectReferences.Remove(projectReference);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Convert MSBuild items to a DependencyGraphSpec.
        /// </summary>
        public static DependencyGraphSpec GetDependencySpec(IEnumerable <IMSBuildItem> items)
        {
            if (items == null)
            {
                throw new ArgumentNullException(nameof(items));
            }

            // Unique names created by the MSBuild restore target are project paths, these
            // can be different on case-insensitive file systems for the same project file.
            // To workaround this unique names should be compared based on the OS.
            var uniqueNameComparer = PathUtility.GetStringComparerBasedOnOS();

            var graphSpec         = new DependencyGraphSpec();
            var itemsById         = new Dictionary <string, List <IMSBuildItem> >(uniqueNameComparer);
            var restoreSpecs      = new HashSet <string>(uniqueNameComparer);
            var validForRestore   = new HashSet <string>(uniqueNameComparer);
            var projectPathLookup = new Dictionary <string, string>(uniqueNameComparer);
            var toolItems         = new List <IMSBuildItem>();

            // Sort items and add restore specs
            foreach (var item in items)
            {
                var projectUniqueName = item.GetProperty("ProjectUniqueName");

                if (item.IsType("restorespec"))
                {
                    restoreSpecs.Add(projectUniqueName);
                }
                else if (!string.IsNullOrEmpty(projectUniqueName))
                {
                    List <IMSBuildItem> idItems;
                    if (!itemsById.TryGetValue(projectUniqueName, out idItems))
                    {
                        idItems = new List <IMSBuildItem>(1);
                        itemsById.Add(projectUniqueName, idItems);
                    }

                    idItems.Add(item);
                }
            }

            // Add projects
            var validProjectSpecs = itemsById.Values.Select(GetPackageSpec).Where(e => e != null);

            foreach (var spec in validProjectSpecs)
            {
                // Keep track of all project path casings
                var uniqueName = spec.RestoreMetadata.ProjectUniqueName;
                if (uniqueName != null && !projectPathLookup.ContainsKey(uniqueName))
                {
                    projectPathLookup.Add(uniqueName, uniqueName);
                }

                var projectPath = spec.RestoreMetadata.ProjectPath;
                if (projectPath != null && !projectPathLookup.ContainsKey(projectPath))
                {
                    projectPathLookup.Add(projectPath, projectPath);
                }

                if (spec.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference ||
                    spec.RestoreMetadata.ProjectStyle == ProjectStyle.ProjectJson ||
                    spec.RestoreMetadata.ProjectStyle == ProjectStyle.DotnetCliTool ||
                    spec.RestoreMetadata.ProjectStyle == ProjectStyle.Standalone ||
                    spec.RestoreMetadata.ProjectStyle == ProjectStyle.DotnetToolReference)
                {
                    validForRestore.Add(spec.RestoreMetadata.ProjectUniqueName);
                }

                graphSpec.AddProject(spec);
            }

            // Fix project reference casings to match the original project on case insensitive file systems.
            NormalizePathCasings(projectPathLookup, graphSpec);

            // Remove references to projects that could not be read by restore.
            RemoveMissingProjects(graphSpec);

            // Add valid projects to restore section
            foreach (var projectUniqueName in restoreSpecs.Intersect(validForRestore))
            {
                graphSpec.AddRestore(projectUniqueName);
            }

            return(graphSpec);
        }
        public PackagesLockFile CreateNuGetLockFile(LockFile assetsFile)
        {
            var lockFile = new PackagesLockFile(GetPackagesLockFileVersion(assetsFile));

            var libraryLookup = assetsFile.Libraries.Where(e => e.Type == LibraryType.Package)
                                .ToDictionary(e => new PackageIdentity(e.Name, e.Version));

            foreach (var target in assetsFile.Targets)
            {
                var nuGettarget = new PackagesLockFileTarget()
                {
                    TargetFramework   = target.TargetFramework,
                    RuntimeIdentifier = target.RuntimeIdentifier
                };

                var framework = assetsFile.PackageSpec.TargetFrameworks.FirstOrDefault(
                    f => EqualityUtility.EqualsWithNullCheck(f.FrameworkName, target.TargetFramework));

                IEnumerable <LockFileTargetLibrary> libraries = target.Libraries;

                // check if this is RID-based graph then only add those libraries which differ from original TFM.
                if (!string.IsNullOrEmpty(target.RuntimeIdentifier))
                {
                    var onlyTFM = assetsFile.Targets.First(t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, target.TargetFramework));

                    libraries = target.Libraries.Where(lib => !onlyTFM.Libraries.Any(tfmLib => tfmLib.Equals(lib)));
                }

                foreach (var library in libraries.Where(e => e.Type == LibraryType.Package))
                {
                    var identity = new PackageIdentity(library.Name, library.Version);

                    var dependency = new LockFileDependency()
                    {
                        Id = library.Name,
                        ResolvedVersion = library.Version,
                        ContentHash     = libraryLookup[identity].Sha512,
                        Dependencies    = library.Dependencies
                    };

                    var framework_dep = framework?.Dependencies.FirstOrDefault(
                        dep => StringComparer.OrdinalIgnoreCase.Equals(dep.Name, library.Name));

                    CentralPackageVersion centralPackageVersion = null;
                    framework?.CentralPackageVersions.TryGetValue(library.Name, out centralPackageVersion);

                    if (framework_dep != null)
                    {
                        dependency.Type             = PackageDependencyType.Direct;
                        dependency.RequestedVersion = framework_dep.LibraryRange.VersionRange;
                    }

                    // The dgspec has a list of the direct dependencies and changes in the direct dependencies will invalidate the lock file
                    // A dgspec does not have information about transitive dependencies
                    // At the restore time the transitive dependencies could be pinned from central package version management file
                    // By marking them will allow to evaluate when to invalidate the packages.lock.json
                    // in cases that a central transitive version is updated, removed or added the lock file will be invalidated
                    else if (centralPackageVersion != null)
                    {
                        // This is a transitive dependency that is in the list of central dependencies.
                        dependency.Type             = PackageDependencyType.CentralTransitive;
                        dependency.RequestedVersion = centralPackageVersion.VersionRange;
                    }
                    else
                    {
                        dependency.Type = PackageDependencyType.Transitive;
                    }

                    nuGettarget.Dependencies.Add(dependency);
                }

                var projectFullPaths = assetsFile.Libraries
                                       .Where(l => l.Type == LibraryType.Project || l.Type == LibraryType.ExternalProject)
                                       .ToDictionary(l => new PackageIdentity(l.Name, l.Version), l => l.MSBuildProject);

                foreach (var projectReference in libraries.Where(e => e.Type == LibraryType.Project || e.Type == LibraryType.ExternalProject))
                {
                    var projectIdentity = new PackageIdentity(projectReference.Name, projectReference.Version);
                    var projectFullPath = projectFullPaths[projectIdentity];
                    var id = PathUtility.GetStringComparerBasedOnOS().Equals(Path.GetFileNameWithoutExtension(projectFullPath), projectReference.Name)
                        ? projectReference.Name.ToLowerInvariant()
                        : projectReference.Name;

                    var dependency = new LockFileDependency()
                    {
                        Id           = id,
                        Dependencies = projectReference.Dependencies,
                        Type         = PackageDependencyType.Project
                    };

                    nuGettarget.Dependencies.Add(dependency);
                }

                nuGettarget.Dependencies = nuGettarget.Dependencies.OrderBy(d => d.Type).ToList();

                lockFile.Targets.Add(nuGettarget);
            }

            return(lockFile);
        }
예제 #7
0
        public static void Log(ILogger logger, IReadOnlyList <RestoreSummary> restoreSummaries, bool logErrors = false)
        {
            if (restoreSummaries.Count == 0)
            {
                return;
            }

            var noOpCount   = 0;
            var feedsUsed   = new HashSet <string>();
            var configFiles = new HashSet <string>();
            var installed   = new Dictionary <string, int>(restoreSummaries.Count, PathUtility.GetStringComparerBasedOnOS());

            foreach (RestoreSummary restoreSummary in restoreSummaries)
            {
                if (restoreSummary.NoOpRestore)
                {
                    noOpCount++;
                }

                foreach (var feed in restoreSummary.FeedsUsed)
                {
                    feedsUsed.Add(feed);
                }

                foreach (var configFile in restoreSummary.ConfigFiles)
                {
                    configFiles.Add(configFile);
                }

                if (!string.IsNullOrEmpty(restoreSummary.InputPath))
                {
                    if (installed.ContainsKey(restoreSummary.InputPath))
                    {
                        installed[restoreSummary.InputPath] += restoreSummary.InstallCount;
                    }
                    else
                    {
                        installed[restoreSummary.InputPath] = restoreSummary.InstallCount;
                    }
                }
            }

            // This should only be true by nuget exe since it does not have msbuild logger
            if (logErrors)
            {
                // Display the errors summary
                foreach (var restoreSummary in restoreSummaries)
                {
                    // log errors
                    LogErrorsToConsole(
                        restoreSummary,
                        string.Format(CultureInfo.CurrentCulture, Strings.Log_ErrorSummary, restoreSummary.InputPath),
                        logger);
                }
            }

            // Display the information summary
            if (configFiles.Any())
            {
                logger.LogInformationSummary(string.Empty);
                logger.LogInformationSummary(Strings.Log_ConfigFileSummary);
                foreach (var configFile in configFiles)
                {
                    logger.LogInformationSummary($"    {configFile}");
                }
            }

            if (feedsUsed.Any())
            {
                logger.LogInformationSummary(string.Empty);
                logger.LogInformationSummary(Strings.Log_FeedsUsedSummary);
                foreach (var feedUsed in feedsUsed)
                {
                    logger.LogInformationSummary($"    {feedUsed}");
                }
            }

            if (installed.Any(i => i.Value > 0))
            {
                logger.LogInformationSummary(string.Empty);
                logger.LogInformationSummary(Strings.Log_InstalledSummary);
                foreach (var pair in installed.Where(i => i.Value > 0))
                {
                    logger.LogInformationSummary("    " + string.Format(
                                                     CultureInfo.CurrentCulture,
                                                     Strings.Log_InstalledSummaryCount,
                                                     pair.Value,
                                                     pair.Key));
                }
            }

            if (!RuntimeEnvironmentHelper.IsRunningInVisualStudio)
            {
                if (noOpCount == restoreSummaries.Count)
                {
                    logger.LogMinimal(Strings.Log_AllProjectsUpToDate);
                }
                else if (noOpCount > 0)
                {
                    logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectUpToDateSummary, noOpCount, restoreSummaries.Count));
                }
            }
        }
예제 #8
0
        public PackagesLockFile CreateNuGetLockFile(LockFile assetsFile)
        {
            var lockFile = new PackagesLockFile();

            var libraryLookup = assetsFile.Libraries.Where(e => e.Type == LibraryType.Package)
                                .ToDictionary(e => new PackageIdentity(e.Name, e.Version));

            foreach (var target in assetsFile.Targets)
            {
                var nuGettarget = new PackagesLockFileTarget()
                {
                    TargetFramework   = target.TargetFramework,
                    RuntimeIdentifier = target.RuntimeIdentifier
                };

                var framework = assetsFile.PackageSpec.TargetFrameworks.FirstOrDefault(
                    f => EqualityUtility.EqualsWithNullCheck(f.FrameworkName, target.TargetFramework));

                var libraries = target.Libraries;

                // check if this is RID-based graph then only add those libraries which differ from original TFM.
                if (!string.IsNullOrEmpty(target.RuntimeIdentifier))
                {
                    var onlyTFM = assetsFile.Targets.First(t => EqualityUtility.EqualsWithNullCheck(t.TargetFramework, target.TargetFramework));

                    libraries = target.Libraries.Where(lib => !onlyTFM.Libraries.Any(tfmLib => tfmLib.Equals(lib))).ToList();
                }

                foreach (var library in libraries.Where(e => e.Type == LibraryType.Package))
                {
                    var identity = new PackageIdentity(library.Name, library.Version);

                    var dependency = new LockFileDependency()
                    {
                        Id = library.Name,
                        ResolvedVersion = library.Version,
                        ContentHash     = libraryLookup[identity].Sha512,
                        Dependencies    = library.Dependencies
                    };

                    var framework_dep = framework?.Dependencies.FirstOrDefault(
                        dep => StringComparer.OrdinalIgnoreCase.Equals(dep.Name, library.Name));

                    if (framework_dep != null)
                    {
                        dependency.Type             = PackageDependencyType.Direct;
                        dependency.RequestedVersion = framework_dep.LibraryRange.VersionRange;
                    }
                    else
                    {
                        dependency.Type = PackageDependencyType.Transitive;
                    }

                    nuGettarget.Dependencies.Add(dependency);
                }

                var projectFullPaths = assetsFile.Libraries
                                       .Where(l => l.Type == LibraryType.Project || l.Type == LibraryType.ExternalProject)
                                       .ToDictionary(l => new PackageIdentity(l.Name, l.Version), l => l.MSBuildProject);

                foreach (var projectReference in libraries.Where(e => e.Type == LibraryType.Project || e.Type == LibraryType.ExternalProject))
                {
                    var projectIdentity = new PackageIdentity(projectReference.Name, projectReference.Version);
                    var projectFullPath = projectFullPaths[projectIdentity];
                    var id = PathUtility.GetStringComparerBasedOnOS().Equals(Path.GetFileNameWithoutExtension(projectFullPath), projectReference.Name)
                        ? projectReference.Name.ToLowerInvariant()
                        : projectReference.Name;

                    var dependency = new LockFileDependency()
                    {
                        Id           = id,
                        Dependencies = projectReference.Dependencies,
                        Type         = PackageDependencyType.Project
                    };

                    nuGettarget.Dependencies.Add(dependency);
                }

                nuGettarget.Dependencies = nuGettarget.Dependencies.OrderBy(d => d.Type).ToList();

                lockFile.Targets.Add(nuGettarget);
            }

            return(lockFile);
        }