Tom Eyckmans wrote:
2009/9/18 Adam Murdoch <[email protected]
<mailto:[email protected]>>
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?
Exactly what you are suggesting below depending on the type of sources
have different tasks.
I'm still not sure why you would run gradle compile from the
command-line. What would you do with the results? You can't use the
classes for anything without running more tasks.
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.
Good plan
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
Totally agree, main and test should not be the only slices possible.
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)
}
}
I really like this idea, not sure if we need a new concept for the
'usePlugin' part, usePlugin is fine by me but it might be confusing
for starters to have usePlugin for sourcesets and toplevel in the
build script (project-reports plugin ?).
I wonder this too. I'm leaning towards the above.
I suspect that source sets won't be the only domain objects that we will
want to extend at runtime using plugins, whether that's directly via
usePlugin() or indirectly with some kind of type or role property). I
can imagine builds, repository containers, configurations, dependencies,
and maybe even tasks should be extensible in this way.
The question is, do we apply plugins to projects only, and have some
other type-specific mechanism for other types, or do we generalise the
plugin concept to allow pretty much any type to be extended via
usePlugin(). In other words, what's so special about projects that they
are the only extensible things that are extended using usePlugin()?
Another option is to rename usePlugin() to something that fits a bit
more generally.
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*
I like both.
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.
Perhaps a gradle console would be nice also
run 'gradle' to start the console
and be able to do:
cd gradle-core <enter>
-t <enter>
show only tasks of the gradle-core subproject
I like this.
Adam