Mercurial > projects > dil
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); |