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.<String>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 BufferedReader reader = new BufferedReader(new StringReader(dependencyGraph));
135 DependencyNode node = parse(reader);
136 reader.close();
137 return node;
138 }
139
140
141
142
143
144 public DependencyNode parseResource(String resource) throws IOException {
145 URL res = this.getClass().getClassLoader().getResource(prefix + resource);
146 if (res == null) {
147 throw new IOException("Could not find classpath resource " + prefix + resource);
148 }
149 return parse(res);
150 }
151
152
153
154
155 public List<DependencyNode> parseMultiResource(String resource) throws IOException {
156 URL res = this.getClass().getClassLoader().getResource(prefix + resource);
157 if (res == null) {
158 throw new IOException("Could not find classpath resource " + prefix + resource);
159 }
160
161 BufferedReader reader = new BufferedReader(new InputStreamReader(res.openStream(), StandardCharsets.UTF_8));
162
163 List<DependencyNode> ret = new ArrayList<>();
164 DependencyNode root = null;
165 while ((root = parse(reader)) != null) {
166 ret.add(root);
167 }
168 return ret;
169 }
170
171
172
173
174 public DependencyNode parse(URL resource) throws IOException {
175 BufferedReader reader = null;
176 try {
177 reader = new BufferedReader(new InputStreamReader(resource.openStream(), StandardCharsets.UTF_8));
178 return parse(reader);
179 } finally {
180 try {
181 if (reader != null) {
182 reader.close();
183 reader = null;
184 }
185 } catch (final IOException e) {
186
187 }
188 }
189 }
190
191 private DependencyNode parse(BufferedReader in) throws IOException {
192 Iterator<String> substitutionIterator = (substitutions != null) ? substitutions.iterator() : null;
193
194 String line = null;
195
196 DependencyNode root = null;
197 DependencyNode node = null;
198 int prevLevel = 0;
199
200 Map<String, DependencyNode> nodes = new HashMap<>();
201 LinkedList<DependencyNode> stack = new LinkedList<>();
202 boolean isRootNode = true;
203
204 while ((line = in.readLine()) != null) {
205 line = cutComment(line);
206
207 if (isEmpty(line)) {
208
209 continue;
210 }
211
212 if (isEOFMarker(line)) {
213
214 break;
215 }
216
217 while (line.contains("%s")) {
218 if (!substitutionIterator.hasNext()) {
219 throw new IllegalStateException("not enough substitutions to fill placeholders");
220 }
221 line = line.replaceFirst("%s", substitutionIterator.next());
222 }
223
224 LineContext ctx = createContext(line);
225 if (prevLevel < ctx.getLevel()) {
226
227 stack.add(node);
228 }
229
230
231 while (prevLevel > ctx.getLevel()) {
232 stack.removeLast();
233 prevLevel -= 1;
234 }
235
236 prevLevel = ctx.getLevel();
237
238 if (ctx.getDefinition() != null && ctx.getDefinition().reference != null) {
239 String reference = ctx.getDefinition().reference;
240 DependencyNode child = nodes.get(reference);
241 if (child == null) {
242 throw new IllegalStateException("undefined reference " + reference);
243 }
244 node.getChildren().add(child);
245 } else {
246
247 node = build(isRootNode ? null : stack.getLast(), ctx, isRootNode);
248
249 if (isRootNode) {
250 root = node;
251 isRootNode = false;
252 }
253
254 if (ctx.getDefinition() != null && ctx.getDefinition().id != null) {
255 nodes.put(ctx.getDefinition().id, node);
256 }
257 }
258 }
259
260 return root;
261 }
262
263 private boolean isEOFMarker(String line) {
264 return line.startsWith("---");
265 }
266
267 private static boolean isEmpty(String line) {
268 return line == null || line.length() == 0;
269 }
270
271 private static String cutComment(String line) {
272 int idx = line.indexOf('#');
273
274 if (idx != -1) {
275 line = line.substring(0, idx);
276 }
277
278 return line;
279 }
280
281 private DependencyNode build(DependencyNode parent, LineContext ctx, boolean isRoot) {
282 NodeDefinition def = ctx.getDefinition();
283 if (!isRoot && parent == null) {
284 throw new IllegalStateException("dangling node: " + def);
285 } else if (ctx.getLevel() == 0 && parent != null) {
286 throw new IllegalStateException("inconsistent leveling (parent for level 0?): " + def);
287 }
288
289 DefaultDependencyNode node;
290 if (def != null) {
291 DefaultArtifact artifact = new DefaultArtifact(def.coords, def.properties);
292 Dependency dependency = new Dependency(artifact, def.scope, def.optional);
293 node = new DefaultDependencyNode(dependency);
294 int managedBits = 0;
295 if (def.premanagedScope != null) {
296 managedBits |= DependencyNode.MANAGED_SCOPE;
297 node.setData("premanaged.scope", def.premanagedScope);
298 }
299 if (def.premanagedVersion != null) {
300 managedBits |= DependencyNode.MANAGED_VERSION;
301 node.setData("premanaged.version", def.premanagedVersion);
302 }
303 node.setManagedBits(managedBits);
304 if (def.relocations != null) {
305 List<Artifact> relocations = new ArrayList<>();
306 for (String relocation : def.relocations) {
307 relocations.add(new DefaultArtifact(relocation));
308 }
309 node.setRelocations(relocations);
310 }
311 try {
312 node.setVersion(versionScheme.parseVersion(artifact.getVersion()));
313 node.setVersionConstraint(
314 versionScheme.parseVersionConstraint(def.range != null ? def.range : artifact.getVersion()));
315 } catch (InvalidVersionSpecificationException e) {
316 throw new IllegalArgumentException("bad version: " + e.getMessage(), e);
317 }
318 } else {
319 node = new DefaultDependencyNode((Dependency) null);
320 }
321
322 if (parent != null) {
323 parent.getChildren().add(node);
324 }
325
326 return node;
327 }
328
329 public String dump(DependencyNode root) {
330 StringBuilder ret = new StringBuilder();
331
332 List<NodeEntry> entries = new ArrayList<>();
333
334 addNode(root, 0, entries);
335
336 for (NodeEntry nodeEntry : entries) {
337 char[] level = new char[(nodeEntry.getLevel() * 3)];
338 Arrays.fill(level, ' ');
339
340 if (level.length != 0) {
341 level[level.length - 3] = '+';
342 level[level.length - 2] = '-';
343 }
344
345 String definition = nodeEntry.getDefinition();
346
347 ret.append(level).append(definition).append("\n");
348 }
349
350 return ret.toString();
351 }
352
353 private void addNode(DependencyNode root, int level, List<NodeEntry> entries) {
354
355 NodeEntry entry = new NodeEntry();
356 Dependency dependency = root.getDependency();
357 StringBuilder defBuilder = new StringBuilder();
358 if (dependency == null) {
359 defBuilder.append("(null)");
360 } else {
361 Artifact artifact = dependency.getArtifact();
362
363 defBuilder
364 .append(artifact.getGroupId())
365 .append(":")
366 .append(artifact.getArtifactId())
367 .append(":")
368 .append(artifact.getExtension())
369 .append(":")
370 .append(artifact.getVersion());
371 if (dependency.getScope() != null && (!"".equals(dependency.getScope()))) {
372 defBuilder.append(":").append(dependency.getScope());
373 }
374
375 Map<String, String> properties = artifact.getProperties();
376 if (!(properties == null || properties.isEmpty())) {
377 for (Map.Entry<String, String> prop : properties.entrySet()) {
378 defBuilder.append(";").append(prop.getKey()).append("=").append(prop.getValue());
379 }
380 }
381 }
382
383 entry.setDefinition(defBuilder.toString());
384 entry.setLevel(level++);
385
386 entries.add(entry);
387
388 for (DependencyNode node : root.getChildren()) {
389 addNode(node, level, entries);
390 }
391 }
392
393 class NodeEntry {
394 int level;
395
396 String definition;
397
398 Map<String, String> properties;
399
400 public int getLevel() {
401 return level;
402 }
403
404 public void setLevel(int level) {
405 this.level = level;
406 }
407
408 public String getDefinition() {
409 return definition;
410 }
411
412 public void setDefinition(String definition) {
413 this.definition = definition;
414 }
415
416 public Map<String, String> getProperties() {
417 return properties;
418 }
419
420 public void setProperties(Map<String, String> properties) {
421 this.properties = properties;
422 }
423 }
424
425 private static LineContext createContext(String line) {
426 LineContext ctx = new LineContext();
427 String definition;
428
429 String[] split = line.split("- ");
430 if (split.length == 1)
431 {
432 ctx.setLevel(0);
433 definition = split[0];
434 } else {
435 ctx.setLevel((int) Math.ceil((double) split[0].length() / (double) 3));
436 definition = split[1];
437 }
438
439 if ("(null)".equalsIgnoreCase(definition)) {
440 return ctx;
441 }
442
443 ctx.setDefinition(new NodeDefinition(definition));
444
445 return ctx;
446 }
447
448 static class LineContext {
449 NodeDefinition definition;
450
451 int level;
452
453 public NodeDefinition getDefinition() {
454 return definition;
455 }
456
457 public void setDefinition(NodeDefinition definition) {
458 this.definition = definition;
459 }
460
461 public int getLevel() {
462 return level;
463 }
464
465 public void setLevel(int level) {
466 this.level = level;
467 }
468 }
469
470 public Collection<String> getSubstitutions() {
471 return substitutions;
472 }
473
474 public void setSubstitutions(Collection<String> substitutions) {
475 this.substitutions = substitutions;
476 }
477
478 public void setSubstitutions(String... substitutions) {
479 setSubstitutions(Arrays.asList(substitutions));
480 }
481 }