Getting pom xml from gradle cache

I want to get the pom xml from an artifact. (Similar to this post.)

There’s no api to do it, but with some assumptions about the maven local and gradle caches layout it can be done.

My problem is that typically the pom xml isn’t even downloaded. Oddly, running gradle with --refresh-dependencies will pull down pom xml for every artifact in the cache.

Here’s a script that resolves the pom xml:

apply plugin: "java"

ext.getPomFromArtifact = { artifact ->
    try {
        // maven local style
        fileTree(dir:artifact.file.parentFile, include:"**/*.pom").singleFile
    } catch (e) {
        // gradle caches style
        fileTree(dir:artifact.file.parentFile.parentFile, include:"**/*.pom").singleFile
    }
}

repositories {
    jcenter()
}

dependencies {
    compile "commons-io:commons-io:2.4"
}

task resolvePoms() << {
    configurations.compile.resolvedConfiguration.resolvedArtifacts.each { art ->
        try {
            logger.lifecycle("art {}\npom {}", art.file, getPomFromArtifact(art))
        } catch (e) {
            logger.error("could not find pom for {}", art.file)
        }
    }
}

Here’s what I see with this script:

$   rm -rf ~/.gradle/caches/modules-2/files-2.1
$   ./gradlew resolvePoms                       
Download https://jcenter.bintray.com/commons-io/commons-io/2.4/commons-io-2.4.jar
:resolvePoms
could not find pom for ~/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar

BUILD SUCCESSFUL

Total time: 2.765 secs

This build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.8/userguide/gradle_daemon.html

$   ./gradlew resolvePoms --refresh-dependencies
Download https://jcenter.bintray.com/commons-io/commons-io/2.4/commons-io-2.4.pom
Download https://jcenter.bintray.com/org/apache/commons/commons-parent/25/commons-parent-25.pom
:resolvePoms
art ~/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/b1b6ea3b7e4aa4f492509a4952029cd8e48019ad/commons-io-2.4.jar
pom ~/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/2.4/9ece23effe8bce3904f3797a76b1ba6ab681e1b9/commons-io-2.4.pom

BUILD SUCCESSFUL

Total time: 2.964 secs

This build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.8/userguide/gradle_daemon.html

Why is the pom xml sometimes downloaded and sometimes not? Is there a way to get it to download the pom programmatically?

Gradle has another cache located at ~/.gradle/caches/modules-2/metadata-2.16/module-metadata.bin that caches the module metadata found in the pom.xml file. Even though you’ve deleted the cached pom.xml, the POM metadata is still available to Gradle from that cache, so the POM will not be downloaded.

This doesn’t really seem like a solution, but deleting module-metadata.bin in metadata-2.16 like you’re doing with the files-2.1 files should cause a re-download of the pom.xml files. However, I suspect you’re only removing these to prove the unreliability of the POM being there and really don’t want to delete any caches if you can help it.

Without touching anything internal, you could also just declare every dependency that you need like this as a ‘changing’ module and set the cacheChangingModulesFor 0, ‘seconds’ on the configuration. This should cause the pom.xml to be downloaded every time and available for your code above to utilize. This could cause significant performance degradation if we’re talking many dependencies or those of any substantial size, so may not be usable either.

What are you trying to accomplish? Do you just want to download the POM as a separate artifact or are you trying to explicitly trigger redownloading the POM because perhaps its contents have changed (i.e. a SNAPSHOT dependency)?

Sounds like you will want to have a look at the Artifact Query API. Here’s some sample code.

1 Like

I’m trying to do something very much like @bmuschko’s sample code (exporting dependencies). Of course my example code doesn’t do that, but I was trying to keep it simple. :slightly_smiling:

The Artifact Query API seems to download the POM if its not there, which is exactly what I wanted. Thanks @bmuschko!

fyi, here’s the modified code:

apply plugin: "java"

ext.getPomFromArtifact = { artifact ->
    // get the pom
    def component = project.dependencies.createArtifactResolutionQuery()
                            .forComponents(artifact.id.componentIdentifier)
                            .withArtifacts(MavenModule, MavenPomArtifact)
                            .execute()
                            .resolvedComponents[0]
    def pomFile= component.getArtifacts(MavenPomArtifact)[0].file
    return pomFile
}

repositories {
    jcenter()
}

dependencies {
    compile "commons-io:commons-io:2.4"
}

task resolvePoms() << {
    configurations.compile.resolvedConfiguration.resolvedArtifacts.each { art ->
        try {
            logger.lifecycle("art {}\npom {}", art.file, getPomFromArtifact(art))
        } catch (e) {
            logger.error("could not find pom for {}", art.file)
        }
    }
}
2 Likes