Example #1
0
        public void LibraryDependencyTargetUtils_Parse(string input, LibraryDependencyTarget expected)
        {
            // Arrange & Act
            var actual = LibraryDependencyTargetUtils.Parse(input);

            // Assert
            Assert.Equal(expected, actual);
        }
Example #2
0
        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()
                    });
                }
            }
        }
Example #4
0
        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
                    });
                }
            }
        }
Example #5
0
        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);
        }
Example #6
0
        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);
        }