1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.util.graph.visitor;
20
21 import java.util.ArrayDeque;
22 import java.util.Deque;
23 import java.util.Iterator;
24 import java.util.function.Consumer;
25
26 import org.eclipse.aether.artifact.Artifact;
27 import org.eclipse.aether.graph.Dependency;
28 import org.eclipse.aether.graph.DependencyNode;
29 import org.eclipse.aether.graph.DependencyVisitor;
30 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
31 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
32 import org.eclipse.aether.util.graph.transformer.ConflictResolver;
33
34 import static java.util.Objects.requireNonNull;
35
36
37
38
39
40
41
42 public class DependencyGraphDumper implements DependencyVisitor {
43
44 private final Consumer<String> consumer;
45
46 private final Deque<DependencyNode> nodes = new ArrayDeque<>();
47
48 public DependencyGraphDumper(Consumer<String> consumer) {
49 this.consumer = requireNonNull(consumer);
50 }
51
52 @Override
53 public boolean visitEnter(DependencyNode node) {
54 nodes.push(node);
55 consumer.accept(formatLine(nodes));
56 return true;
57 }
58
59 @Override
60 public boolean visitLeave(DependencyNode node) {
61 if (!nodes.isEmpty()) {
62 nodes.pop();
63 }
64 return true;
65 }
66
67 protected String formatLine(Deque<DependencyNode> nodes) {
68 return formatIndentation(nodes) + formatNode(nodes);
69 }
70
71 protected String formatIndentation(Deque<DependencyNode> nodes) {
72 StringBuilder buffer = new StringBuilder(128);
73 Iterator<DependencyNode> iter = nodes.descendingIterator();
74 DependencyNode parent = iter.hasNext() ? iter.next() : null;
75 DependencyNode child = iter.hasNext() ? iter.next() : null;
76 while (parent != null && child != null) {
77 boolean lastChild = parent.getChildren().get(parent.getChildren().size() - 1) == child;
78 boolean end = child == nodes.peekFirst();
79 String indent;
80 if (end) {
81 indent = lastChild ? "\\- " : "+- ";
82 } else {
83 indent = lastChild ? " " : "| ";
84 }
85 buffer.append(indent);
86 parent = child;
87 child = iter.hasNext() ? iter.next() : null;
88 }
89 return buffer.toString();
90 }
91
92 protected String formatNode(Deque<DependencyNode> nodes) {
93 DependencyNode node = requireNonNull(nodes.peek(), "bug: should not happen");
94 StringBuilder buffer = new StringBuilder(128);
95 Artifact a = node.getArtifact();
96 buffer.append(a);
97 Dependency d = node.getDependency();
98 if (d != null && !d.getScope().isEmpty()) {
99 buffer.append(" [").append(d.getScope());
100 if (d.isOptional()) {
101 buffer.append(", optional");
102 }
103 buffer.append("]");
104 }
105 String premanaged = DependencyManagerUtils.getPremanagedVersion(node);
106 if (premanaged != null && !premanaged.equals(a.getBaseVersion())) {
107 buffer.append(" (version managed from ").append(premanaged).append(")");
108 }
109
110 premanaged = DependencyManagerUtils.getPremanagedScope(node);
111 if (premanaged != null && d != null && !premanaged.equals(d.getScope())) {
112 buffer.append(" (scope managed from ").append(premanaged).append(")");
113 }
114 DependencyNode winner = (DependencyNode) node.getData().get(ConflictResolver.NODE_DATA_WINNER);
115 if (winner != null) {
116 if (ArtifactIdUtils.equalsId(a, winner.getArtifact())) {
117 buffer.append(" (nearer exists)");
118 } else {
119 Artifact w = winner.getArtifact();
120 buffer.append(" (conflicts with ");
121 if (ArtifactIdUtils.toVersionlessId(a).equals(ArtifactIdUtils.toVersionlessId(w))) {
122 buffer.append(w.getVersion());
123 } else {
124 buffer.append(w);
125 }
126 buffer.append(")");
127 }
128 }
129 return buffer.toString();
130 }
131 }