1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.impl;
20
21 import java.io.PrintWriter;
22 import java.util.ArrayList;
23 import java.util.IdentityHashMap;
24 import java.util.Iterator;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.eclipse.aether.graph.Dependency;
30 import org.eclipse.aether.graph.DependencyNode;
31
32
33
34
35 public class DependencyGraphDumper {
36
37 public static void dump(PrintWriter writer, DependencyNode node) {
38 Context context = new Context();
39 dump(context, node, 0, true);
40
41 LinkedList<Indent> indents = new LinkedList<>();
42 for (Line line : context.lines) {
43 if (line.depth > indents.size()) {
44 if (!indents.isEmpty()) {
45 if (indents.getLast() == Indent.CHILD) {
46 indents.removeLast();
47 indents.addLast(Indent.CHILDREN);
48 } else if (indents.getLast() == Indent.LAST_CHILD) {
49 indents.removeLast();
50 indents.addLast(Indent.NO_CHILDREN);
51 }
52 }
53 indents.addLast(line.last ? Indent.LAST_CHILD : Indent.CHILD);
54 } else if (line.depth < indents.size()) {
55 while (line.depth <= indents.size()) {
56 indents.removeLast();
57 }
58 indents.addLast(line.last ? Indent.LAST_CHILD : Indent.CHILD);
59 } else if (line.last && !indents.isEmpty()) {
60 indents.removeLast();
61 indents.addLast(Indent.LAST_CHILD);
62 }
63
64 for (Indent indent : indents) {
65 writer.print(indent);
66 }
67
68 line.print(writer);
69 }
70
71 writer.flush();
72 }
73
74 private static void dump(Context context, DependencyNode node, int depth, boolean last) {
75 Line line = context.nodes.get(node);
76 if (line != null) {
77 if (line.id <= 0) {
78 line.id = ++context.ids;
79 }
80 context.lines.add(new Line(null, line.id, depth, last));
81 return;
82 }
83
84 Dependency dependency = node.getDependency();
85
86 if (dependency == null) {
87 line = new Line(null, 0, depth, last);
88 } else {
89 line = new Line(dependency, 0, depth, last);
90 }
91
92 context.lines.add(line);
93
94 context.nodes.put(node, line);
95
96 depth++;
97
98 for (Iterator<DependencyNode> it = node.getChildren().iterator(); it.hasNext(); ) {
99 DependencyNode child = it.next();
100 dump(context, child, depth, !it.hasNext());
101 }
102 }
103
104 enum Indent {
105 NO_CHILDREN(" "),
106
107 CHILDREN("| "),
108
109 CHILD("+- "),
110
111 LAST_CHILD("\\- ");
112
113 private final String chars;
114
115 Indent(String chars) {
116 this.chars = chars;
117 }
118
119 @Override
120 public String toString() {
121 return chars;
122 }
123 }
124
125 static class Context {
126
127 int ids;
128
129 List<Line> lines;
130
131 Map<DependencyNode, Line> nodes;
132
133 Context() {
134 this.lines = new ArrayList<>();
135 this.nodes = new IdentityHashMap<>(1024);
136 }
137 }
138
139 static class Line {
140
141 Dependency dependency;
142
143 int id;
144
145 int depth;
146
147 boolean last;
148
149 Line(Dependency dependency, int id, int depth, boolean last) {
150 this.dependency = dependency;
151 this.id = id;
152 this.depth = depth;
153 this.last = last;
154 }
155
156 void print(PrintWriter writer) {
157 if (dependency == null) {
158 if (id > 0) {
159 writer.print("^");
160 writer.print(id);
161 } else {
162 writer.print("(null)");
163 }
164 } else {
165 if (id > 0) {
166 writer.print("(");
167 writer.print(id);
168 writer.print(")");
169 }
170 writer.print(dependency.getArtifact());
171 if (!dependency.getScope().isEmpty()) {
172 writer.print(":");
173 writer.print(dependency.getScope());
174 }
175 }
176 writer.println();
177 }
178 }
179 }