comparison src/cmd/ImportGraph.d @ 809:7e84472f4e91

Refactored the importgraph command.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sun, 09 Mar 2008 16:39:46 +0100
parents bcb74c9b895c
children 525ee3f848d9
comparison
equal deleted inserted replaced
808:28e1ff1dcfcf 809:7e84472f4e91
18 import tango.io.FileConst; 18 import tango.io.FileConst;
19 import tango.text.Util; 19 import tango.text.Util;
20 20
21 alias FileConst.PathSeparatorChar dirSep; 21 alias FileConst.PathSeparatorChar dirSep;
22 22
23 /// Options for the importgraph command. 23 /// The importgraph command.
24 enum IGraphOption 24 struct IGraphCommand
25 { 25 {
26 None, 26 /// Options for the command.
27 IncludeUnlocatableModules = 1, 27 enum Option
28 PrintDot = 1<<1, 28 {
29 HighlightCyclicEdges = 1<<2, 29 None,
30 HighlightCyclicVertices = 1<<3, 30 IncludeUnlocatableModules = 1,
31 GroupByPackageNames = 1<<4, 31 PrintDot = 1<<1,
32 GroupByFullPackageName = 1<<5, 32 HighlightCyclicEdges = 1<<2,
33 PrintPaths = 1<<6, 33 HighlightCyclicVertices = 1<<3,
34 PrintList = 1<<7, 34 GroupByPackageNames = 1<<4,
35 MarkCyclicModules = 1<<8, 35 GroupByFullPackageName = 1<<5,
36 PrintPaths = 1<<6,
37 PrintList = 1<<7,
38 MarkCyclicModules = 1<<8,
39 }
40 alias Option Options;
41
42 Options options; /// Command options.
43 string filePath; /// File path to the root module.
44 string[] regexps; /// Regular expressions.
45 string siStyle = "dashed"; /// Static import style.
46 string piStyle = "bold"; /// Public import style.
47 uint levels; /// How many levels to print.
48
49 CompilationContext context;
50
51 /// Adds o to the options.
52 void add(Option o)
53 {
54 options |= o;
55 }
56
57 void run()
58 {
59 // Init regular expressions.
60 RegExp[] regexps;
61 foreach (strRegexp; this.regexps)
62 regexps ~= new RegExp(strRegexp);
63
64 // Add the directory of the file to the import paths.
65 auto filePath = new FilePath(this.filePath);
66 auto fileDir = filePath.folder();
67 context.importPaths ~= fileDir;
68
69 auto gbuilder = new GraphBuilder;
70
71 gbuilder.importPaths = context.importPaths;
72 gbuilder.options = options;
73 gbuilder.filterPredicate = (string moduleFQNPath) {
74 foreach (rx; regexps)
75 // Replace slashes: dil/ast/Node -> dil.ast.Node
76 if (rx.test(replace(moduleFQNPath.dup, dirSep, '.')))
77 return true;
78 return false;
79 };
80
81 auto graph = gbuilder.start(filePath.name());
82
83 if (options & (Option.PrintList | Option.PrintPaths))
84 {
85 if (options & Option.MarkCyclicModules)
86 graph.detectCycles();
87
88 if (options & Option.PrintPaths)
89 printModulePaths(graph.vertices, levels+1, "");
90 else
91 printModuleList(graph.vertices, levels+1, "");
92 }
93 else
94 printDotDocument(graph, siStyle, piStyle, options);
95 }
36 } 96 }
37 97
38 /// Represents a module dependency graph. 98 /// Represents a module dependency graph.
39 class Graph 99 class Graph
40 { 100 {
146 206
147 /// Builds a module dependency graph. 207 /// Builds a module dependency graph.
148 class GraphBuilder 208 class GraphBuilder
149 { 209 {
150 Graph graph; 210 Graph graph;
151 IGraphOption options; 211 IGraphCommand.Options options;
152 string[] importPaths; /// Where to look for modules. 212 string[] importPaths; /// Where to look for modules.
153 Vertex[string] loadedModulesTable; /// Maps FQN paths to modules. 213 Vertex[string] loadedModulesTable; /// Maps FQN paths to modules.
154 bool delegate(string) filterPredicate; 214 bool delegate(string) filterPredicate;
155 215
156 this() 216 this()
190 250
191 Vertex vertex; 251 Vertex vertex;
192 252
193 if (moduleFilePath is null) 253 if (moduleFilePath is null)
194 { // Module not found. 254 { // Module not found.
195 if (options & IGraphOption.IncludeUnlocatableModules) 255 if (options & IGraphCommand.Option.IncludeUnlocatableModules)
196 { // Include module nevertheless. 256 { // Include module nevertheless.
197 vertex = new Vertex; 257 vertex = new Vertex;
198 vertex.modul = new Module(""); 258 vertex.modul = new Module("");
199 vertex.modul.setFQN(replace(moduleFQNPath, dirSep, '.')); 259 vertex.modul.setFQN(replace(moduleFQNPath, dirSep, '.'));
200 graph.addVertex(vertex); 260 graph.addVertex(vertex);
232 } 292 }
233 return vertex; 293 return vertex;
234 } 294 }
235 } 295 }
236 296
237 /// Executes the importgraph command.
238 void execute(string filePathString, CompilationContext context, string[] strRegexps,
239 uint levels, string siStyle, string piStyle, IGraphOption options)
240 {
241 // Init regular expressions.
242 RegExp[] regexps;
243 foreach (strRegexp; strRegexps)
244 regexps ~= new RegExp(strRegexp);
245
246 // Add the directory of the file to the import paths.
247 auto filePath = new FilePath(filePathString);
248 auto fileDir = filePath.folder();
249 context.importPaths ~= fileDir;
250
251 auto gbuilder = new GraphBuilder;
252
253 gbuilder.importPaths = context.importPaths;
254 gbuilder.options = options;
255 gbuilder.filterPredicate = (string moduleFQNPath) {
256 foreach (rx; regexps)
257 // Replace slashes: dil/ast/Node -> dil.ast.Node
258 if (rx.test(replace(moduleFQNPath.dup, dirSep, '.')))
259 return true;
260 return false;
261 };
262
263 auto graph = gbuilder.start(filePath.name());
264
265 if (options & (IGraphOption.PrintList | IGraphOption.PrintPaths))
266 {
267 if (options & IGraphOption.MarkCyclicModules)
268 graph.detectCycles();
269
270 if (options & IGraphOption.PrintPaths)
271 printModulePaths(graph.vertices, levels+1, "");
272 else
273 printModuleList(graph.vertices, levels+1, "");
274 }
275 else
276 printDotDocument(graph, siStyle, piStyle, options);
277 }
278
279 /// Prints the file paths to the modules. 297 /// Prints the file paths to the modules.
280 void printModulePaths(Vertex[] vertices, uint level, char[] indent) 298 void printModulePaths(Vertex[] vertices, uint level, char[] indent)
281 { 299 {
282 if (level == 0) 300 if (level == 0)
283 return; 301 return;
302 } 320 }
303 } 321 }
304 322
305 /// Prints the graph as a graphviz dot document. 323 /// Prints the graph as a graphviz dot document.
306 void printDotDocument(Graph graph, string siStyle, string piStyle, 324 void printDotDocument(Graph graph, string siStyle, string piStyle,
307 IGraphOption options) 325 IGraphCommand.Options options)
308 { 326 {
309 Vertex[][string] verticesByPckgName; 327 Vertex[][string] verticesByPckgName;
310 if (options & IGraphOption.GroupByFullPackageName) 328 if (options & IGraphCommand.Option.GroupByFullPackageName)
311 foreach (vertex; graph.vertices) 329 foreach (vertex; graph.vertices)
312 verticesByPckgName[vertex.modul.packageName] ~= vertex; 330 verticesByPckgName[vertex.modul.packageName] ~= vertex;
313 331
314 if (options & (IGraphOption.HighlightCyclicVertices | 332 if (options & (IGraphCommand.Option.HighlightCyclicVertices |
315 IGraphOption.HighlightCyclicEdges)) 333 IGraphCommand.Option.HighlightCyclicEdges))
316 graph.detectCycles(); 334 graph.detectCycles();
317 335
318 // Output header of the dot document. 336 // Output header of the dot document.
319 Stdout("Digraph ImportGraph\n{\n"); 337 Stdout("Digraph ImportGraph\n{\n");
320 // Output nodes. 338 // Output nodes.
336 } 354 }
337 edge.isCyclic && (edgeStyles ~= "[color=red]"); 355 edge.isCyclic && (edgeStyles ~= "[color=red]");
338 Stdout.formatln(` n{} -> n{} {};`, edge.from.id, edge.to.id, edgeStyles); 356 Stdout.formatln(` n{} -> n{} {};`, edge.from.id, edge.to.id, edgeStyles);
339 } 357 }
340 358
341 if (options & IGraphOption.GroupByFullPackageName) 359 if (options & IGraphCommand.Option.GroupByFullPackageName)
342 foreach (packageName, vertices; verticesByPckgName) 360 foreach (packageName, vertices; verticesByPckgName)
343 { // Output nodes in a cluster. 361 { // Output nodes in a cluster.
344 Stdout.format(` subgraph "cluster_{}" {`\n` label="{}";color=blue;`"\n ", packageName, packageName); 362 Stdout.format(` subgraph "cluster_{}" {`\n` label="{}";color=blue;`"\n ", packageName, packageName);
345 foreach (vertex; vertices) 363 foreach (vertex; vertices)
346 Stdout.format(`n{};`, vertex.id); 364 Stdout.format(`n{};`, vertex.id);