Wednesday, February 9, 2011

Ant Target Dependency Graph

We can get a pretty good diagram of our Ant target dependencies very easily using an embedded Groovy script and GraphViz.

Add this to build.xml:



def u(x) {x.toString().replace("-", "_").replace(".", "_")}
new File("build.dot").text = """
digraph ant {
${project.targets.values().collect {target ->
target.dependencies.collect {dep ->
u(dep) + " -> " + u(target)
}.join("\n")
}.join("\n")}
}
"""


You will need to have the embeddable groovy-all.jar in Ant's classpath, e.g. in ~/.ant/lib/.

Then run "ant target-graph". It writes a build.dot file in the current directory.

Convert this into a picture using the GraphViz dot command:
dot -Tsvg -O build.dot

The results are surprisingly good.

Here's an example from the Apache commons-dbcp project:



I'm not going to show you the diagram I got for our system at work, the reason I wrote this script! The diagram is so big and complex, I was shocked. After being happy with Ant all these years, I think it's time to be getting serious about Gradle.

6 comments:

Gail S said...

If you declare the taskdef classpath and taskdef separately
you don't have to put groovy in .ant/lib

vickikozel said...

If I am not mistaken, this will work only for that build.xml to which you are adding the groovy target. How about if I have a myriad of entangled build files, a ton of imports, and a universe of dependencies? This solution would be really practical if it worked for my situation.

John Hurst said...

I've used it with imported scripts.

Targets from imported scripts get their names prefixed with the 'name' attribute from the imported script.

So I have



where common-build has name "common", and in my diagram I get nodes "common.compile", "common.test" etc.

BTW my original version had trivial tag nesting issues with (not sure how that happened).

More importantly, you can improve the format of the result by using quotes around the node names, using:

target.dependencies.collect {dep ->
'"' + dep + '" -> "' + target + '"'
}.join("\n")

John Hurst said...

Argh, example is supposed to read

<import file="common-build.xml"/>

vickikozel said...

thank you John, I'll try to experiment with these solutions.
Vicki

Smith said...

Hi John what version of groovy are you using?