public DependencyNode transformGraph()

in maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java [181:275]


    public DependencyNode transformGraph(DependencyNode node, DependencyGraphTransformationContext context)
            throws RepositoryException {
        requireNonNull(node, "node cannot be null");
        requireNonNull(context, "context cannot be null");
        List<?> sortedConflictIds = (List<?>) context.get(TransformationContextKeys.SORTED_CONFLICT_IDS);
        if (sortedConflictIds == null) {
            ConflictIdSorter sorter = new ConflictIdSorter();
            sorter.transformGraph(node, context);

            sortedConflictIds = (List<?>) context.get(TransformationContextKeys.SORTED_CONFLICT_IDS);
        }

        @SuppressWarnings("unchecked")
        Map<String, Object> stats = (Map<String, Object>) context.get(TransformationContextKeys.STATS);
        long time1 = System.nanoTime();

        @SuppressWarnings("unchecked")
        Collection<Collection<?>> conflictIdCycles =
                (Collection<Collection<?>>) context.get(TransformationContextKeys.CYCLIC_CONFLICT_IDS);
        if (conflictIdCycles == null) {
            throw new RepositoryException("conflict id cycles have not been identified");
        }

        Map<?, ?> conflictIds = (Map<?, ?>) context.get(TransformationContextKeys.CONFLICT_IDS);
        if (conflictIds == null) {
            throw new RepositoryException("conflict groups have not been identified");
        }

        Map<Object, Collection<Object>> cyclicPredecessors = new HashMap<>();
        for (Collection<?> cycle : conflictIdCycles) {
            for (Object conflictId : cycle) {
                Collection<Object> predecessors = cyclicPredecessors.computeIfAbsent(conflictId, k -> new HashSet<>());
                predecessors.addAll(cycle);
            }
        }

        State state = new State(node, conflictIds, sortedConflictIds.size(), context);
        for (Iterator<?> it = sortedConflictIds.iterator(); it.hasNext(); ) {
            Object conflictId = it.next();

            // reset data structures for next graph walk
            state.prepare(conflictId, cyclicPredecessors.get(conflictId));

            // find nodes with the current conflict id and while walking the graph (more deeply), nuke leftover losers
            gatherConflictItems(node, state);

            // now that we know the min depth of the parents, update depth of conflict items
            state.finish();

            // earlier runs might have nuked all parents of the current conflict id, so it might not exist anymore
            if (!state.items.isEmpty()) {
                ConflictContext ctx = state.conflictCtx;
                state.versionSelector.selectVersion(ctx);
                if (ctx.winner == null) {
                    throw new RepositoryException("conflict resolver did not select winner among " + state.items);
                }
                DependencyNode winner = ctx.winner.node;

                state.scopeSelector.selectScope(ctx);
                if (Verbosity.NONE != state.verbosity) {
                    winner.setData(
                            NODE_DATA_ORIGINAL_SCOPE, winner.getDependency().getScope());
                }
                winner.setScope(ctx.scope);

                state.optionalitySelector.selectOptionality(ctx);
                if (Verbosity.NONE != state.verbosity) {
                    winner.setData(
                            NODE_DATA_ORIGINAL_OPTIONALITY,
                            winner.getDependency().isOptional());
                }
                winner.setOptional(ctx.optional);

                removeLosers(state);
            }

            // record the winner so we can detect leftover losers during future graph walks
            state.winner();

            // in case of cycles, trigger final graph walk to ensure all leftover losers are gone
            if (!it.hasNext() && !conflictIdCycles.isEmpty() && state.conflictCtx.winner != null) {
                DependencyNode winner = state.conflictCtx.winner.node;
                state.prepare(state, null);
                gatherConflictItems(winner, state);
            }
        }

        if (stats != null) {
            long time2 = System.nanoTime();
            stats.put("ConflictResolver.totalTime", time2 - time1);
            stats.put("ConflictResolver.conflictItemCount", state.totalConflictItems);
        }

        return node;
    }