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);
        }
Example #2
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)
            {
                WarningPropertiesCollection = new WarningPropertiesCollection()
                {
                    ProjectWideWarningProperties     = request.Project?.RestoreMetadata?.ProjectWideWarningProperties,
                    PackageSpecificWarningProperties = WarningPropertiesCollection.GetPackageSpecificWarningProperties(request.Project)
                }
            };

            _logger = collectorLogger;
        }
        private bool IsWarningSuppressed(ILogMessage message)
        {
            if (message.Level == LogLevel.Warning)
            {
                // If the WarningPropertiesCollection is present then test if the warning is suppressed in
                // project wide no warn
                if (WarningPropertiesCollection.ApplyProjectWideNoWarnProperties(message, warningProperties: WarningProperties))
                {
                    return(true);
                }
                else
                {
                    // Use packagereference warning properties only if the project does not suppress the warning
                    // In packagereference warning properties look at only the package specific ones as all properties are per package reference.
                    IPackLogMessage packLogMessage = message as IPackLogMessage;

                    if (packLogMessage != null)
                    {
                        return(PackageSpecificWarningProperties?.ApplyNoWarnProperties(packLogMessage) == true);
                    }
                }
            }

            return(false);
        }
        private bool IsWarningSuppressed(ILogMessage message)
        {
            if (message.Level == LogLevel.Warning)
            {
                return(WarningPropertiesCollection.ApplyProjectWideNoWarnProperties(message, warningProperties: WarningProperties));
            }

            return(false);
        }
        /// <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
                       ));
        }
Example #6
0
        public void Log(IRestoreLogMessage message)
        {
            // This will be true only when the Message is a Warning and should be suppressed.
            if (WarningPropertiesCollection == null || !WarningPropertiesCollection.ApplyWarningProperties(message))
            {
                if (string.IsNullOrEmpty(message.FilePath))
                {
                    message.FilePath = message.ProjectPath ?? ProjectPath;
                }

                if (CollectMessage(message.Level))
                {
                    _errors.Enqueue(message);
                }

                if (DisplayMessage(message))
                {
                    _innerLogger.Log(message);
                }
            }
        }
 /// <summary>
 /// This method upgrades the warning to an error if the project wide warning properties have set the code in WarningsAsErrors or
 /// set TreatWarningsAsErrors to true
 /// </summary>
 /// <param name="message">ILogMessage to be logged as an error or warning.</param>
 /// <returns>bool indicating if the message should be suppressed.</returns>
 private void UpgradeWarningToErrorIfNeeded(ILogMessage message)
 {
     WarningPropertiesCollection.ApplyProjectWideWarningsAsErrorProperties(message, WarningProperties);
 }
        /// <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);
        }