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