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.

This is the way the meta-jb (my project) builds are setup. It used to be one big monolithic ant build with lots of different targets and now I've superimposed gradle projects onto it. (Interesting side-note: the reason I've abandoned maven here is because the pom.xml's produced were uglier than gradle's nice clean ones.)

In some cases, I could have moved things around but some of these projects are so small and for some things it's a lot easier to navigate around one tree than a dozen different full-depth trees.

For our project, in the root we have:
/src/main... etc.
/std/build.gradle, settings.gradle
/std/core, /std/util, etc.
/ext/
/ext/extract, /ext/util, etc.

"std" contains all of the main sub-projects that are managed and versioned together. The dependencies in those sub-projects are of the project( ":foo" ) variety.

"ext" contains separately released projects that are independent. They depend on other project artifacts just like any other dependency using the maven-style gradle-ized coordinate groupId:app:version.

In both cases, all of the build.gradle files have sections like:

compile {
  include( "org/progeeks/foo/**" )
}

The only odd thing is configuring resources like that seems to use an entirely different syntax.

For the most part, this works great... until it doesn't. And when it doesn't one gets very strange behavior.

Since javac will happily compile anything that it finds the source for if it doesn't also find a class on the classpath, and since we're building everything out of the same source tree, any mistakes in dependency specification (or "excludes" in some cases) will cause those .class files to be duplicated in the local jar.

This can also have a cascade effect. I think I've seen cases where if a project's dependencies include an old version of a .class file for a class they shouldn't have and the compiling project is dependent on a newer version then it will get recompiled.

At any rate, it should be easy to see that one little mistake can cause some very strange classpath behavior in trying to figure out why updating "util" isn't causing a certain class to update.

I'm not sure this is a problem gradle can solve but it's something to be aware of for any going down this road.

Actually, is there a way to limit the classes included in the build jar file? If I could give it a similar set of include()/exclude() lines as in the compile {} configuration then at least the errors wouldn't propagate silently.


- 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?


This is probably not related but my only other project pain has to do with the compile test cycle.

It used to be that we had some junit helper classes that depended on our util module. The util tests used these helper classes to test the util classes. In Ant this was ok because all project source was compiled and then all test code was compiled and run.

In gradle (and maven, and etc., etc. any other project-based build system), each project is an island and must be "fully built" before another project gets to use it. This adds a sort of artificial circular dependency since to compile the junit helpers one must full build util which includes testing the jar which requires the junit helpers, etc..

It's sort of too bad that project -> project dependencies can't have their tasks interleaved such that I'd get util:compile, junit:compile, util:test, junit:test, etc..

I realize there are several reasons that this setup was fragile but it was really convenient. Probably completely unrelated to "java project source layout" though.

-Paul




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

   http://xircles.codehaus.org/manage_email


Reply via email to