Пример #1
0
        public RestoreCommand(RestoreRequest request)
        {
            _request = request ?? throw new ArgumentNullException(nameof(request));

            // Validate the lock file version requested
            if (_request.LockFileVersion < 1 || _request.LockFileVersion > LockFileFormat.Version)
            {
                Debug.Fail($"Lock file version {_request.LockFileVersion} is not supported.");
                throw new ArgumentOutOfRangeException(nameof(_request.LockFileVersion));
            }

            var collectorLoggerHideWarningsAndErrors = request.Project.RestoreSettings.HideWarningsAndErrors ||
                                                       request.HideWarningsAndErrors;

            var collectorLogger = new RestoreCollectorLogger(_request.Log, collectorLoggerHideWarningsAndErrors)
            {
                ProjectPath = _request.Project.RestoreMetadata?.ProjectPath,
                WarningPropertiesCollection = new WarningPropertiesCollection()
                {
                    ProjectWideWarningProperties     = request.Project.RestoreMetadata?.ProjectWideWarningProperties,
                    PackageSpecificWarningProperties = PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(request.Project),
                    ProjectFrameworks = request.Project.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly()
                }
            };

            _logger = collectorLogger;
        }
Пример #2
0
        /// <summary>
        /// Indexes a PackageSpecificWarningProperties collection on framework.
        /// </summary>
        /// <param name="packageSpecificWarningProperties">PackageSpecificWarningProperties to be converted.</param>
        /// <returns>New dictionary containing the data of a PackageSpecificWarningProperties collection on framework.</returns>
        public static Dictionary <string, HashSet <NuGetLogCode> > ExtractPackageSpecificNoWarnForFramework(
            PackageSpecificWarningProperties packageSpecificWarningProperties,
            NuGetFramework framework)
        {
            Dictionary <string, HashSet <NuGetLogCode> > result = null;

            if (packageSpecificWarningProperties?.Properties != null && framework != null)
            {
                result = new Dictionary <string, HashSet <NuGetLogCode> >(StringComparer.OrdinalIgnoreCase);

                foreach (var codePair in packageSpecificWarningProperties.Properties)
                {
                    var code = codePair.Key;
                    var libraryCollection = codePair.Value;

                    foreach (var libraryPair in libraryCollection)
                    {
                        var libraryId  = libraryPair.Key;
                        var frameworks = libraryPair.Value;

                        if (frameworks.Contains(framework))
                        {
                            if (!result.TryGetValue(libraryId, out var codes))
                            {
                                codes             = new HashSet <NuGetLogCode>();
                                result[libraryId] = codes;
                            }
                            codes.Add(code);
                        }
                    }
                }
            }

            return(result);
        }
Пример #3
0
        private static WarningPropertiesCollection GetNodeWarningProperties(
            PackageSpec nodeProjectSpec,
            NuGetFramework framework,
            Dictionary <string, Dictionary <NuGetFramework, WarningPropertiesCollection> > warningPropertiesCache)
        {
            var key = nodeProjectSpec.RestoreMetadata.ProjectPath;

            if (!warningPropertiesCache.TryGetValue(key, out var frameworkCollection))
            {
                frameworkCollection
                    = new Dictionary <NuGetFramework, WarningPropertiesCollection>(new NuGetFrameworkFullComparer());

                warningPropertiesCache[key] = frameworkCollection;
            }

            if (!frameworkCollection.TryGetValue(framework, out var collection))
            {
                collection = new WarningPropertiesCollection(
                    nodeProjectSpec.RestoreMetadata?.ProjectWideWarningProperties,
                    PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(nodeProjectSpec, framework),
                    nodeProjectSpec.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly());

                frameworkCollection.Add(framework, collection);
            }

            return(collection);
        }
 public WarningPropertiesCollection(WarningProperties projectWideWarningProperties,
                                    PackageSpecificWarningProperties packageSpecificWarningProperties,
                                    IReadOnlyList <NuGetFramework> projectFrameworks)
 {
     ProjectWideWarningProperties     = projectWideWarningProperties;
     PackageSpecificWarningProperties = packageSpecificWarningProperties;
     ProjectFrameworks = projectFrameworks ?? new ReadOnlyCollection <NuGetFramework>(new List <NuGetFramework>());
 }
