1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.test.util;
20
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.io.InputStreamReader;
24 import java.io.StringReader;
25 import java.net.URL;
26 import java.nio.charset.StandardCharsets;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.LinkedList;
34 import java.util.List;
35 import java.util.Map;
36
37 import org.eclipse.aether.artifact.Artifact;
38 import org.eclipse.aether.artifact.DefaultArtifact;
39 import org.eclipse.aether.graph.DefaultDependencyNode;
40 import org.eclipse.aether.graph.Dependency;
41 import org.eclipse.aether.graph.DependencyNode;
42 import org.eclipse.aether.version.InvalidVersionSpecificationException;
43 import org.eclipse.aether.version.VersionScheme;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 public class DependencyGraphParser {
96
97 private final VersionScheme versionScheme;
98
99 private final String prefix;
100
101 private Collection<String> substitutions;
102
103
104
105
106
107
108 public DependencyGraphParser(String prefix, Collection<String> substitutions) {
109 this.prefix = prefix;
110 this.substitutions = substitutions;
111 versionScheme = new TestVersionScheme();
112 }
113
114
115
116
117
118
119 public DependencyGraphParser(String prefix) {
120 this(prefix, Collections.emptyList());
121 }
122
123
124
125
126 public DependencyGraphParser() {
127 this("");
128 }
129
130
131
132
133 public DependencyNode parseLiteral(String dependencyGraph) throws IOException {
134 try (BufferedReader reader = new BufferedReader(new StringReader(dependencyGraph))) {
135 return parse(reader);
136 }
137 }
138
139
140
141
142
143 public DependencyNode parseResource(String resource) throws IOException {
144 URL res = this.getClass().getClassLoader().getResource(prefix + resource);
145 if (res == null) {
146 throw new IOException("Could not find classpath resource " + prefix + resource);
147 }
148 return parse(res);
149 }
150
151
152
153
154 public List<DependencyNode> parseMultiResource(String resource) throws IOException {
155 URL res = this.getClass().getClassLoader().getResource(prefix + resource);
156 if (res == null) {
157 throw new IOException("Could not find classpath resource " + prefix + resource);
158 }
159
160 try (BufferedReader reader =
161 new BufferedReader(new InputStreamReader(res.openStream(), StandardCharsets.UTF_8))) {
162 List<DependencyNode> ret = new ArrayList<>();
163 DependencyNode root = null;
164 while ((root = parse(reader)) != null) {
165 ret.add(root);
166 }
167 return ret;
168 }
169 }
170
171
172
173
174 public DependencyNode parse(URL resource) throws IOException {
175 try (BufferedReader reader =
176 new BufferedReader(new InputStreamReader(resource.openStream(), StandardCharsets.UTF_8))) {
177 return parse(reader);
178 }
179 }
180
181 private DependencyNode parse(BufferedReader in) throws IOException {
182 Iterator<String> substitutionIterator = (substitutions != null) ? substitutions.iterator() : null;
183
184 String line = null;
185
186 DependencyNode root = null;
187 DependencyNode node = null;
188 int prevLevel = 0;
189
190 Map<String, DependencyNode> nodes = new HashMap<>();
191 LinkedList<DependencyNode> stack = new LinkedList<>();
192 boolean isRootNode = true;
193
194 while ((line = in.readLine()) != null) {
195 line = cutComment(line);
196
197 if (isEmpty(line)) {
198
199 continue;
200 }
201
202 if (isEOFMarker(line)) {
203
204 break;
205 }
206
207 while (line.contains("%s")) {
208 if (!substitutionIterator.hasNext()) {
209 throw new IllegalStateException("not enough substitutions to fill placeholders");
210 }
211 line = line.replaceFirst("%s", substitutionIterator.next());
212 }
213
214 LineContext ctx = createContext(line);
215 if (prevLevel < ctx.getLevel()) {
216
217 stack.add(node);
218 }
219
220
221 while (prevLevel > ctx.getLevel()) {
222 stack.removeLast();
223 prevLevel -= 1;
224 }
225
226 prevLevel = ctx.getLevel();
227
228 if (ctx.getDefinition() != null && ctx.getDefinition().reference != null) {
229 String reference = ctx.getDefinition().reference;
230 DependencyNode child = nodes.get(reference);
231 if (child == null) {
232 throw new IllegalStateException("undefined reference " + reference);
233 }
234 node.getChildren().add(child);
235 } else {
236
237 node = build(isRootNode ? null : stack.getLast(), ctx, isRootNode);
238
239 if (isRootNode) {
240 root = node;
241 isRootNode = false;
242 }
243
244 if (ctx.getDefinition() != null && ctx.getDefinition().id != null) {
245 nodes.put(ctx.getDefinition().id, node);
246 }
247 }
248 }
249
250 return root;
251 }
252
253 private boolean isEOFMarker(String line) {
254 return line.startsWith("---");
255 }
256
257 private static boolean isEmpty(String line) {
258 return line == null || line.isEmpty();
259 }
260
261 private static String cutComment(String line) {
262 int idx = line.indexOf('#');
263
264 if (idx != -1) {
265 line = line.substring(0, idx);
266 }
267
268 return line;
269 }
270
271 private DependencyNode build(DependencyNode parent, LineContext ctx, boolean isRoot) {
272 NodeDefinition def = ctx.getDefinition();
273 if (!isRoot && parent == null) {
274 throw new IllegalStateException("dangling node: " + def);
275 } else if (ctx.getLevel() == 0 && parent != null) {
276 throw new IllegalStateException("inconsistent leveling (parent for level 0?): " + def);
277 }
278
279 DefaultDependencyNode node;
280 if (def != null) {
281 DefaultArtifact artifact = new DefaultArtifact(def.coords, def.properties);
282 Dependency dependency = new Dependency(artifact, def.scope, def.optional);
283 node = new DefaultDependencyNode(dependency);
284 int managedBits = 0;
285 if (def.premanagedScope != null) {
286 managedBits |= DependencyNode.MANAGED_SCOPE;
287 node.setData("premanaged.scope", def.premanagedScope);
288 }
289 if (def.premanagedVersion != null) {
290 managedBits |= DependencyNode.MANAGED_VERSION;
291 node.setData("premanaged.version", def.premanagedVersion);
292 }
293 node.setManagedBits(managedBits);
294 if (def.relocations != null) {
295 List<Artifact> relocations = new ArrayList<>();
296 for (String relocation : def.relocations) {
297 relocations.add(new DefaultArtifact(relocation));
298 }
299 node.setRelocations(relocations);
300 }
301 try {
302 node.setVersion(versionScheme.parseVersion(artifact.getVersion()));
303 node.setVersionConstraint(
304 versionScheme.parseVersionConstraint(def.range != null ? def.range : artifact.getVersion()));
305 } catch (InvalidVersionSpecificationException e) {
306 throw new IllegalArgumentException("bad version: " + e.getMessage(), e);
307 }
308 } else {
309 node = new DefaultDependencyNode((Dependency) null);
310 }
311
312 if (parent != null) {
313 parent.getChildren().add(node);
314 }
315
316 return node;
317 }
318
319 public String dump(DependencyNode root) {
320 StringBuilder ret = new StringBuilder();
321
322 List<NodeEntry> entries = new ArrayList<>();
323
324 addNode(root, 0, entries);
325
326 for (NodeEntry nodeEntry : entries) {
327 char[] level = new char[(nodeEntry.getLevel() * 3)];
328 Arrays.fill(level, ' ');
329
330 if (level.length != 0) {
331 level[level.length - 3] = '+';
332 level[level.length - 2] = '-';
333 }
334
335 String definition = nodeEntry.getDefinition();
336
337 ret.append(level).append(definition).append("\n");
338 }
339
340 return ret.toString();
341 }
342
343 private void addNode(DependencyNode root, int level, List<NodeEntry> entries) {
344
345 NodeEntry entry = new NodeEntry();
346 Dependency dependency = root.getDependency();
347 StringBuilder defBuilder = new StringBuilder();
348 if (dependency == null) {
349 defBuilder.append("(null)");
350 } else {
351 Artifact artifact = dependency.getArtifact();
352
353 defBuilder
354 .append(artifact.getGroupId())
355 .append(":")
356 .append(artifact.getArtifactId())
357 .append(":")
358 .append(artifact.getExtension())
359 .append(":")
360 .append(artifact.getVersion());
361 if (dependency.getScope() != null && (!"".equals(dependency.getScope()))) {
362 defBuilder.append(":").append(dependency.getScope());
363 }
364
365 Map<String, String> properties = artifact.getProperties();
366 if (!(properties == null || properties.isEmpty())) {
367 for (Map.Entry<String, String> prop : properties.entrySet()) {
368 defBuilder.append(";").append(prop.getKey()).append("=").append(prop.getValue());
369 }
370 }
371 }
372
373 entry.setDefinition(defBuilder.toString());
374 entry.setLevel(level++);
375
376 entries.add(entry);
377
378 for (DependencyNode node : root.getChildren()) {
379 addNode(node, level, entries);
380 }
381 }
382
383 private static class NodeEntry {
384 int level;
385
386 String definition;
387
388 Map<String, String> properties;
389
390 public int getLevel() {
391 return level;
392 }
393
394 public void setLevel(int level) {
395 this.level = level;
396 }
397
398 public String getDefinition() {
399 return definition;
400 }
401
402 public void setDefinition(String definition) {
403 this.definition = definition;
404 }
405
406 public Map<String, String> getProperties() {
407 return properties;
408 }
409
410 public void setProperties(Map<String, String> properties) {
411 this.properties = properties;
412 }
413 }
414
415 private static LineContext createContext(String line) {
416 LineContext ctx = new LineContext();
417 String definition;
418
419 String[] split = line.split("- ");
420 if (split.length == 1)
421 {
422 ctx.setLevel(0);
423 definition = split[0];
424 } else {
425 ctx.setLevel((int) Math.ceil((double) split[0].length() / (double) 3));
426 definition = split[1];
427 }
428
429 if ("(null)".equalsIgnoreCase(definition)) {
430 return ctx;
431 }
432
433 ctx.setDefinition(new NodeDefinition(definition));
434
435 return ctx;
436 }
437
438 static class LineContext {
439 NodeDefinition definition;
440
441 int level;
442
443 public NodeDefinition getDefinition() {
444 return definition;
445 }
446
447 public void setDefinition(NodeDefinition definition) {
448 this.definition = definition;
449 }
450
451 public int getLevel() {
452 return level;
453 }
454
455 public void setLevel(int level) {
456 this.level = level;
457 }
458 }
459
460 public Collection<String> getSubstitutions() {
461 return substitutions;
462 }
463
464 public void setSubstitutions(Collection<String> substitutions) {
465 this.substitutions = substitutions;
466 }
467
468 public void setSubstitutions(String... substitutions) {
469 setSubstitutions(Arrays.asList(substitutions));
470 }
471 }