Hans Dockter wrote:
On Sep 2, 2009, at 1:57 AM, Adam Murdoch wrote:
Hi,
I've made a few changes to how you implement tasks over the last
month or so. Here's a bit of a summary, with some questions at the end.
1. You don't need to provide a constructor any more.
We now inject the project and name around the side directly into
AbstractTask. This means we can also inject other things, such as the
OutputHandler, without exposing this to the task implementations.
2. You can mark the 'main' method of a task with the @TaskAction
annotation. It automatically gets added as a task action.
3. There's some documentation:
http://gradle.org/latest/docs/userguide/custom_tasks.html
4. You can mark the input and output properties of a task using
annotations:
@InputFile
public File getConfigFile()
@InputDirectory
public File getTestClassesDir()
@InputFiles
public Iterable<File> getSourceDirs()
@OutputFile
public File getReportFile()
@OutputDirectory
public File getDestinationDir()
Currently, we use these annotations to apply some validation to the
task properties. The validation is added as a task action, so it is
performed just before the task is executed:
@InputFile/@InputDirectory: Check the property is not null, and the
specified file exists and is a file/directory
@InputFiles: Check the property is not null.
@OutputFile/@OutputDirectory: Check the property is not null, and
that the specified file can be created as a file/directory. Also
create the parent dir if it does not exist.
There's also an @Optional annotation, which switches off the not-null
check, and a @SkipWhenEmpty, which skips the task if the associated
@InputFiles property is an empty FileCollection.
I'd like to use these annotations to also:
- Wire up dependencies. For example, we know that build/classes/main
is an output file of both the compileTest and processTestResources
tasks, and an input file of the test task, so we could automatically
add the these as dependencies of the test task. We also know that the
classpath of the test task is actually the testRuntime configuration,
so we could automatically add its buildDependencies to the test task.
That would be very cool.
That is,
task intTests(type: Test) {
testClassesDir = source.intTests.classesDir // auto add
compileIntTest and processIntTestResources
classpath = configurations.testRuntime // auto add
testRuntime.buildDependencies
}
- Apply optimisation. For example, we know that build/classes/main
and testRuntime are input files of the test task, and that
build/reports/test is an output dir of the test task. We can skip
test if its input files have not changed since it last executed
successfully and if its output dir exists and is not empty. We can
decide whether its input files have changed by hashing them, or using
their timestamps, or the last successful execution time of the tasks
which produce those files.
One question I have is how to apply this to task actions which are
added to the task as closures:
task intTests(type: Test)
intTests.doFirst {
.. some setup ..
}
or
task explodedDistBase << {
.. copy some stuff ..
}
One option is to allow you to declare the input and output files of a
task:
task explodedDistBase(inputDirs: source.main.groovySrcDirs,
outputDir: distDir) << {
copy { from inputDirs; into outputDir }
}
where 'inputFile', 'inputDirs', 'inputFiles', 'outputDir', etc
correspond to the @InputFile annotation, etc, and are added as
properties of the task.
Could you explain a bit more the problem?
The problem is we don't know what the closure actions added to a task
are actually doing, so we can't validate, or wire up dependencies, or do
change detection. For example:
task integTest(type: Test) {
classpath = configurations.testRuntime
doFirst {
copy(from: explodedDistDir, into: "$buildDir/integTest")
}
}
We know that the 'classpath' property points to some input files for the
'integTest' task, because the Test class has the appropriate annotation
on the getClasspath() method. However, we don't know that the
'integTest' task will also use 'explodedDistDir' as an input directory
or "$buildDir/integTest" as an output dir when it executes. It would be
nice to have some way to declare these additional input and output dirs
for the task.
Adam
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email