Is this the best way to access the pom file for a dependency?

I am trying to parse the pom files to get license information (when it’s available) and this is what I came up with to get to the URLs:

buildscript {
 repositories {
  mavenCentral()
 }
   dependencies {
  classpath 'commons-io:commons-io:2.4'
  classpath 'xerces:xercesImpl:2.7.1'
 }
}
  import org.apache.commons.io.FileUtils;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
  task licenses {
 configurations.compile.resolvedConfiguration.getResolvedArtifacts().each { dep ->
  String dir = dep.getFile().getAbsolutePath().replaceAll("\\jar\\.*", "")
  String[] exts = new String[1]
  exts[0] = "pom"
  FileUtils.listFiles(new File(dir), exts, true).each { file ->
   DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance()
   DocumentBuilder xml = factory.newDocumentBuilder()
   Document dom = xml.parse(file.getAbsolutePath())
        Element root = dom.getDocumentElement();
   NodeList licenses = root.getElementsByTagName("license");
   for (org.w3c.dom.Node license : licenses) {
    NodeList urls = license.getElementsByTagName("url")
    for (org.w3c.dom.Node url : urls) {
     println(url.getFirstChild().getNodeValue())
    }
   }
  }
 }
}

Basically it goes to the path of the dependency, drops of everything after and including the jar directory (to get back to the top directory for that dependency) and then recursively checks for all pom files under that directory. Once that is done, it parses the XML to get the URLs.

Is this really the best way to do it or did I miss some Gradle property or method?

A simpler way to get to the artifact files is configurations.compile.each { file -> … }. A simpler way to parse the XML is to use Groovy’s ‘XmlSlurper’. An alternative way to scan a directory hierarchy is to use Groovy’s ‘File.traverse()’ method.

Andrew, how far did you get? Are you implementing some plugin? Seems that I need quite similar stuff - generate dependency license report.

1 Like

I’m interested in getting license information out of the dependencies as well - any progress here that you might be able to share?

This solution reuse the hack of Andrew Warren-Love to generate path for the POM file. Actually, it would be quite nice if someone from the gradle team could show the proper way to access it. The main improvement is that the solution does not use 3rd party jars. def jarLicenses= new FileWriter(‘3rdPartyLicenses.txt’)

jarLicenses.write(“This is the complete list of the JARs used by the JChem Web Services (license information is included in case when no details are available in license.html):\n==================================\n\n”)

configurations.compile.each { File jar ->

jarLicenses.write(jar.name+":\n")

if(jar.getAbsolutePath().contains("\jar\")){

def dir=new File(jar.getAbsolutePath().replaceAll("\\jar\\.*", “\\pom”))

if(dir!=null&&dir.exists()) {

def project = new XmlSlurper().parse(dir?.listFiles()[0]?.listFiles()[0])

project.licenses.license.each {

jarLicenses.write(it.name.text()+" - “+it.url.text()+”\n\n")

jarLicenses.flush()

}

}

}

}

jarLicenses.close();

Hi, i have similar needs.

I modified the “hack” and added the poms to an extra configuration automatically. This solution works on all os (the others work only on windows). Also no information about the gradle cache is needed.

configurations {
    poms
}
task showLicenses {
    doFirst {
        configurations.compile.dependencies.each { Dependency dependency ->
            dependencies {
                poms(
                    group: dependency.group,
                     name: dependency.name,
                     version: dependency.version,
                     ext: 'pom'
                )
            }
        }
    }
          doLast {
        configurations.poms.each { File pom ->
            println "${pom.name}:"
            def project = new XmlSlurper().parse(pom)
            project.licenses.license.each {
                println it.name.text()+" - "+it.url.text()+"\n"
            }
        }
    }
}
2 Likes

That’s a pretty good solution - as good as it gets without Gradle providing access to module descriptors as a first-class feature. The ‘doFirst’/‘doLast’ could be collapsed into a single task action.

1 Like