Пример #5
0
        /// <summary>
        /// Merge 2 PackageSpecificWarningProperties objects.
        /// This method will combine the warning properties from both the collections.
        /// </summary>
        /// <param name="first">First Object to be merged.</param>
        /// <param name="second">Second Object to be merged.</param>
        /// <returns>Returns a PackageSpecificWarningProperties with the combined warning properties.
        /// Will return the reference to one of the inputs if the other input is Null.
        /// Returns a Null if both the input properties are Null. </returns>
        public static PackageSpecificWarningProperties MergePackageSpecificWarningProperties(
            PackageSpecificWarningProperties first,
            PackageSpecificWarningProperties second)
        {
            PackageSpecificWarningProperties result = null;

            if (TryMergeNullObjects(first, second, out var merged))
            {
                result = merged;
            }
            else
            {
                result = new PackageSpecificWarningProperties();
                if (first.Properties != null)
                {
                    foreach (var codePair in first.Properties)
                    {
                        var code = codePair.Key;
                        var libraryCollection = codePair.Value;

                        foreach (var libraryPair in libraryCollection)
                        {
                            var libraryId  = libraryPair.Key;
                            var frameworks = libraryPair.Value;

                            result.AddRangeOfFrameworks(code, libraryId, frameworks);
                        }
                    }
                }

                if (second.Properties != null)
                {
                    foreach (var codePair in second.Properties)
                    {
                        var code = codePair.Key;
                        var libraryCollection = codePair.Value;

                        foreach (var libraryPair in libraryCollection)
                        {
                            var libraryId  = libraryPair.Key;
                            var frameworks = libraryPair.Value;

                            result.AddRangeOfFrameworks(code, libraryId, frameworks);
                        }
                    }
                }
            }

            return(result);
        }
Пример #6
0
        /// <summary>
        /// Creates a PackageSpecificWarningProperties for a project generated by traversing the dependency graph.
        /// </summary>
        /// <param name="targetGraphs">Parent project restore target graphs.</param>
        /// <param name="parentProjectSpec">PackageSpec of the parent project.</param>
        /// <returns>WarningPropertiesCollection with the project frameworks and the transitive package specific no warn properties.</returns>
        public static WarningPropertiesCollection CreateTransitiveWarningPropertiesCollection(
            IEnumerable <RestoreTargetGraph> targetGraphs,
            PackageSpec parentProjectSpec)
        {
            var transitivePackageSpecificProperties = new PackageSpecificWarningProperties();
            var projectFrameworks       = new List <NuGetFramework>();
            var parentWarningProperties = new WarningPropertiesCollection(
                parentProjectSpec.RestoreMetadata?.ProjectWideWarningProperties,
                PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(parentProjectSpec),
                parentProjectSpec.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly());

            var parentPackageSpecifcNoWarn = ExtractPackageSpecificNoWarnPerFramework(
                parentWarningProperties.PackageSpecificWarningProperties);

            var warningPropertiesCache = new Dictionary <string, Dictionary <NuGetFramework, WarningPropertiesCollection> >(
                StringComparer.OrdinalIgnoreCase);

            foreach (var targetGraph in targetGraphs)
            {
                if (string.IsNullOrEmpty(targetGraph.RuntimeIdentifier))
                {
                    if (parentPackageSpecifcNoWarn == null ||
                        !parentPackageSpecifcNoWarn.TryGetValue(targetGraph.Framework, out var parentPackageSpecificNoWarnForFramework))
                    {
                        parentPackageSpecificNoWarnForFramework = null;
                    }

                    var transitiveNoWarnFromTargetGraph = ExtractTransitiveNoWarnProperties(
                        targetGraph,
                        parentProjectSpec.RestoreMetadata.ProjectName,
                        parentWarningProperties.ProjectWideWarningProperties.NoWarn.AsHashSet(),
                        parentPackageSpecificNoWarnForFramework,
                        warningPropertiesCache);

                    projectFrameworks.Add(targetGraph.Framework);

                    transitivePackageSpecificProperties = MergePackageSpecificWarningProperties(
                        transitivePackageSpecificProperties,
                        transitiveNoWarnFromTargetGraph);
                }
            }

            return(new WarningPropertiesCollection(
                       projectWideWarningProperties: null,
                       packageSpecificWarningProperties: transitivePackageSpecificProperties,
                       projectFrameworks: projectFrameworks
                       ));
        }
        /// <summary>
        /// Extracts PackageSpecific WarningProperties from a PackageSpec
        /// </summary>
        /// <param name="packageSpec">PackageSpec containing the Dependencies with WarningProperties</param>
        /// <returns>PackageSpecific WarningProperties extracted from a PackageSpec</returns>
        public static PackageSpecificWarningProperties GetPackageSpecificWarningProperties(PackageSpec packageSpec)
        {
            // NuGetLogCode -> LibraryId -> Set of Frameworks.
            var warningProperties = new PackageSpecificWarningProperties();

            foreach (var dependency in packageSpec.Dependencies)
            {
                warningProperties.AddRange(dependency.NoWarn, dependency.Name);
            }

            foreach (var framework in packageSpec.TargetFrameworks)
            {
                foreach (var dependency in framework.Dependencies)
                {
                    warningProperties.AddRange(dependency.NoWarn, dependency.Name, framework.FrameworkName);
                }
            }

            return(warningProperties);
        }
