Example #1
0
        private static void WalkTreeCheckCycleAndNearestWins(CyclesAndDowngrades context, GraphNode <RemoteResolveResult> node)
        {
            // Cycle:
            //
            // A -> B -> A (cycle)
            //
            // Downgrade:
            //
            // A -> B -> C -> D 2.0 (downgrade)
            //        -> D 1.0
            //
            // Potential downgrades that turns out to not be downgrades:
            //
            // 1. This should never happen in practice since B would have never been valid to begin with.
            //
            //    A -> B -> C -> D 2.0
            //           -> D 1.0
            //      -> D 2.0
            //
            // 2. This occurs if none of the sources have version C 1.0 so C 1.0 is bumped up to C 2.0.
            //
            //   A -> B -> C 2.0
            //     -> C 1.0

            var cycles            = context.Cycles;
            var workingDowngrades = context.Downgrades;

            if (node.Disposition == Disposition.Cycle)
            {
                cycles.Add(node);

                // Remove this node from the tree so the nothing else evaluates this.
                // This is ok since we have a parent pointer and we can still print the path
                node.OuterNode.InnerNodes.Remove(node);

                return;
            }

            if (node.Disposition != Disposition.PotentiallyDowngraded)
            {
                return;
            }

            // REVIEW: This could probably be done in a single pass where we keep track
            // of what is nearer as we walk down the graph (BFS)
            for (var n = node.OuterNode; n != null; n = n.OuterNode)
            {
                var innerNodes = n.InnerNodes;
                var count      = innerNodes.Count;
                for (var i = 0; i < count; i++)
                {
                    var sideNode = innerNodes[i];
                    if (sideNode != node && StringComparer.OrdinalIgnoreCase.Equals(sideNode.Key.Name, node.Key.Name))
                    {
                        // Nodes that have no version range should be ignored as potential downgrades e.g. framework reference
                        if (sideNode.Key.VersionRange != null &&
                            node.Key.VersionRange != null &&
                            !RemoteDependencyWalker.IsGreaterThanOrEqualTo(sideNode.Key.VersionRange, node.Key.VersionRange))
                        {
                            // Is the resolved version actually within node's version range? This happen if there
                            // was a different request for a lower version of the library than this version range
                            // allows but no matching library was found, so the library is bumped up into this
                            // version range.
                            var resolvedVersion = sideNode?.Item?.Data?.Match?.Library?.Version;
                            if (resolvedVersion != null && node.Key.VersionRange.Satisfies(resolvedVersion))
                            {
                                continue;
                            }

                            workingDowngrades[node] = sideNode;
                        }
                        else
                        {
                            workingDowngrades.Remove(node);
                        }
                    }
                }
            }

            // Remove this node from the tree so the nothing else evaluates this.
            // This is ok since we have a parent pointer and we can still print the path
            node.OuterNode.InnerNodes.Remove(node);
        }
Example #2
0
        private static void CheckCycleAndNearestWins <TItem>(this GraphNode <TItem> root,
                                                             List <DowngradeResult <TItem> > downgrades,
                                                             List <GraphNode <TItem> > cycles)
        {
            // Cycle

            // A -> B -> A (cycle)

            // Downgrade

            // A -> B -> C -> D 2.0 (downgrage)
            //        -> D 1.0

            // Potential downgrade that turns out to not downgrade
            // This should never happen in practice since B would have never been valid to begin with.

            // A -> B -> C -> D 2.0
            //        -> D 1.0
            //   -> D 2.0

            var workingDowngrades = new Dictionary <GraphNode <TItem>, GraphNode <TItem> >();

            root.ForEach(node =>
            {
                if (node.Disposition == Disposition.Cycle)
                {
                    cycles.Add(node);

                    // Remove this node from the tree so the nothing else evaluates this.
                    // This is ok since we have a parent pointer and we can still print the path
                    node.OuterNode.InnerNodes.Remove(node);

                    return;
                }

                if (node.Disposition != Disposition.PotentiallyDowngraded)
                {
                    return;
                }

                // REVIEW: This could probably be done in a single pass where we keep track
                // of what is nearer as we walk down the graph (BFS)
                for (var n = node.OuterNode; n != null; n = n.OuterNode)
                {
                    foreach (var sideNode in n.InnerNodes)
                    {
                        if (sideNode != node && StringComparer.OrdinalIgnoreCase.Equals(sideNode.Key.Name, node.Key.Name))
                        {
                            // Nodes that have no version range should be ignored as potential downgrades e.g. framework reference
                            if (sideNode.Key.VersionRange != null &&
                                node.Key.VersionRange != null &&
                                !RemoteDependencyWalker.IsGreaterThanOrEqualTo(sideNode.Key.VersionRange, node.Key.VersionRange))
                            {
                                workingDowngrades[node] = sideNode;
                            }
                            else
                            {
                                workingDowngrades.Remove(node);
                            }
                        }
                    }
                }

                // Remove this node from the tree so the nothing else evaluates this.
                // This is ok since we have a parent pointer and we can still print the path
                node.OuterNode.InnerNodes.Remove(node);
            });

            downgrades.AddRange(workingDowngrades.Select(p => new DowngradeResult <TItem>
            {
                DowngradedFrom = p.Key,
                DowngradedTo   = p.Value
            }));
        }