How to get hold of ivy.xml file of dependency


(t.enderling) #1

Hi,

is there any straightforward way to get hold of the Ivy module descriptor (ivy.xml file) of a dependency using Gradle?

I know how to grab a ResolvedDependency and from there also all artifacts. But the module descriptor itself is not among them (which you might or might not expect), also I don’t see a method to access it directly. (Tried Gradle 1.6 and looked up the documentation for 1.7-rc-2.)

I could try to fallback to using Ivy itself, but you are hiding Ivy pretty well. Also I don’t want to replace Gradle’s dependency resolution by Ivy, nor do I want to use two dependency management systems in the same build.

Any directions on how to solve this?

Our use case is the following:

Since the format of Ivy module descriptors is easily extensible (you can add extra elements and attributes) we use module descriptors to store additional meta data for our modules. During build I need access to the meta data of its dependencies.

(I’m not sure if this is even Ivy specific, its more a general requirement to get hold of the meta data - if any. I could imagine use cases for requiring to read the pom.xml of a dependency as well.)

Thank you, Tim


(Peter Niederwieser) #2

The only solution I’m aware of is to (manually or programmatically) declare a dependency on the ‘ivy.xml’ itself, and resolve that (perhaps using a separate configuration).


(t.enderling) #3

Thanks I’ll try that and post back my solution if it works.


(Peter Niederwieser) #4

Here is a proof-of-concept that I once wrote. Maybe you’ll find it useful.

apply plugin: "java"
  repositories {
    ivy {
        url "/tmp/ivys2/build/repo"
    }
}
  dependencies {
    compile "org.gradle.sample:ivys2:1.0"
}
  task showDependencies(dependsOn: configurations.compile) << {
    configurations.compile.each { println it }
}
  task printDescriptors(dependsOn: configurations.compile) << {
    def ivyDeps = configurations.compile.allDependencies
        .findAll { it instanceof ModuleDependency }
        .collect { it.copy() }
    ivyDeps.each { dep ->
        dep.artifacts.clear()
        dep.artifact {
            name = "ivy"
            type = "ivy"
            extension = "xml"
        }
    }
    def ivyConf = configurations.detachedConfiguration(*ivyDeps)
    ivyConf.each {
        println it.text
        println()
    }
}

(t.enderling) #5

Great! And great support.

If I’m not mistaken there is a tiny little issue: A racing condition, that if you use the unresolved configuration as source of the dependency and the dependency has a dynamic version, it could be that the resolve of artifacts and the descriptor come in different versions. (Like because a new version was just published.) Unless of course, your (filesystem/memory) cache prevents this. (It probably won’t happen - until the first time that I’m not around to explain or I’ve forgotten about this vast possibility.) But I’ll just use the resolved configuration or just compare versions afterwards.

Second, I guess this won’t work, if the resolver specifies an independent pattern for the Ivy file via .IvyArtifactRepository:ivyPattern(java.lang.String), although I haven’t tried.

I can’t find the button to mark my question “answered”. If this is something only employees can do, I’m more than happy with your answer!


(Peter Niederwieser) #6

ad1. You might be able to resolve artifacts and descriptor together, and separate them later.

ad2. You could potentially declare further repositories to solve this, although it doesn’t exactly feel like a nice solution.

Unfortunately, only moderators can mark a question as answered. I’ll gladly do so.


(Hugh Greene) #7

I have a slightly different requirement – feel free to tell me to move this to a new topic.

Unless I’m missing something, the method described above seems to only let you get at the ivy files for first-level module dependencies, as returned by Configuration#getAllDependencies(). I want to get the ivy files for the full transitive set of dependencies, and I’m planning to try something like the following.

Does it sound like a plausible solution? Is there a simpler way?

  • Resolve all dependencies as normal. * Create an entirely new configuration at runtime (detached, probably). * Traverse the full set of ResolvedDependencies, and add a new (non-resolved) dependency to the new configuration. May be some cleverness required here to only add ones which would correspond to ExternalModuleDependency instances.

  • These dependencies can be added as a flat list; we don’t need to reproduce the original dependency graph structure. * For each such dependency, add just one artifact, the Ivy file. * Now resolve this new configuration, and pull out the Ivy file names.