On 28/03/2013, at 2:43 AM, Daz DeBoer <[email protected]> wrote:
> G'day
>
> Now in master is a pretty cool new feature: you can now implement an
> 'incremental' task that is informed about exactly which input files
> have changed when the task is out of date.
> This is very useful for something like a C++ compile task, as it means
> that only the changed files need to be recompiled, rather than the
> entire set of inputs.
>
> I've got a 'draft' DSL functioning, and would appreciate any feedback
> you guys have. Here's a sample:
>
> class IncrementalSync extends DefaultTask {
> @InputFiles
> def FileCollection src
>
> @OutputDirectory
> def File destination
>
> @TaskAction
> void execute(TaskInputChanges inputs) {
> if (inputs.allOutOfDate) {
> FileUtils.forceDelete(destination)
> }
>
> inputs.outOfDate({
> FileUtils.copyFile(change.file, targetFile(change.file))
> } as Action)
> .removed({
> FileUtils.forceDelete(targetFile(change.file))
> } as Action)
> .process()
> }
>
> def targetFile(def inputFile) {
> new File(destination, change.file.name)
> }
> }
>
> Notes:
> 1. The way to implement an incremental task is to add a
> TaskInputChanges parameter to your @TaskAction method. This must be a
> typed parameter, and currently TaskInputChanges is the only parameter
> type we support (but there are plans to add more, like
> TaskOutputChanges). The reason for using a typed parameter is that
> this is the way the task tells us what it wants: I thought about an
> annotated parameter, but it seems kind of pointless when the
> annotation would imply the type anyway. (Perhaps we can add an
> annotation-based marker at a later stage, if it helps).
>
> 2. There are 2 discrete ways we report incremental changes:
> - If the _only_ change to the task execution state is changed input
> files, then TaskInputChanges.allOutOfDate() will be false, and only
> the added/changed/removed files will be notified to the
> TaskInputChanges.outOfDate() and .removed() actions.
> - In the case of non-file changes to task inputs (properties, task
> class) and changes to task output files, then Gradle will consider all
> input files to be out of date. In this case,
> TaskInputChanges.allOutOfDate() will be true, and every input file
> will be reported to the TaskInputChanges.outOfDate() action.
>
> 4. The reason for the chained action methods combined with a final
> process() method is that this allows us to stream changed inputs in
> any order, and does not require us to persist these changes for a
> subsequent method call. This is a little awkward, but doesn't force us
> to jump through hoops. We could implement a more discrete API on top,
> but it may be less efficient.
I think we should separate the two pieces, so you can say 'give me the out of
date input files' and 'give me the obsolete input files' separately. It's fine
if you can't ask for the obsolete inputs until after you've asked for the
out-of-date inputs, and if you can only ask for each of these once only.
>
> 5. I haven't yet got any DSL magic applied to the TaskInputChanges
> instance, so using a closure directly isn't (yet) possible. Not sure
> how important that is for this DSL, or how tricky it will be to add.
Currently, there are 2 parts to the DSL magic: magic to make the target object
extensible and magic to mix in the DSL. We'd want the DSL stuff but not the
extensibility stuff.
--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com
Join us at the Gradle Summit 2013, June 13th and 14th in Santa Clara, CA:
http://www.gradlesummit.com