Ivy transitive dependency resolution not working?


(Marcel Overdijk) #1

I’ve the following snippet in my build.gradle:

project.configurations {
   compile
  }
    project.repositories {
   ivy { url "../local-repo" }
   mavenCentral()
  }

(actually it’s added by a custom plugin but I don’t think that’s relevant for the problem).

I’ve also the following dependency:

dependencies {
 compile "com.mycomp:mod-a:1.0"
}

This dependency is stored in the local ivy repo and the ivy.xml looks like:

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven">
 <info organisation="com.mycomp"
  module="mod-a"
  revision="1.0"
  status="release"
  publication="20121220150745"
 />
 <configurations>
  <conf name="compile" visibility="public"/>
  <conf name="default" visibility="public"/>
 </configurations>
 <publications>
 </publications>
 <dependencies>
  <dependency org="com.mycomp" name="mod-b" rev="2.0" conf="compile->default"/>
 </dependencies>
</ivy-module>

when running gradle dependencies I can see the dependency to mod-a as defined in build.gradle, however the transitive dependency to mod-b is not shown/picked up.

Am I doing somethin wrong here?


(Marcel Overdijk) #2

Note that when I use Apache Ant/Ivy (without Gradle) the transitive deps work as expected.

<target name="resolve" description="--> retrieve dependencies with ivy">
     <property name="ivy.local.default.root" value="/path/to/local-repo" />
     <property name="ivy.local.default.ivy.pattern" value="[organisation]/[module]/[revision]/ivy-[revision].xml" />
        <ivy:retrieve />
        <ivy:artifactreport tofile="${basedir}/target/deps.xml" />
    </target>

In this case deps.xml contains both mod-a (direct dep) and mod-b (transitive dep) as expected.

Also note that I’m using the same Ivy local-repo.


#3

I suspect that the problem is that your dependency is marked with ‘conf=“compile->default”’. Gradle is resolving the ‘default’ configuration of your module, which does not have any declared dependencies.

You could address this in a number of ways:

  • Make ‘default’ configuration extend ‘compile’ * Remove the explicit ‘conf’ mapping for the dependency * Edit the explicit ‘conf’ mapping for the dependency to include ‘default’ on the LHS.

(Marcel Overdijk) #4

Yes this indeed to do with configurations and conf element. Weird thing is all module are published using Gradle Ivy Publish plugin but when connecting them it goes wrong.

To be more specific this is how my Gradle build looks like for module A:

apply plugin: 'ivy-publish'
  group = "com.mycomp"
version = "6.0"
  configurations {
 compile
}
  dependencies {
 compile "com.mycomp:mod-b:5.0"
 compile "com.mycomp:mod-c:5.0"
}
  repositories {
 ivy { url "../local-repo" }
 mavenCentral()
}
  publishing {
 repositories {
  ivy { url "../local-repo" }
 }
}

Note that it does not contain anything except custom “compile” configuration. The Gradle Ivy Publish plugin generates a ivy.xml which looks like:

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven">
 <info organisation="com.mycomp"
  module="mod-a"
  revision="6.0"
  status="release"
  publication="20130103092706"
 />
 <configurations>
  <conf name="compile" visibility="public"/>
 </configurations>
 <publications>
 </publications>
 <dependencies>
  <dependency org="com.mycomp" name="mod-b" rev="5.0" conf="compile->default"/>
  <dependency org="com.mycomp" name="mod-c" rev="5.0" conf="compile->default"/>
 </dependencies>
</ivy-module>

Now when running gradle dependencies for my mail Gradle build I get the original error message posted earlier: configuration:compile declares a dependency on configuration ‘default’ which is not declared in the module descriptor for group:com.mycomp, module:mod-a, version:6.0

I tried this in my main Gradle build file, but without success:

configurations {
 compile
 it."default" { extendsFrom compile }
}

However when I just remove the element and <dependency conf=… attribute from the generated ivy.xml files then it works as you also suggested. I probably can do this automatically with descriptor { withXml { closures but I would prefer an easier approach like extending the compile configuration.

Did I correctly extend the default configuration as mentioned above?


(Marcel Overdijk) #5

However when I just remove the element and <dependency conf=… attribute from the generated ivy.xml files then it works as you also suggested. I probably can do this automatically with descriptor { withXml { closures but I would prefer an easier approach like extending the compile configuration.

Did I correctly extend the default configuration as mentioned above?


(Marcel Overdijk) #6

… continued …

However when I just remove the conf element and conf attribute from the generated ivy.xml files then it works as you also suggested. I probably can do this automatically with descriptor { withXml { closures but I would prefer an easier approach like extending the compile configuration.

Did I correctly extend the default configuration as mentioned above?


#7

Your configuration syntax works for me. You can also try:

configurations {
     compile
     it."default".extendsFrom(compile)
}

or

configurations.add("default")
configurations.default.extendsFrom(configurations.compile)

Please note that the ‘ivy-publish’ plugin is marked as ‘@Incubating’ and is a work-in-progress. While it works in many cases (like combined with the standard ‘java’ plugin), it hasn’t been completed to the stage that all edge cases have been resolved (like using without the ‘base’ plugin).

Also note that we are currently introducing the concept of a SoftwareComponent to Gradle, which will have a significant impact on publishing. Things that currently work may not continue to work in the future.


(Marcel Overdijk) #8

Hi Daz,

Thanks for noting the ivy-publish plugin is incubating (I was aware) and the introduction of the concept of a SoftwareComponent. We will be happy to update or code in future releases when necessary.

For now I will take the approach removing the configuration.conf mappings and the conf attributes from the dependencies.

For reference for other users I copied in the code to do this below:

publishing {
 publications {
  ivy {
   descriptor {
    withXml {
     asNode().configurations.conf.each { it.parent().remove(it) }
     asNode().dependencies.dependency.findAll { it.@conf }.each { it.attributes().remove("conf") }
    }
   }
  }
 }