Tom Eyckmans wrote:
2009/9/16 Adam Murdoch <[email protected]
<mailto:[email protected]>>
Steve Appling wrote:
Adam Murdoch wrote:
Steve Appling wrote:
I have not been paying enough attention to the source
set changes, but one item caught my eye today that I
really would like to see changed.
I fully support the concept of source sets where you
have groups of source divided by function: main, test,
integTest, etc. This is great!
I don't, however, like the inclusion of the language
as part of the task name. I don't think that the user
should have to know whether to call compileGroovy or
compile or compileScala. I have been bit several
times now by calling project:compile and nothing
happens. There is a compile task, it just does
nothing. I didn't know to call project:compileGroovy.
I'm curious why you're calling the compile task from the
command-line? Not that what you point out above isn't a
problem, I think it is. If we know what your use case is,
we can come up with a solution.
The first time I ran into this was a dependency problem in the
gradle-ui project. It has:
compileTest.dependsOn project( ':gradle-core' ).compileTest
This is now broken because "compileTest" doesn't do anything.
It needs to now be compileTestGroovy. I didn't know that and
it took me a while to puzzle out.
Aside - Perhaps you could suggest a better way to do this. We
needed to have the tests in the gradle-ui project depend on
the tests in the gradle-core project. It seemed that this
should be easier, but we solved it with the above task
dependency and a configuration of:
testCompile files(project( ':gradle-core'
).dependencyProject.source.test.classesDir)
I think the best option is for projects to consume gradle-core's
test classes using exactly the same mechanism as they do for
gradle-core's production classes. Currently, we publish a jar
containing the production classes to a configuration, and the
other projects pick this up using a project dependency. We should
do the same for the tests, though we might just publish the test
classes dir, rather than bothering to jar them up.
Then, the auto-wiring will pick up the correct dependencies,
without anyone needing to explicitly add dependOn compile or
compileTestGroovy or whatever.
Something like:
In gradle-core:
configurations {
testFixtures
testFixturesRuntime
}
dependencies {
testFixtures source.test.classes, source.test.compileClasspath
testFixturesRuntime source.test.runtimeClasspath
}
In gradle-*
dependencies {
testCompile project(path: ':gradle-core', configuration:
':testFixtures')
testRuntime project(path: ':gradle-core', configuration:
':testFixturesRuntime')
}
Later I noted that the gradle-ui/src/main/groovy only contains
java files and I wanted to compare the compile speed for
building this under groovy and under java. I was running
gradlew :gradle-ui:compile and comparing the performance with
a java directory and a groovy directory. Surprisingly the
groovy one was faster - but only because the compile task
doesn't do anything when you have the groovy directory. After
comparing using the correct tasks I saw that it compiled about
1.5 sec faster when under the java directory. I plan to check
it in this way. This isn't a common thing to do, but it
pointed out an area of confusion to me. I do think that
people call compile (and certainly test) directly and they
shouldn't have to specify the language.
Perhaps we should rename 'compile' to 'compileJava', and add a
'compile' task which depends on {compileJava, compileGroovy,
compileScala} as appropriate?
I also find it really ood to have to specify the language here, I
thought we planned on having a distinction between main and test
source sets and have the compile and compileTests as tasks that
compile all main source sets and compileTests compile all test source
sets.
I'm curious why you would want to do this? What use cases do you have in
mind?
Right now, source sets are untyped, so there is no distinction between
which are production source sets and which are test source sets. I still
think it is a good idea to type them somehow. My plan was to go slowly
at this, and leave them untyped for the 0.8 release. Then, we can see
how they are being used and what does and does not work, and address
that in later releases.
I'm not, for example, 100% convinced that 'main' and 'test' is the right
way to slice them. It feels to me we want a more descriptive slicing,
something like:
- library
- application
- web app
- unit tests
- integration tests
We might allow multiple of the 'roles' to be applied to a source set.
One option would be to allow plugins to be applied to a source set:
source {
main {
usePlugin 'java-application' // (1)
mainClass = 'org.gradle.BootstrapMain'
usePlugin 'library' // (2)
api {
exclude '**/internal/*
}
}
test {
usePlugin 'library' // (3)
}
integTest {
usePlugin 'integration-test' // (4)
}
}
Where
(1) might add a dist task which creates a Zip containing launcher
scripts, the runtime classpath, the main jar, plus anything from
src/dist. Similarly, it might also add sourceDist, distTar, distTarGz
and explodedDist tasks which do the same thing in different formats. It
might also add the dist archives to the 'dists' configuration.
(2) might add the javadoc task, and wire it up so it is included in the
dist image. It might also add an apiJar task, and include that Jar in
the 'api' configuration.
(3) might publish the test classes api to the 'testFixtures'
configuration, and the test classes impl to the 'testFixturesRuntime'
configuration.
(4) might add in an integTest task which runs against the main jar from
the dist image, rather than the main classes dir.
We might default to main { usePlugin 'library' } and test { usePlugin
'unit-test' }. Or maybe just test { usePlugin 'unit-test' }.
We still get the distinction between production and test source sets,
but we end up with a model that is much, much richer. We could also then
fix up some odd things like the fact that the war plugin disables the
jar task.
To limit the gradle -t output we need to have a way to segment the
output, like for synthetic tasks for source sets only show the global
tasks that execute all of the main/test source set compiles/tests/....
This problem is independent of what we do with source sets, and affects
anyone with large builds regardless of how the tasks get added.
We really need some way to distinguish between the important tasks that
are intended for a user to run from the command-line, and all the
internal tasks. Personally, I like John's suggestion of having gradle -t
show only lifecycle tasks by default, and maybe having gradle -t --all
show all the tasks.
Additionally, gradle -t might take a set of task name patterns, eg
gradle -t compile*
Or perhaps we should get some HTML project reports happening, which
could potentially offer a better way of exploring and navigating the
tasks of the build.
Adam