On 23/10/2010, at 2:05 AM, chris wrote:

> 
> Hi,
> 
> I'm try to do a multi-project build, and to keep my sanity I'm checking the
> dependencies on a configuration I have. The problem is when I do this, it
> appears to alter the list of files attached to this later on!
> 
> So I have this kind of thing:
> 
> rootProject build.gradle:
> 
> subprojects
> {
>    apply plugin: 'java'
> 
>    configurations {
>        configServerTier // server tier jars
>        configServer { // server-tier, test jars, libraries
>            extendsFrom configServerTier, configTest
>        }
>    }
> 
>    // etc...
> 
>    afterEvaluate { project ->
> 
>        if (project.hasProperty('specialProject'))
>        {
>            // if following is commented, I get all my dependency libraries
> for the configServer configuration, otherwise I just get project artifacts!
> WHY?
>            println "configServer: " +
> project.configurations.configServer.files.collect { it.name }
> 
>            task testJar (type: Jar, dependsOn:
> subprojects.configurations.configServer) {
>                into('test') {
>                    from configurations.configServer
>                    from configurations.configServer.allArtifactFiles
>                }
>            }
>        }
>    }
> }
> 
> 
> subproject :core build.gradle:
> 
> configurations {
>    compile { extendsFrom configServer }
> }
> dependencies {
>    compile project(':util')
>    configServer 'ecs:ecs:1.4.2'
>    configServer 'com.thoughtworks.xstream:xstream:1.3'
> }
> 
> 
> subproject :anotherProject (depends on above core project) build.gradle:
> 
> specialProject = true
> dependencies {
>    // depend on all other projects
>    rootProject.standardProjects(exclude:this.project).each {
>        configServer project(path: it.path, configuration: 'configServer')
>    }
>    compile project(path: ':core')
> }
> 
> 
> When the println is commented I get the ecs and xstream jars in my Jar as
> well as artifacts through the serverConfig configuration. When the println
> is executed, all I get is the artifacts - no ecs or xstream.
> 
> What's going on? Why would a println affect the configuration?

There's two things going on here.

First, when a configuration is resolved (for example, when iterating over its 
files) the result is cached and the same set of files is always returned.

Second, the afterEvaluate { } closure of a project is executed immediately 
after the build script for the project is executed, but not necessarily after 
the other build scripts which affect the project have been executed.

In your example, the build script for :anotherProject executes first. When its 
afterEvaluate { } closure executes, the build scripts for :core and :util 
projects have not been executed. The println causes the configuration to be 
resolved and the result cached. And since :core's build script has not been 
executed, the dependencies for ecs and xstream have not been added.

You're supposed to get an exception when you modify a configuration in some way 
after it's been resolved, but you've run into a situation where it's broken: 
http://jira.codehaus.org/browse/GRADLE-1120

Configuration ordering is a bit of a problem at the moment, and can lead to 
some really confusing behaviour. We want to make some changes to improve this.

One part of the solution will be to have things fail when you try to configure 
something which has already been 'executed'. Adding dependencies to a 
configuration after it has been resolved is an example of this. Or adding 
dependencies to a task after the graph has been built. Or changing a task 
property after the task has executed. And so on.

Another part will be to provide better ways to declare what your code needs. 
For example, your println really only works once the configServer configuration 
has been fully configured. So we might offer a whenConfigured { } method on the 
Gradle domain objects, so you can do something like:

configurations.configServer.whenConfigured { println ... }

Or perhaps you might be able to say that the afterEvaluate { } closure 
dependsOn the configServer configuration.

The final part is to have Gradle take care of more (or all) of the ordering for 
you. For example, Gradle can figure out that that the whenConfigured { } 
closure above must be deferred until after the :core and :utils projects have 
been configured, because of the transitive project dependencies in the 
configServer configuration.


--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz

Reply via email to