onsdag 23. november 2011

Show gradle dependencies as graphwiz png

A few weeks ago I needed to show my team an overview of all the dependencies between our sub projects. I found a solution where I generated a graphwiz dot file. The caveat here was that I had to install graphwiz and run another command to generate a png.

Today I was reading through "Making Java Groovy", MEAP authored by Ken Kousen. I saw an example using the googles charting api. A quick check revealed they had experimental support for creating a png from a dot graph !

So my gradle task ended up looking as follows:

reportsDir = new File("build/reports")
compileDepsPng = file("$reportsDir/compileDeps.png")

task dependenciesPng() {
  inputs.files subprojects.configurations.compile
  outputs.files compileDepsPng
  doFirst {
    if(compileDepsPng.exists()) compileDepsPng.delete()
    if(!reportsDir.exists()) reportsDir.mkdirs()
  
  }
  doLast {
    dotGraph = "digraph Compile{"
    subprojects.each {subproject ->
      subproject.configurations.compile.dependencies.each {dependency ->
      if(dependency instanceof ProjectDependency) {
 dotGraph += "\"$subproject.name\" -> \"$dependency.name\"" 
      }   }
    }
    dotGraph += "}"
  
    def chartParams = [cht: 'gv', chof: 'png', chl: dotGraph]
    def url = "http://chart.googleapis.com/chart?" 
    url += chartParams.collect {k,v -> "$k=${URLEncoder.encode(v)}"}.join('&')
  
    compileDepsPng.withOutputStream{out ->
      out << new URL(url).openStream()
    }   
  }
}





3 kommentarer:

  1. Could you make a sample gradle project i can fork on github?

    SvarSlett
  2. Good article, but a bit out of date, I think. What I did was, put this in the build.gradle of the project of interest:

    task dependenciesPng() {
    def reportsDir = new File("build/reports")
    def compileDepsDot = file("$reportsDir/compileDeps.dot")
    inputs.files subprojects.configurations.compile
    outputs.files compileDepsDot
    doFirst {
    if(!reportsDir.exists()) reportsDir.mkdirs()
    }
    doLast {
    dotGraph = "digraph compile{" + System.getProperty("line.separator")
    Set deps = [] as Set
    subprojects.each {subproject ->
    subproject.configurations.compile.dependencies.each {dependency ->
    if(dependency instanceof ProjectDependency) {
    String dep = "\"$subproject.name\" -> \"$dependency.name\";"
    if (deps.add(dep)){ // if was not there before - avoid duplicates
    dotGraph += dep + System.getProperty("line.separator")
    }
    }
    }
    }
    dotGraph += "}"
    compileDepsDot.write(dotGraph)
    }
    }

    Then ran in the directory where that build.gradle is

    gradle dependenciesPng

    That produced build/reports/compileDeps.dot.
    In this build/reports/ I ran

    apt-get install graphviz

    dot -Tpng ./compileDeps.dot -o ./compileDeps_dot.png &&
    neato -Tpng ./compileDeps.dot -o ./compileDeps_neato.png &&
    twopi -Tpng ./compileDeps.dot -o ./compileDeps_twopi.png &&
    circo -Tpng ./compileDeps.dot -o ./compileDeps_circo.png

    And you will have to choose from the best image you like. Circo as the best for me.

    SvarSlett
  3. Thanks, this was very useful! Do you maybe have an updated version that works without charts.google.com's GraphViz API? It's going to be discontinued in 2015.

    SvarSlett