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