public void LibraryDependencyTargetUtils_Parse(string input, LibraryDependencyTarget expected) { // Arrange & Act var actual = LibraryDependencyTargetUtils.Parse(input); // Assert Assert.Equal(expected, actual); }
private static void WalkTreeDectectConflicts <TItem>(GraphNode <TItem> node, ConflictsAndAccepted <TItem> context) { if (node.Disposition != Disposition.Accepted) { return; } var versionConflicts = context.VersionConflicts; var acceptedLibraries = context.AcceptedLibraries; // For all accepted nodes, find dependencies that aren't satisfied by the version // of the package that we have selected var innerNodes = node.InnerNodes; var count = innerNodes.Count; for (var i = 0; i < count; i++) { var childNode = innerNodes[i]; GraphNode <TItem> acceptedNode; if (acceptedLibraries.TryGetValue(childNode.Key.Name, out acceptedNode) && childNode != acceptedNode && childNode.Key.VersionRange != null && acceptedNode.Item.Key.Version != null) { var acceptedType = LibraryDependencyTargetUtils.Parse(acceptedNode.Item.Key.Type); var childType = childNode.Key.TypeConstraint; // Skip the check if a project reference override a package dependency // Check the type constraints, if there is any overlap check for conflict if ((acceptedType & (LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject)) == LibraryDependencyTarget.None && (childType & acceptedType) != LibraryDependencyTarget.None) { var versionRange = childNode.Key.VersionRange; var checkVersion = acceptedNode.Item.Key.Version; if (!versionRange.Satisfies(checkVersion)) { versionConflicts.Add(new VersionConflictResult <TItem> { Selected = acceptedNode, Conflicting = childNode }); } } } } }
private static void PopulateDependencies( string packageSpecPath, IList <LibraryDependency> results, JObject settings, string propertyName, bool isGacOrFrameworkReference) { var dependencies = settings[propertyName] as JObject; if (dependencies != null) { foreach (var dependency in dependencies) { if (string.IsNullOrEmpty(dependency.Key)) { throw FileFormatException.Create( "Unable to resolve dependency ''.", dependency.Value, packageSpecPath); } // Support // "dependencies" : { // "Name" : "1.0" // } var dependencyValue = dependency.Value; var dependencyTypeValue = LibraryDependencyType.Default; var dependencyIncludeFlagsValue = LibraryIncludeFlags.All; var dependencyExcludeFlagsValue = LibraryIncludeFlags.None; var suppressParentFlagsValue = LibraryIncludeFlagUtils.DefaultSuppressParent; var noWarn = new List <NuGetLogCode>(); // This method handles both the dependencies and framework assembly sections. // Framework references should be limited to references. // Dependencies should allow everything but framework references. var targetFlagsValue = isGacOrFrameworkReference ? LibraryDependencyTarget.Reference : LibraryDependencyTarget.All & ~LibraryDependencyTarget.Reference; var autoReferenced = false; string dependencyVersionValue = null; var dependencyVersionToken = dependencyValue; if (dependencyValue.Type == JTokenType.String) { dependencyVersionValue = dependencyValue.Value <string>(); } else { if (dependencyValue.Type == JTokenType.Object) { dependencyVersionToken = dependencyValue["version"]; if (dependencyVersionToken != null && dependencyVersionToken.Type == JTokenType.String) { dependencyVersionValue = dependencyVersionToken.Value <string>(); } } IEnumerable <string> strings; if (TryGetStringEnumerable(dependencyValue["type"], out strings)) { dependencyTypeValue = LibraryDependencyType.Parse(strings); // Types are used at pack time, they should be translated to suppressParent to // provide a matching effect for project to project references. // This should be set before suppressParent is checked. if (!dependencyTypeValue.Contains(LibraryDependencyTypeFlag.BecomesNupkgDependency)) { suppressParentFlagsValue = LibraryIncludeFlags.All; } else if (dependencyTypeValue.Contains(LibraryDependencyTypeFlag.SharedFramework)) { dependencyIncludeFlagsValue = LibraryIncludeFlags.Build | LibraryIncludeFlags.Compile | LibraryIncludeFlags.Analyzers; } } if (TryGetStringEnumerable(dependencyValue["include"], out strings)) { dependencyIncludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); } if (TryGetStringEnumerable(dependencyValue["exclude"], out strings)) { dependencyExcludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); } if (TryGetStringEnumerable(dependencyValue["suppressParent"], out strings)) { // This overrides any settings that came from the type property. suppressParentFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); } noWarn = GetNuGetLogCodeEnumerableFromJArray(dependencyValue["noWarn"]) .ToList(); var targetToken = dependencyValue["target"]; if (targetToken != null) { var targetString = targetToken.Value <string>(); targetFlagsValue = LibraryDependencyTargetUtils.Parse(targetString); // Verify that the value specified is package, project, or external project if (!ValidateDependencyTarget(targetFlagsValue)) { var message = string.Format( CultureInfo.CurrentCulture, Strings.InvalidDependencyTarget, targetString); throw FileFormatException.Create(message, targetToken, packageSpecPath); } } autoReferenced = GetBoolOrFalse(dependencyValue, "autoReferenced", packageSpecPath); } VersionRange dependencyVersionRange = null; if (!string.IsNullOrEmpty(dependencyVersionValue)) { try { dependencyVersionRange = VersionRange.Parse(dependencyVersionValue); } catch (Exception ex) { throw FileFormatException.Create( ex, dependencyVersionToken, packageSpecPath); } } // Projects and References may have empty version ranges, Packages may not if (dependencyVersionRange == null) { if ((targetFlagsValue & LibraryDependencyTarget.Package) == LibraryDependencyTarget.Package) { throw FileFormatException.Create( new ArgumentException(Strings.MissingVersionOnDependency), dependency.Value, packageSpecPath); } else { // Projects and references with no version property allow all versions dependencyVersionRange = VersionRange.All; } } // the dependency flags are: Include flags - Exclude flags var includeFlags = dependencyIncludeFlagsValue & ~dependencyExcludeFlagsValue; results.Add(new LibraryDependency() { LibraryRange = new LibraryRange() { Name = dependency.Key, TypeConstraint = targetFlagsValue, VersionRange = dependencyVersionRange, }, Type = dependencyTypeValue, IncludeType = includeFlags, SuppressParent = suppressParentFlagsValue, AutoReferenced = autoReferenced, NoWarn = noWarn.ToList() }); } } }
private static void PopulateDependencies( string projectPath, IList <ProjectLibraryDependency> results, JObject settings, string propertyName, bool isGacOrFrameworkReference) { var dependencies = settings.Value <JToken>(propertyName) as JObject; if (dependencies != null) { foreach (var dependency in dependencies) { if (string.IsNullOrEmpty(dependency.Key)) { throw FileFormatException.Create( "Unable to resolve dependency ''.", dependency.Key, projectPath); } var dependencyValue = dependency.Value; var dependencyTypeValue = LibraryDependencyType.Default; var dependencyIncludeFlagsValue = LibraryIncludeFlags.All; var dependencyExcludeFlagsValue = LibraryIncludeFlags.None; var suppressParentFlagsValue = LibraryIncludeFlagUtils.DefaultSuppressParent; var target = isGacOrFrameworkReference ? LibraryDependencyTarget.Reference : LibraryDependencyTarget.All; string dependencyVersionAsString = null; if (dependencyValue.Type == JTokenType.Object) { // "dependencies" : { "Name" : { "version": "1.0", "type": "build", "target": "project" } } dependencyVersionAsString = dependencyValue.Value <string>("version"); var type = dependencyValue.Value <string>("type"); if (type != null) { dependencyTypeValue = LibraryDependencyType.Parse(new [] { type }); } // Read the target if specified if (!isGacOrFrameworkReference) { var targetStr = dependencyValue.Value <string>("target"); target = LibraryDependencyTargetUtils.Parse(targetStr); } IEnumerable <string> strings; if (TryGetStringEnumerable(dependencyValue["include"], out strings)) { dependencyIncludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); } if (TryGetStringEnumerable(dependencyValue["exclude"], out strings)) { dependencyExcludeFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); } if (TryGetStringEnumerable(dependencyValue["suppressParent"], out strings)) { // This overrides any settings that came from the type property. suppressParentFlagsValue = LibraryIncludeFlagUtils.GetFlags(strings); } } else if (dependencyValue.Type == JTokenType.String) { // "dependencies" : { "Name" : "1.0" } dependencyVersionAsString = dependencyValue.Value <string>(); } else { throw FileFormatException.Create( string.Format( "Invalid dependency version: {0}. The format is not recognizable.", dependency.Key), dependencyValue, projectPath); } VersionRange dependencyVersionRange = null; if (!string.IsNullOrEmpty(dependencyVersionAsString)) { try { dependencyVersionRange = VersionRange.Parse(dependencyVersionAsString); } catch (Exception ex) { throw FileFormatException.Create(ex, dependencyValue, projectPath); } } // the dependency flags are: Include flags - Exclude flags var includeFlags = dependencyIncludeFlagsValue & ~dependencyExcludeFlagsValue; var lineInfo = (IJsonLineInfo)dependencyValue; results.Add(new ProjectLibraryDependency { LibraryRange = new LibraryRange( dependency.Key, dependencyVersionRange, target), Type = dependencyTypeValue, IncludeType = includeFlags, SuppressParent = suppressParentFlagsValue, SourceFilePath = projectPath, SourceLine = lineInfo.LineNumber, SourceColumn = lineInfo.LinePosition }); } } }
private static bool TryResolveConflicts <TItem>(this GraphNode <TItem> root, List <VersionConflictResult <TItem> > versionConflicts) { // now we walk the tree as often as it takes to determine // which paths are accepted or rejected, based on conflicts occuring // between cousin packages var acceptedLibraries = new Dictionary <string, GraphNode <TItem> >(StringComparer.OrdinalIgnoreCase); var patience = 1000; var incomplete = true; while (incomplete && --patience != 0) { // Create a picture of what has not been rejected yet var tracker = new Tracker <TItem>(); root.ForEach(true, (node, state) => { if (!state || node.Disposition == Disposition.Rejected) { // Mark all nodes as rejected if they aren't already marked node.Disposition = Disposition.Rejected; return(false); } tracker.Track(node.Item); return(true); }); // Inform tracker of ambiguity beneath nodes that are not resolved yet // between: // a1->b1->d1->x1 // a1->c1->d2->z1 // first attempt // d1/d2 are considered disputed // x1 and z1 are considered ambiguous // d1 is rejected // second attempt // d1 is rejected, d2 is accepted // x1 is no longer seen, and z1 is not ambiguous // z1 is accepted root.ForEach(WalkState.Walking, (node, state) => { if (node.Disposition == Disposition.Rejected) { return(WalkState.Rejected); } if (state == WalkState.Walking && tracker.IsDisputed(node.Item)) { return(WalkState.Ambiguous); } if (state == WalkState.Ambiguous) { tracker.MarkAmbiguous(node.Item); } return(state); }); // Now mark unambiguous nodes as accepted or rejected root.ForEach(true, (node, state) => { if (!state || node.Disposition == Disposition.Rejected) { return(false); } if (tracker.IsAmbiguous(node.Item)) { return(false); } if (node.Disposition == Disposition.Acceptable) { if (tracker.IsBestVersion(node.Item)) { node.Disposition = Disposition.Accepted; acceptedLibraries[node.Key.Name] = node; } else { node.Disposition = Disposition.Rejected; } } return(node.Disposition == Disposition.Accepted); }); incomplete = false; root.ForEach(node => incomplete |= node.Disposition == Disposition.Acceptable); } root.ForEach(node => { if (node.Disposition != Disposition.Accepted) { return; } // For all accepted nodes, find dependencies that aren't satisfied by the version // of the package that we have selected foreach (var childNode in node.InnerNodes) { GraphNode <TItem> acceptedNode; if (acceptedLibraries.TryGetValue(childNode.Key.Name, out acceptedNode) && childNode != acceptedNode && childNode.Key.VersionRange != null && acceptedNode.Item.Key.Version != null) { var acceptedType = LibraryDependencyTargetUtils.Parse(acceptedNode.Item.Key.Type); var childType = childNode.Key.TypeConstraint; // Check the type constraints, if there is any overlap check for conflict if ((childType & acceptedType) != LibraryDependencyTarget.None) { var versionRange = childNode.Key.VersionRange; var checkVersion = acceptedNode.Item.Key.Version; if (!versionRange.Satisfies(checkVersion)) { versionConflicts.Add(new VersionConflictResult <TItem> { Selected = acceptedNode, Conflicting = childNode }); } } } } }); return(!incomplete); }
private async Task <RestoreTargetGraph> WalkDependenciesAsync(LibraryRange projectRange, NuGetFramework framework, string runtimeIdentifier, RuntimeGraph runtimeGraph, RemoteDependencyWalker walker, RemoteWalkContext context, bool writeToLockFile, CancellationToken token) { var name = FrameworkRuntimePair.GetName(framework, runtimeIdentifier); var graphs = new List <GraphNode <RemoteResolveResult> >(); if (_request.ExistingLockFile != null && _request.ExistingLockFile.IsLocked) { // Walk all the items in the lock file target and just synthesize the outer graph var target = _request.ExistingLockFile.GetTarget(framework, runtimeIdentifier); token.ThrowIfCancellationRequested(); if (target != null) { foreach (var targetLibrary in target.Libraries) { token.ThrowIfCancellationRequested(); var library = _request.ExistingLockFile.GetLibrary(targetLibrary.Name, targetLibrary.Version); if (library == null) { _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Log_LockFileMissingLibraryForTargetLibrary, targetLibrary.Name, targetLibrary.Version, target.Name)); continue; // This library is not in the main lockfile? } var range = new LibraryRange() { Name = library.Name, TypeConstraint = LibraryDependencyTargetUtils.Parse(library.Type), VersionRange = new VersionRange( minVersion: library.Version, includeMinVersion: true, maxVersion: library.Version, includeMaxVersion: true) }; graphs.Add(await walker.WalkAsync( range, framework, runtimeIdentifier, runtimeGraph, recursive: false)); } } } else { graphs.Add(await walker.WalkAsync( projectRange, framework, runtimeIdentifier, runtimeGraph, recursive: true)); } // Resolve conflicts _logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_ResolvingConflicts, name)); // Flatten and create the RestoreTargetGraph to hold the packages var result = RestoreTargetGraph.Create(writeToLockFile, runtimeGraph, graphs, context, _logger, framework, runtimeIdentifier); // Check if the dependencies got bumped up // ...but not if there is an existing locked lock file. if (_request.ExistingLockFile == null || !_request.ExistingLockFile.IsLocked) { // No lock file, OR the lock file is unlocked, so check dependencies CheckDependencies(result, _request.Project.Dependencies); var fxInfo = _request.Project.GetTargetFramework(framework); if (fxInfo != null) { CheckDependencies(result, fxInfo.Dependencies); } } return(result); }