Hi,

So we're starting to build out a graph of build items, with our source sets and 
jvm binaries (and publications). At the moment, this is pretty basic, where you 
can define some source sets and define some jvm binaries and attach the source 
sets as inputs to the binaries. Or you can attach a component as input to a 
publication.

There are a few different types of build items that we need to model:

1. Something that already exists and does not need building. These things are 
only consumed in the current project. You need to be able to define it and 
configure some stuff about how to use it. For example: here is a java source 
set and it includes java source from this directory and that directory.

2. Something that is produced outside the project. Again, these things are only 
consumed in the current project. You need to be able to define a dependency on 
the thing and resolve it into something usable. For example: give me a jvm 
binary for 'org:gradle:gradle-core:1.5+' so that I can use it in my compile 
classpath, or give me the source set for project(':other') so I can generate 
some aggregate javadoc from it.

3. Something that is produced by the project. You need to be able to define it 
and configure some stuff about how to build it. For example, please produce a 
jvm binary into this classes directory, built from these input source sets and 
targeting this jvm version.

4. Something that is produced and consumed within the project. As above, where 
the configuration that describes how to build it also implies how to use it.

5. Something that is a view over some other things. For example, a composite or 
a filtered source set. These things are only consumed.

What's common here is that everything is consumable, but not everything is 
buildable by the current build. So, we need to come up with some API patterns 
for representing things that are only consumable and things that are both 
buildable and consumable.

One option is to use read-only super types, and mutable subtypes, something 
like (this is just to demonstrate the idea):

interface JavaSourceSet {
     FileCollection getSource();
     FileCollection getCompileClasspath();
}

interface ConfigurableJavaSourceSet extends JavaSourceSet {
    SourceDirectorySet getSource();
    ConfigurableFileCollection getCompileClasspath();
}

You would define and configure an implementation of ConfigurableJavaSourceSet. 
ClassesDirectoryBinary would accept any JavaSourceSet as input.

Another option is to use parallel types, and the mutable type can give you a 
read-only view of itself:

interface JavaSourceSet {
    FileCollection getSource();
    FileCollection getCompileClasspath();
}

interface ConfigurableJavaSourceSet {
    SourceDirectorySet getSource();
    ConfigurableFileCollection getCompileClasspath();

    JavaSourceSet toSourceSet();  // convert to usable view
}

ClassesDirectoryBinary would accept any JavaSourceSet or anything that can be 
converted to a JavaSourceSet.

Then there's the optional operation approach:

interface JavaSourceSet {
    SourceDirectorySet getSource() // may return a read-only instance that 
throws UnsupportedOperationException when you try to mutate it
    ConfigurableFileCollection getCompileClasspath() // may return a read-only 
instance
}


Thoughts? Preferences? Other options?


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