001package org.eclipse.aether.internal.impl; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.PrintWriter; 023import java.util.ArrayList; 024import java.util.IdentityHashMap; 025import java.util.Iterator; 026import java.util.LinkedList; 027import java.util.List; 028import java.util.Map; 029 030import org.eclipse.aether.graph.Dependency; 031import org.eclipse.aether.graph.DependencyNode; 032 033/** 034 * A helper to visualize dependency graphs. 035 */ 036public class DependencyGraphDumper 037{ 038 039 public static void dump( PrintWriter writer, DependencyNode node ) 040 { 041 Context context = new Context(); 042 dump( context, node, 0, true ); 043 044 LinkedList<Indent> indents = new LinkedList<>(); 045 for ( Line line : context.lines ) 046 { 047 if ( line.depth > indents.size() ) 048 { 049 if ( !indents.isEmpty() ) 050 { 051 if ( indents.getLast() == Indent.CHILD ) 052 { 053 indents.removeLast(); 054 indents.addLast( Indent.CHILDREN ); 055 } 056 else if ( indents.getLast() == Indent.LAST_CHILD ) 057 { 058 indents.removeLast(); 059 indents.addLast( Indent.NO_CHILDREN ); 060 } 061 } 062 indents.addLast( line.last ? Indent.LAST_CHILD : Indent.CHILD ); 063 } 064 else if ( line.depth < indents.size() ) 065 { 066 while ( line.depth <= indents.size() ) 067 { 068 indents.removeLast(); 069 } 070 indents.addLast( line.last ? Indent.LAST_CHILD : Indent.CHILD ); 071 } 072 else if ( line.last && !indents.isEmpty() ) 073 { 074 indents.removeLast(); 075 indents.addLast( Indent.LAST_CHILD ); 076 } 077 078 for ( Indent indent : indents ) 079 { 080 writer.print( indent ); 081 } 082 083 line.print( writer ); 084 } 085 086 writer.flush(); 087 } 088 089 private static void dump( Context context, DependencyNode node, int depth, boolean last ) 090 { 091 Line line = context.nodes.get( node ); 092 if ( line != null ) 093 { 094 if ( line.id <= 0 ) 095 { 096 line.id = ++context.ids; 097 } 098 context.lines.add( new Line( null, line.id, depth, last ) ); 099 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}