Esempio n. 1
0
        private static WalkState WalkTreeMarkAmbiguousNodes <TItem>(GraphNode <TItem> node, WalkState state, Tracker <TItem> context)
        {
            // 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
            if (node.Disposition == Disposition.Rejected)
            {
                return(WalkState.Rejected);
            }

            if (state == WalkState.Walking &&
                context.IsDisputed(node.Item))
            {
                return(WalkState.Ambiguous);
            }

            if (state == WalkState.Ambiguous)
            {
                context.MarkAmbiguous(node.Item);
            }

            return(state);
        }
Esempio n. 2
0
        private static void DetectAndMarkAmbiguousCentralTransitiveDependencies <TItem>(Tracker <TItem> tracker, List <GraphNode <TItem> > centralTransitiveNodes)
        {
            // if a central transitive node has all parents disputed or ambiguous mark it and its children ambiguous
            int ctdCount = centralTransitiveNodes.Count;

            for (int i = 0; i < ctdCount; i++)
            {
                if (centralTransitiveNodes[i].Disposition == Disposition.Acceptable)
                {
                    bool allParentsAreDisputedOrAmbiguous = !centralTransitiveNodes[i].ParentNodes
                                                            .Any(p => p.Disposition != Disposition.Rejected && !(tracker.IsDisputed(p.Item) || tracker.IsAmbiguous(p.Item)));

                    if (allParentsAreDisputedOrAmbiguous)
                    {
                        // children of ambiguous nodes were already marked as ambiguous, skip them
                        centralTransitiveNodes[i].ForEach(x => tracker.MarkAmbiguous(x.Item), pn => tracker.IsAmbiguous(pn.Item));
                    }
                }
            }
            ;
        }
Esempio n. 3
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);
        }
Esempio n. 4
0
        public static bool TryResolveConflicts <TItem>(this GraphNode <TItem> root)
        {
            // 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 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)
                    {
                        node.Disposition = tracker.IsBestVersion(node.Item) ? Disposition.Accepted : Disposition.Rejected;
                    }

                    return(node.Disposition == Disposition.Accepted);
                });

                incomplete = false;

                root.ForEach(node => incomplete |= node.Disposition == Disposition.Acceptable);
            }

            return(!incomplete);
        }