On 08/09/2011, at 1:54 AM, davide.cavestro wrote:

> Just got the ugliest workaround running. Having a multiproject that includes
> some projects, and every project having only external dependencies, it
> simply introduces before /compileJava/ a dependency on the maven install
> task for projects (within the multiproject) related to external
> dependencies.
> 
> It's only a raw attempt to mimic a sort of /smarter dependency resolution/.
> 
> 
> This workaround is only for multi-project builds... and that's a pity, but
> if I check out only a single project, it continues to build downloading
> dependencies from the maven repo.
> 
> Any remark/suggestion?

If you want to substitute in projects from within the same (multi-project) 
build, as it sounds like you're doing above, another approach might be: Once 
the build scripts for all projects have been executed, run through the set of 
dependencies, and replace external dependencies that refer to projects in the 
same build with actual project dependencies.

For example, in the root build.gradle:

gradle.projectsEvaluated {
    allprojects {
        configurations.each { config ->
            config.dependencies.withType(ExternalDependency).each { dep ->
                def targetProject = findTargetProject(dep)
                if ( targetProject ) {
                    config.dependencies.remove(dep)
                    dependencies.add(config.name, targetProject)
                }
            }
        }
    }
}

def findTargetProject(ExternalDependency dep) {
    // iterate over all projects, look for match on group+name, return if found
}

(this code probably needs a tweak based on which version of Gradle you are 
using, but you get the idea)

What's nice about this approach is that you get all the goodness of Gradle 
knowing about the dependencies between the projects: IDE support understands 
this, you can use 'buildNeeded' and 'buildDependent', etc.

For projects outside the build, you'd need to use a different approach. One 
option: Once all the projects have been evaluated, run through the set of 
dependencies. For each one which refers to a project that can be built locally 
(however it is you decide that), add an 'install<Project>' task of type 
GradleBuild, which runs the install task for the project. Then, add a dummy 
file dependency to the configuration which depends on this install task:

gradle.projectsEvaluated {
    allprojects {
        configurations.each { config ->
            config.dependencies.withType(ExternalDependency).each { dep ->
                def targetProjectDir = findTargetProject(dep)
                if ( targetProjectDir ) {
                    def installTask = rootProject.task("install$dep.name", 
type: GradleBuild) {
                        dir = targetProjectDir
                        tasks = ['install']
                    }
                    dependencies.add(config.name, files() { builtBy installTask 
})
                }
            }
        }
    }
}

def findTargetProjectDir(ExternalDependency dep) {
    // Figures out where to find the project on the local filesystem, if 
available.
}

This is definitely a use case I want to tackle soon after Gradle 1.0 is 
available. We'd start probably with a plugin that packages up the above logic. 
You'd apply the plugin and provide us with some mapping from external 
dependency to target project directory. We'd then improve the plugin over time:

* Add some support to the IDE plugins, so that locally available projects are 
dragged into the IDE project with the appropriate 
dependencies between them.

* Use the artifacts directly out of the external projects, as we do for project 
dependencies, rather than routing through maven cache.

* Add a conventional location to look for local projects, and use them 
automatically if found. For example, I might just check out a bunch of source 
trees into, say, a '~/gradle' directory and Gradle will just wire them together 
automatically.

* Make 'buildNeeded' work across build boundaries. Maybe make 'buildDependents' 
work across build boundaries in the other direction, so that it builds all 
local projects that depend on the project.

* Make external builds first-class citizens, so that you can refer to their 
tasks and publications directly from the build and the command-line, see them 
in the UI, and so on. By doing this, buildSrc can become a regular external, 
stand-alone project which happens to live in a conventional location.

There's lot of interesting stuff we can do in this space.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply via email to