2009/3/18 Adam Murdoch <[email protected]>
>
>
> Tom Eyckmans wrote:
>
> Hi,
> During aSkype session on sunday (Hans & me) we thought of introducing a
> SourceDirectory concept to improve our compile/resource and test handling.
>
>
> I think this is a fantastic idea.
>
cool
>
>
> some of my first ideas:
>
> # Defining source & resource dirs:
>
> sourceDir('main') {
> dir('src/main/java')
> }
> resourceDir('main') {
> dir('src/main/resources')
> replaceTokens ( prefix : '${', suffix : '}' ) ( [
> tokenOne: 'valueOne',
> tokenTwo: 'valueTwo'
> ])
> }
> testSourceDir('main') {
> dir('src/test/java')
> }
> testResourceDir('main' {
> dir('src/test/resources')
> }
>
> a more advanced example (with jdk version specific code):
>
> sourceDir('main') { dir('src/main/java') }
> sourceDir('jdk14') { dir('src/jdk14/java') }
> sourceDir('jdk15') { dir('src/jdk15/java') }
>
> sourceDirGroup('jdk14'){ sourceDirs('main','jdk14') }
> sourceDirGroup('jdk15'){ sourceDirs('main','jdk15') }
>
> testSourceDir('main') { dir('src/test/java') }
> testSourceDir('jdk14') { dir('src/test-jdk14/java') }
> testSourceDir('jdk15') { dir('src/test-jdk15/java') }
>
> testSourceDirGroup('jdk14') { testSourceDirs('main','jdk14') }
> testSourceDirGroup('jdk15') { testSourceDirs('main','jdk15') }
>
>
> Some comments/questions:
>
> How would we deal with resources and source living in the same directory?
>
I think the solution to this would be to type the sourceDirs like we do with
artifact tasks, the type would define includes/excludes.
> production and test classes in the same directory?
> java 1.4 and java 1.5 classes in the same directory?
I think both are really nasty situations that should be avoided at all times
(compile/testCompile configuration concept is useless) but in the case that
it happens, I think we should just compile it twice and don't treat it in a
special way. Best possible scenario would be to define the
sourceDirs/testSourceDirs with includes/excludes (packaged based/ or
classname based (again abstract class issues probably when not following a
naming convention)) otherwise I think it is a lost cause and it really ought
to be separate dirs anyways :).
>
> How would we deal with a multi-language project, which has both java and
> groovy source, or java and c source, or whatever?
>
I think by typeing the sourceDirs we have a good handle on multi-language
projects, for groovy source the type would extend the java type and include
both java/groovy sources, I wouldn't go for multi-typed sourceDirs because
we would have to figure out a pretty difficult regexp expression merger (and
I'm not nearly smart enough for that :)).
>
>
> Why do we need source dir groups?
>
In case of the following sourceDirGroup:
sourceDirGroup('jdk14'){ sourceDirs('main','jdk14') }
You include multiple sourceDirs
- main
- jdk14
By grouping these source dirs you don't need to mention both dirs when
referencing the group.
>
>
> I'm not sure about how we should define and reference these domain objects.
> This is another type of domain object with a name and type, which you can
> add to the project, configure, and refer to, just like tasks, projects,
> configurations, repositories, etc. We should make the DSL for source
> directories consistent with the DSL for other domain objects with a name and
> type.
>
I agree that naming domain objects should be consistent all the way.
>
>
> Using http://docs.codehaus.org/display/GRADLE/Dependencies as a reference
> for what we want the DSL to look like, we should either put source
> directories in a context like repositories:
>
> sourceDirectories {
> SourceDirectory(name: 'api') {
> dir('...')
> }
> SourceDirectory(name: 'main') {
> dir('...')
> }
> TestSourceDirectory(name: 'test') {
> dir('...')
> }
> }
>
> or we should treat them the same way as tasks, something like:
>
> main(SourceDirectory) {
> dir('...')
> }
>
I like both perhaps a combo/split is also an option (amount of strings like
with taks but still grouped):
sourceDirectories { // type of the items defined in this block:
main {
dir('...')
}
}
testSourceDirectories {
test {
dir('...')
}
}
>
>
> or we should change the DSL shown on the wiki to match what you've got
> here.
>
> Personally, I would really like a DSL where I can refer to the domain
> objects using a groovy identifier, rather than a string (or even worse,
> forcing me to sometimes use a string and sometimes an identifier, like we
> currently do with tasks).
>
I agree we should pick one and also agree and I think that the groovy
identifier is way more flexible.
>
>
> Regardless, it might be a good idea if you added some of the stuff you've
> described here to the DSL wiki page, so we can see it in context with the
> other DSL stuff, which might help us figure out something consistent for all
> domain objects.
>
I'll update the wiki page this evening.
>
>
> # Define how stuff should be compiled
>
> // default by name and synhtetic
> compile('main') {
> // options
> }
> // or
> compileMain {
> // options
> }
>
> // custom compiles (naming optional)
> compile ( sourceDir('build/generated-java-sources') ) {
> // options
> }
> // or
> compile ('antlr-source-compile',
> sourceDir('build/generated-java-sources') ) {
> // options
> }
>
>
> What are these defining? compile tasks? some kind of domain object?
>
both a domain object and a task (more info in reply to the more generalized
idea)
>
>
>
> # Define how stuff should be tested:
>
> // default by name and synhtetic
> test('main') {
> // options
> }
> // or
> testMain {
> // options
> }
>
> // custom compiles (naming optional but required when you want to be able
> to use it from the command line)
> test (sourceDir('main'), testSourceDir('main') ) {
> dependsOn(...) ?
> // options
> }
> // with explicit name
> test ('slow-test', sourceDir('main'), testSourceDir('main') ) {
> // options
> }
>
>
> what are these defining?
>
both a domain object and a task (more info in reply to the more generalized
idea)
>
>
> # Define how stuff should be javadoc-ed
>
> javadoc('main') {
> // options
> }
> // or
> javadocMain() {
> // options
> }
>
> // custom javadoc
> javadoc('custom', sourceDirs('jdk14','antlr-sources') ) {
> // options
> }
>
>
> what are these defining?
>
both a domain object and a task (more info in reply to the more generalized
idea)
>
>
> # Define how stuff should be packaged
>
> defaultJar(JarTask, name: project.name) {
> mainCompile { // include the result of main compile
> // additional options includes/excludes ?
> }
> mainResources // include the result of main resources
> }
> // or
> defaultJar(JarTask, name: project.name) {
> main // all of main compile + resources
> }
>
> defaultSourceJar(JarTask, name: project.name, classifier: 'sources') {
> mainSources
> }
>
> defaultJavadocJar(JarTask, name: project.name, classifier: 'javadoc' ) {
> javadocMain
> }
>
> defaultTestJar(JarTask, name: project.name, classifier: 'tests') {
> mainTestCompile
> mainTestResources
> }
> // or
> defaultTestJar(JarTask, name:project.name, classifier: 'tests') {
> mainTest // all of mainTest test compile + test resources
> }
>
> defaultTestSourceJar(JarTask, name: project.name, classifier:
> 'test-sources') {
> mainTestSources
> }
>
> // this way it is very easy to define bundles:
> gradleExternalJavadocBundle(JarTask, name: 'gradle-external-javadoc' ) {
> main {
> package('org.gradle.external.javadoc')
> }
> manifest {
> // additional manifest instructions
> }
> }
>
>
> We will need some way to include the these things with a prefix, as not
> everything ends up in the root of an archive.
>
I agree, just a tought:
defaultJavadocJar(JarTask, name: project.name, classifier: 'javadoc' ) {
docs { // if not defined in this context it is a directory
'api-docs' {
javadocMain
}
}
}
>
>
> I think this is a very powerfull concept to use the task names to include
> the result of a compile/resources task in an artifact and I find it very
> natural but other views may differ.
>
>
> I agree. In fact, we should generalise it: you should be able to add any
> domain object which implements FileCollection (say) to an archive. Given
> that Configuration, Dependency, SourceDirectory, Archive, and all file
> producing tasks implement FileCollection, this makes it very easy to
> assemble archives.
>
I'm not sure if adding the FileCollection stuff on tasks is the best way to
go, I think tasks have a very clear responsibility that would get cluttered,
I would make the domain objects fronts for the task(s) (think of a resouces
domain object could be a front for a copy + tokenReplace tasks) behind them,
the domain objects would also be a perfect place for us to add logic to
detect if files have changed so we can skip compile/copy+tokenReplace... if
nothing has changed (in a doFirst call isCompileNeeded, skip when false), in
a doLast let the domain object know what the destination dir was of the
compile/...
>
>
>
> Adam
>
>