Пример #8
0
        /// <summary>
        /// Indexes a PackageSpecificWarningProperties collection on framework.
        /// </summary>
        /// <param name="packageSpecificWarningProperties">PackageSpecificWarningProperties to be converted.</param>
        /// <returns>New dictionary containing the data of a PackageSpecificWarningProperties collection on framework.</returns>
        public static Dictionary <NuGetFramework, Dictionary <string, HashSet <NuGetLogCode> > > ExtractPackageSpecificNoWarnPerFramework(
            PackageSpecificWarningProperties packageSpecificWarningProperties)
        {
            Dictionary <NuGetFramework, Dictionary <string, HashSet <NuGetLogCode> > > result = null;

            if (packageSpecificWarningProperties?.Properties != null)
            {
                result = new Dictionary <NuGetFramework, Dictionary <string, HashSet <NuGetLogCode> > >(new NuGetFrameworkFullComparer());

                foreach (var codePair in packageSpecificWarningProperties.Properties)
                {
                    var code = codePair.Key;
                    var libraryCollection = codePair.Value;

                    foreach (var libraryPair in libraryCollection)
                    {
                        var libraryId  = libraryPair.Key;
                        var frameworks = libraryPair.Value;

                        foreach (var framework in frameworks)
                        {
                            if (!result.TryGetValue(framework, out var frameworkCollection))
                            {
                                frameworkCollection = new Dictionary <string, HashSet <NuGetLogCode> >(StringComparer.OrdinalIgnoreCase);

                                result[framework] = frameworkCollection;
                            }

                            if (!frameworkCollection.TryGetValue(libraryId, out var codes))
                            {
                                codes = new HashSet <NuGetLogCode>();
                                frameworkCollection[libraryId] = codes;
                            }

                            codes.Add(code);
                        }
                    }
                }
            }
            return(result);
        }
