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.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.StringReader;
27 import java.net.URL;
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(), "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 InputStream stream = null;
191 try
192 {
193 stream = resource.openStream();
194 return parse( new BufferedReader( new InputStreamReader( stream, "UTF-8" ) ) );
195 }
196 finally
197 {
198 if ( stream != null )
199 {
200 stream.close();
201 }
202 }
203 }
204
205 private DependencyNode parse( BufferedReader in )
206 throws IOException
207 {
208 Iterator<String> substitutionIterator = ( substitutions != null ) ? substitutions.iterator() : null;
209
210 String line = null;
211
212 DependencyNode root = null;
213 DependencyNode node = null;
214 int prevLevel = 0;
215
216 Map<String, DependencyNode> nodes = new HashMap<String, DependencyNode>();
217 LinkedList<DependencyNode> stack = new LinkedList<DependencyNode>();
218 boolean isRootNode = true;
219
220 while ( ( line = in.readLine() ) != null )
221 {
222 line = cutComment( line );
223
224 if ( isEmpty( line ) )
225 {
226
227 continue;
228 }
229
230 if ( isEOFMarker( line ) )
231 {
232
233 break;
234 }
235
236 while ( line.contains( "%s" ) )
237 {
238 if ( !substitutionIterator.hasNext() )
239 {
240 throw new IllegalArgumentException( "not enough substitutions to fill placeholders" );
241 }
242 line = line.replaceFirst( "%s", substitutionIterator.next() );
243 }
244
245 LineContext ctx = createContext( line );
246 if ( prevLevel < ctx.getLevel() )
247 {
248
249 stack.add( node );
250 }
251
252
253 while ( prevLevel > ctx.getLevel() )
254 {
255 stack.removeLast();
256 prevLevel -= 1;
257 }
258
259 prevLevel = ctx.getLevel();
260
261 if ( ctx.getDefinition() != null && ctx.getDefinition().reference != null )
262 {
263 String reference = ctx.getDefinition().reference;
264 DependencyNode child = nodes.get( reference );
265 if ( child == null )
266 {
267 throw new IllegalArgumentException( "undefined reference " + reference );
268 }
269 node.getChildren().add( child );
270 }
271 else
272 {
273
274 node = build( isRootNode ? null : stack.getLast(), ctx, isRootNode );
275
276 if ( isRootNode )
277 {
278 root = node;
279 isRootNode = false;
280 }
281
282 if ( ctx.getDefinition() != null && ctx.getDefinition().id != null )
283 {
284 nodes.put( ctx.getDefinition().id, node );
285 }
286 }
287 }
288
289 return root;
290 }
291
292 private boolean isEOFMarker( String line )
293 {
294 return line.startsWith( "---" );
295 }
296
297 private static boolean isEmpty( String line )
298 {
299 return line == null || line.length() == 0;
300 }
301
302 private static String cutComment( String line )
303 {
304 int idx = line.indexOf( '#' );
305
306 if ( idx != -1 )
307 {
308 line = line.substring( 0, idx );
309 }
310
311 return line;
312 }
313
314 private DependencyNode build( DependencyNode parent, LineContext ctx, boolean isRoot )
315 {
316 NodeDefinition def = ctx.getDefinition();
317 if ( !isRoot && parent == null )
318 {
319 throw new IllegalArgumentException( "dangling node: " + def );
320 }
321 else if ( ctx.getLevel() == 0 && parent != null )
322 {
323 throw new IllegalArgumentException( "inconsistent leveling (parent for level 0?): " + def );
324 }
325
326 DefaultDependencyNode node;
327 if ( def != null )
328 {
329 DefaultArtifact artifact = new DefaultArtifact( def.coords, def.properties );
330 Dependency dependency = new Dependency( artifact, def.scope, def.optional );
331 node = new DefaultDependencyNode( dependency );
332 int managedBits = 0;
333 if ( def.premanagedScope != null )
334 {
335 managedBits |= DependencyNode.MANAGED_SCOPE;
336 node.setData( "premanaged.scope", def.premanagedScope );
337 }
338 if ( def.premanagedVersion != null )
339 {
340 managedBits |= DependencyNode.MANAGED_VERSION;
341 node.setData( "premanaged.version", def.premanagedVersion );
342 }
343 node.setManagedBits( managedBits );
344 if ( def.relocations != null )
345 {
346 List<Artifact> relocations = new ArrayList<Artifact>();
347 for ( String relocation : def.relocations )
348 {
349 relocations.add( new DefaultArtifact( relocation ) );
350 }
351 node.setRelocations( relocations );
352 }
353 try
354 {
355 node.setVersion( versionScheme.parseVersion( artifact.getVersion() ) );
356 node.setVersionConstraint( versionScheme.parseVersionConstraint( def.range != null ? def.range
357 : artifact.getVersion() ) );
358 }
359 catch ( InvalidVersionSpecificationException e )
360 {
361 throw new IllegalArgumentException( "bad version: " + e.getMessage(), e );
362 }
363 }
364 else
365 {
366 node = new DefaultDependencyNode( (Dependency) null );
367 }
368
369 if ( parent != null )
370 {
371 parent.getChildren().add( node );
372 }
373
374 return node;
375 }
376
377 public String dump( DependencyNode root )
378 {
379 StringBuilder ret = new StringBuilder();
380
381 List<NodeEntry> entries = new ArrayList<NodeEntry>();
382
383 addNode( root, 0, entries );
384
385 for ( NodeEntry nodeEntry : entries )
386 {
387 char[] level = new char[( nodeEntry.getLevel() * 3 )];
388 Arrays.fill( level, ' ' );
389
390 if ( level.length != 0 )
391 {
392 level[level.length - 3] = '+';
393 level[level.length - 2] = '-';
394 }
395
396 String definition = nodeEntry.getDefinition();
397
398 ret.append( level ).append( definition ).append( "\n" );
399 }
400
401 return ret.toString();
402
403 }
404
405 private void addNode( DependencyNode root, int level, List<NodeEntry> entries )
406 {
407
408 NodeEntry entry = new NodeEntry();
409 Dependency dependency = root.getDependency();
410 StringBuilder defBuilder = new StringBuilder();
411 if ( dependency == null )
412 {
413 defBuilder.append( "(null)" );
414 }
415 else
416 {
417 Artifact artifact = dependency.getArtifact();
418
419 defBuilder.append( artifact.getGroupId() ).append( ":" ).append( artifact.getArtifactId() ).append( ":" ).append( artifact.getExtension() ).append( ":" ).append( artifact.getVersion() );
420 if ( dependency.getScope() != null && ( !"".equals( dependency.getScope() ) ) )
421 {
422 defBuilder.append( ":" ).append( dependency.getScope() );
423 }
424
425 Map<String, String> properties = artifact.getProperties();
426 if ( !( properties == null || properties.isEmpty() ) )
427 {
428 for ( Map.Entry<String, String> prop : properties.entrySet() )
429 {
430 defBuilder.append( ";" ).append( prop.getKey() ).append( "=" ).append( prop.getValue() );
431 }
432 }
433 }
434
435 entry.setDefinition( defBuilder.toString() );
436 entry.setLevel( level++ );
437
438 entries.add( entry );
439
440 for ( DependencyNode node : root.getChildren() )
441 {
442 addNode( node, level, entries );
443 }
444
445 }
446
447 class NodeEntry
448 {
449 int level;
450
451 String definition;
452
453 Map<String, String> properties;
454
455 public int getLevel()
456 {
457 return level;
458 }
459
460 public void setLevel( int level )
461 {
462 this.level = level;
463 }
464
465 public String getDefinition()
466 {
467 return definition;
468 }
469
470 public void setDefinition( String definition )
471 {
472 this.definition = definition;
473 }
474
475 public Map<String, String> getProperties()
476 {
477 return properties;
478 }
479
480 public void setProperties( Map<String, String> properties )
481 {
482 this.properties = properties;
483 }
484 }
485
486 private static LineContext createContext( String line )
487 {
488 LineContext ctx = new LineContext();
489 String definition;
490
491 String[] split = line.split( "- " );
492 if ( split.length == 1 )
493 {
494 ctx.setLevel( 0 );
495 definition = split[0];
496 }
497 else
498 {
499 ctx.setLevel( (int) Math.ceil( (double) split[0].length() / (double) 3 ) );
500 definition = split[1];
501 }
502
503 if ( "(null)".equalsIgnoreCase( definition ) )
504 {
505 return ctx;
506 }
507
508 ctx.setDefinition( new NodeDefinition( definition ) );
509
510 return ctx;
511 }
512
513 static class LineContext
514 {
515 NodeDefinition definition;
516
517 int level;
518
519 public NodeDefinition getDefinition()
520 {
521 return definition;
522 }
523
524 public void setDefinition( NodeDefinition definition )
525 {
526 this.definition = definition;
527 }
528
529 public int getLevel()
530 {
531 return level;
532 }
533
534 public void setLevel( int level )
535 {
536 this.level = level;
537 }
538 }
539
540 public Collection<String> getSubstitutions()
541 {
542 return substitutions;
543 }
544
545 public void setSubstitutions( Collection<String> substitutions )
546 {
547 this.substitutions = substitutions;
548 }
549
550 public void setSubstitutions( String... substitutions )
551 {
552 setSubstitutions( Arrays.asList( substitutions ) );
553 }
554
555 }