View Javadoc
1   package org.eclipse.aether.internal.impl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.PrintWriter;
23  import java.util.ArrayList;
24  import java.util.IdentityHashMap;
25  import java.util.Iterator;
26  import java.util.LinkedList;
27  import java.util.List;
28  import java.util.Map;
29  
30  import org.eclipse.aether.graph.Dependency;
31  import org.eclipse.aether.graph.DependencyNode;
32  
33  /**
34   * A helper to visualize dependency graphs.
35   */
36  public class DependencyGraphDumper
37  {
38  
39      public static void dump( PrintWriter writer, DependencyNode node )
40      {
41          Context context = new Context();
42          dump( context, node, 0, true );
43  
44          LinkedList<Indent> indents = new LinkedList<>();
45          for ( Line line : context.lines )
46          {
47              if ( line.depth > indents.size() )
48              {
49                  if ( !indents.isEmpty() )
50                  {
51                      if ( indents.getLast() == Indent.CHILD )
52                      {
53                          indents.removeLast();
54                          indents.addLast( Indent.CHILDREN );
55                      }
56                      else if ( indents.getLast() == Indent.LAST_CHILD )
57                      {
58                          indents.removeLast();
59                          indents.addLast( Indent.NO_CHILDREN );
60                      }
61                  }
62                  indents.addLast( line.last ? Indent.LAST_CHILD : Indent.CHILD );
63              }
64              else if ( line.depth < indents.size() )
65              {
66                  while ( line.depth <= indents.size() )
67                  {
68                      indents.removeLast();
69                  }
70                  indents.addLast( line.last ? Indent.LAST_CHILD : Indent.CHILD );
71              }
72              else if ( line.last && !indents.isEmpty() )
73              {
74                  indents.removeLast();
75                  indents.addLast( Indent.LAST_CHILD );
76              }
77  
78              for ( Indent indent : indents )
79              {
80                  writer.print( indent );
81              }
82  
83              line.print( writer );
84          }
85  
86          writer.flush();
87      }
88  
89      private static void dump( Context context, DependencyNode node, int depth, boolean last )
90      {
91          Line line = context.nodes.get( node );
92          if ( line != null )
93          {
94              if ( line.id <= 0 )
95              {
96                  line.id = ++context.ids;
97              }
98              context.lines.add( new Line( null, line.id, depth, last ) );
99              return;
100         }
101 
102         Dependency dependency = node.getDependency();
103 
104         if ( dependency == null )
105         {
106             line = new Line( null, 0, depth, last );
107         }
108         else
109         {
110             line = new Line( dependency, 0, depth, last );
111         }
112 
113         context.lines.add( line );
114 
115         context.nodes.put( node, line );
116 
117         depth++;
118 
119         for ( Iterator<DependencyNode> it = node.getChildren().iterator(); it.hasNext(); )
120         {
121             DependencyNode child = it.next();
122             dump( context, child, depth, !it.hasNext() );
123         }
124     }
125 
126     enum Indent
127     {
128 
129         NO_CHILDREN( "   " ),
130 
131         CHILDREN( "|  " ),
132 
133         CHILD( "+- " ),
134 
135         LAST_CHILD( "\\- " );
136 
137         private final String chars;
138 
139         Indent( String chars )
140         {
141             this.chars = chars;
142         }
143 
144         @Override
145         public String toString()
146         {
147             return chars;
148         }
149 
150     }
151 
152     static class Context
153     {
154 
155         int ids;
156 
157         List<Line> lines;
158 
159         Map<DependencyNode, Line> nodes;
160 
161         Context()
162         {
163             this.lines = new ArrayList<>();
164             this.nodes = new IdentityHashMap<>( 1024 );
165         }
166 
167     }
168 
169     static class Line
170     {
171 
172         Dependency dependency;
173 
174         int id;
175 
176         int depth;
177 
178         boolean last;
179 
180         Line( Dependency dependency, int id, int depth, boolean last )
181         {
182             this.dependency = dependency;
183             this.id = id;
184             this.depth = depth;
185             this.last = last;
186         }
187 
188         void print( PrintWriter writer )
189         {
190             if ( dependency == null )
191             {
192                 if ( id > 0 )
193                 {
194                     writer.print( "^" );
195                     writer.print( id );
196                 }
197                 else
198                 {
199                     writer.print( "(null)" );
200                 }
201             }
202             else
203             {
204                 if ( id > 0 )
205                 {
206                     writer.print( "(" );
207                     writer.print( id );
208                     writer.print( ")" );
209                 }
210                 writer.print( dependency.getArtifact() );
211                 if ( dependency.getScope().length() > 0 )
212                 {
213                     writer.print( ":" );
214                     writer.print( dependency.getScope() );
215                 }
216             }
217             writer.println();
218         }
219 
220     }
221 
222 }