Пример #9
0
        /// <summary>
        /// Traverses a Dependency graph starting from the parent project in BF style.
        /// </summary>
        /// <param name="targetGraph">Parent project restore target graph.</param>
        /// <param name="parentProjectName">File path of the parent project.</param>
        /// <param name="parentProjectWideNoWarn">Project Wide NoWarn properties of the parent project.</param>
        /// <param name="parentPackageSpecificNoWarn">Package Specific NoWarn properties of the parent project.</param>
        /// <returns>PackageSpecificWarningProperties containing all the NoWarn's for each package seen in the graph accumulated while traversing the graph.</returns>
        private static PackageSpecificWarningProperties ExtractTransitiveNoWarnProperties(
            RestoreTargetGraph targetGraph,
            string parentProjectName,
            HashSet <NuGetLogCode> parentProjectWideNoWarn,
            Dictionary <string, HashSet <NuGetLogCode> > parentPackageSpecificNoWarn,
            Dictionary <string, Dictionary <NuGetFramework, WarningPropertiesCollection> > warningPropertiesCache)
        {
            var dependencyMapping = new Dictionary <string, LookUpNode>(StringComparer.OrdinalIgnoreCase);
            var queue             = new Queue <DependencyNode>();
            var seen = new Dictionary <string, NodeWarningProperties>(StringComparer.OrdinalIgnoreCase);
            var resultWarningProperties = new PackageSpecificWarningProperties();
            var packageNoWarn           = new Dictionary <string, HashSet <NuGetLogCode> >(StringComparer.OrdinalIgnoreCase);

            // All the packages in parent project's closure.
            // Once we have collected data for all of these, we can exit.
            var parentPackageDependencies = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            var parentTargetFramework = targetGraph.Framework;

            // Add all dependencies into a dict for a quick transitive lookup
            foreach (var dependencyGraphItem in targetGraph.Flattened)
            {
                WarningPropertiesCollection nodeWarningProperties = null;
                HashSet <NuGetLogCode>      nodeProjectWideNoWarn = null;
                Dictionary <string, HashSet <NuGetLogCode> > nodePackageSpecificNoWarn = null;

                if (IsProject(dependencyGraphItem.Key.Type))
                {
                    var localMatch       = (LocalMatch)dependencyGraphItem.Data.Match;
                    var nodeProjectSpec  = GetNodePackageSpec(localMatch);
                    var nearestFramework = nodeProjectSpec.GetTargetFramework(parentTargetFramework).FrameworkName;

                    if (nearestFramework != null)
                    {
                        // Get the WarningPropertiesCollection from the PackageSpec
                        nodeWarningProperties = GetNodeWarningProperties(nodeProjectSpec, nearestFramework, warningPropertiesCache);

                        nodeProjectWideNoWarn = nodeWarningProperties.ProjectWideWarningProperties.NoWarn.AsHashSet();

                        var nodePackageSpecificWarningProperties = ExtractPackageSpecificNoWarnForFramework(
                            nodeWarningProperties.PackageSpecificWarningProperties,
                            nearestFramework);

                        if (nodePackageSpecificWarningProperties != null)
                        {
                            nodePackageSpecificNoWarn = nodePackageSpecificWarningProperties;
                        }
                    }
                }
                else
                {
                    parentPackageDependencies.Add(dependencyGraphItem.Key.Name);
                }

                var lookUpNode = new LookUpNode()
                {
                    Dependencies          = dependencyGraphItem.Data.Dependencies,
                    NodeWarningProperties = NodeWarningProperties.Create(nodeProjectWideNoWarn, nodePackageSpecificNoWarn)
                };

                dependencyMapping[dependencyGraphItem.Key.Name] = lookUpNode;
            }

            // Get the direct dependencies for the parent project to seed the queue
            var parentDependencies = dependencyMapping[parentProjectName];

            // Seed the queue with the parent project's direct dependencies
            var parentNoWarn = NodeWarningProperties.Create(parentProjectWideNoWarn, parentPackageSpecificNoWarn);

            AddDependenciesToQueue(parentDependencies.Dependencies,
                                   queue,
                                   parentNoWarn);

            // Add the parent project to the seen set to prevent adding it back to the queue
            AddToSeen(seen, new DependencyNode(id: parentProjectName, isProject: true, parentNoWarn));

            // start taking one node from the queue and get all of it's dependencies
            while (queue.Count > 0)
            {
                var node = queue.Dequeue();

                // Check if the node has already been visited, or if the node is a NoWarn superset of
                // an existing node. If this is a superset it will not provide any new paths where a
                // warning should be shown.
                if (AddToSeen(seen, node) && dependencyMapping.TryGetValue(node.Id, out var nodeLookUp))
                {
                    var nodeId        = node.Id;
                    var nodeIsProject = node.IsProject;

                    var nodeDependencies      = nodeLookUp.Dependencies;
                    var pathWarningProperties = node.NodeWarningProperties;

                    // If the node is a project then we need to extract the warning properties and
                    // add those to the warning properties of the current path.
                    if (nodeIsProject)
                    {
                        // Merge the node's no warn properties with the one in the path.
                        NodeWarningProperties nodeWarningProperties = nodeLookUp.NodeWarningProperties;
                        AddDependenciesToQueue(nodeDependencies,
                                               queue,
                                               nodeWarningProperties.Merge(node.NodeWarningProperties));
                    }
                    else if (parentPackageDependencies.Contains(nodeId))
                    {
                        // Evaluate the current path for package properties
                        var packageNoWarnFromPath = pathWarningProperties.ExtractPathNoWarnProperties(nodeId);
                        if (packageNoWarn.TryGetValue(nodeId, out var noWarnCodes))
                        {
                            // We have seen atleast one path which contained a NoWarn for the package
                            // We need to update the
                            noWarnCodes.IntersectWith(packageNoWarnFromPath);
                        }
                        else
                        {
                            noWarnCodes = packageNoWarnFromPath;
                            packageNoWarn.Add(nodeId, noWarnCodes);
                        }

                        // Check if there was any NoWarn in the path
                        if (noWarnCodes.Count == 0)
                        {
                            // If the path does not "NoWarn" for this package then remove the path from parentPackageDependencies
                            // This is done because if there are no "NoWarn" in one path, the the warnings must come through
                            // We no longer care about this package in the graph
                            parentPackageDependencies.Remove(nodeId);

                            // If parentPackageDependencies is empty then exit the graph traversal
                            if (parentPackageDependencies.Count == 0)
                            {
                                break;
                            }
                        }

                        AddDependenciesToQueue(nodeDependencies,
                                               queue,
                                               pathWarningProperties);
                    }
                }
            }

            // At the end of the graph traversal add the remaining package no warn lists into the result
            foreach (var packageId in packageNoWarn.Keys)
            {
                resultWarningProperties.AddRangeOfCodes(packageNoWarn[packageId], packageId, parentTargetFramework);
            }

            return(resultWarningProperties);
        }