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; }
/// <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); }
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>()); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }