Hans Dockter wrote:

On Aug 13, 2009, at 11:38 PM, Adam Murdoch wrote:

Hi,

I'd like to figure out a bit of a design for the so-called 'source directories' feature. Basically, this feature is about making the Java plugin, and all the plugins based on it, more flexible in how java projects are laid out, and what happens to the various source files that make up a java project.

I'd like to start with use cases we would need to solve.

Right now a java project:

- Has some production source files. These are compiled and assembled into a jar or war. Optionally some unit tests or quality checks are run against them.

- Has some test source files. These are compiled and run as unit tests against the production classes.

This is all nice and simple. It works fine for, say, an open source library project. However, I've not seen a decent sized java project where this is sufficient.

I'd like to find out about those use cases you might have where this simple model does not work well. Here's some example use cases:

- Multiple projects sharing the same source directory. For example, this might happen when a legacy monolithic Ant build is chopped up into a bunch of Gradle projects.

- Production and test source in the same source directory. Not necessarily a great idea, but some people do this.

- Production source with an api and implementation. For example, you might want to use different checkstyle rules for each, or javadoc just the api, or you might want to end up with an api jar and an api + impl jar.

- Test source contains test fixture classes which are used by other projects. For example, you want to jar up your test classes and publish the test fixture jar alongside the production jar.

- Multiple test suites, each in a separate source directory and with separate classpaths. For example, you might have functional tests or performance tests which you don't want the 'test' task to execute.

- Compile different parts of the source against different java versions.

- Generated source, or generated bytecode.

Anyone have any other use cases?

I have forgotten to mention one other use case. It is discussed in an old posting on this list: http://markmail.org/thread/6ncjp7dxtbq5et5f

It is more related to project dependencies for the build script classpath. But I think it belongs to this discussion.


I hadn't forgotten about this one. It feels more like a build composition problem to me, so I was going to leave it for when the settings file is removed.

Some possible approaches:

1. Use a buildSrc build.

This is similar to what we do now with the buildSrc project. We would generalise the buildSrc concept, so that every build may also have an associated buildSrc build, which you can add projects to when you define the structure of the main build. Then, prior to evaluating the main build, Gradle builds all the projects in the buildSrc build, and adds their artifacts to the main build's classpath.

2. Aggregate builds.

This is similar to what we've talked about for Gradle's website build. Basically, you can declare dependencies on projects in another local build, and when the dependency is resolved, Gradle takes care of building the dependency in the other build. For example:

buildscript {
   classpath name: 'some-other-project' {
       buildfile: 'some-other-project/build.gradle'
   }
}

This is just a regular module dependency, except that we also tell Gradle that when the classpath configuration is resolved (ie just before the build script is evaluated), it should build configuration 'default' in project ':some-other-project' in the build defined by 'some-other-project/build.gradle'.

The buildSrc project would be changed to work the same way, and an implict dependency similar to the above would be added to every build.

The benefit of this option over option 1, is that you can use these types of dependencies for any configuration, not just for the build script classpath. For example, the buildSrc artifacts could be used for both the build script classpath, and the java compile classpath for a project. You can also easily customise the location of the buildSrc project.

3. Allow project dependencies in the classpath declaration of a project.

Here, you would be able add a classpath dependency on another project in the same build. Gradle would take care of building the artifacts in the other project before evaluating the build script. For example:

classpath {
   dependencies project(':project1')
}

Gradle would evaluate project1 and build its default configuration before evaluating this build script.

This is a really interesting option. We could change project evaluation into a task, and the project evaluation task would simply dependsOn configurations.classpath.buildDependencies. We get all the dependency ordering and cycle detection for free. You can doFirst() or doLast() or enable = false or onlyIf() or gradle -x subproject or whatever. And any new stuff we do for tasks (eg change detection, parallel execution, and so on), would also work for project evaluation.

4. Combine 2. and 3.

This is where we really get some interesting combinations. We end up with Gradle building the DAG across multiple builds, wired together based on the artifacts that projects publish and use in build scripts or compilation or runtime or all 3. The projects in different builds remain loosely-coupled, and yet Gradle wires them up into a single aggregate build.


Adam


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email


Reply via email to