# Two cases where the incremental API is lacking

**URL:** <https://discuss.gradle.org/t/two-cases-where-the-incremental-api-is-lacking/24266>\
**Category:** Help/Discuss\
**Tags:** plugins\
**Created:** [October 2, 2017, 5:44am UTC](https://discuss.gradle.org/t/two-cases-where-the-incremental-api-is-lacking/24266 "2017-10-02T05:44:56Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ned\_Twigg](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/ned_twigg/32/1516_2.png) [@Ned\_Twigg](https://discuss.gradle.org/u/Ned_Twigg)\
**Post date:** [October 2, 2017, 5:44am UTC](https://discuss.gradle.org/t/two-cases-where-the-incremental-api-is-lacking/24266/1 "2017-10-02T05:44:56Z")

</div>

I have two Gradle plugins which use the Gradle incremental API, but have to do wonky workarounds. Perhaps these use-cases aren’t worth supporting, but I just wanted to throw them out as possibly helpful testcases in case you revisit the API.

## A task that may modify its input

It’s generally a bad idea for a task to modify any of its inputs, but one notable counter-example is a code formatting task. Example:

1. Change `MyClass.java`, and its formatting is now bad.
2. Run `spotlessApply`, which uses Gradle’s incremental to run a formatter on only that one changed file.
3. If the user immediately runs `spotlessApply` again it ought to be up-to-date (in an ideal world), but it’s not because the file was changed by `spotlessApply`.
4. The third run of `spotlessApply` will now be up-to-date.

Ideally, there would be something like `IncrementalTaskInputs::setUpToDate(File, boolean)` or `InputFileDetails::setUpToDate(boolean)` that we could call after modifying a file so that the task would be up-to-date in step 3 instead of step 4.

That minor performance hit is not a huge deal, but there’s actually a bug that I missed for a long time hiding there:

1. Change `MyClass.java`, and its formatting is now bad.
2. Run `spotlessApply`, which uses Gradle’s incremental to run a formatter on only that file.
3. The user manually changes `MyClass.java` back to its pre-formatted content.
4. Run `spotlessApply`, which ought to run in an ideal world because `MyClass.java` has bad formatting. But because `step 2` was successful, and the content of `MyClass.java` is exactly the same as it was at the beginning of `step 2`, the task is marked as up-to-date, and the badly formatted file lives on.

We handle this by creating a synthetic extra file in the build directory which we treat as an incremental input. Into this file we store a timestamp and the file names that were changed in the previous round. That way we are able to detect and handle the obscure use-case above. This would be unnecessary if we had something like `InputFileDetails::setUpToDate(boolean)`.

[code change](https://github.com/diffplug/spotless/pull/146/commits/8f2fa2037d1156b00aff683a8626ffa2c0a87900), [bug](https://github.com/diffplug/spotless/issues/144), [full PR](https://github.com/diffplug/spotless/pull/146)

## A task where a file’s output files might depend on its content

There are some cases where, for each input file, the name and number of its output files might depend on its content. But with the current API, when a file is removed or changed, there is no way to get information on its previous content.

We handle this by storing this information ourselves in a special file in the build directory.

Ideally, there would be something like `InputFileDetails::setMetadata(Object serializableMetadata)` which would be available in future runs for changed and removed files  
as `InputFileDetails::getMetadata()`.

[code example](https://github.com/diffplug/image-grinder/blob/37a4346e0ffdbe4675551fd8e73d37cdb72ff573/src/main/java/com/diffplug/gradle/imagegrinder/ImageGrinderTask.java#L103-L153), [test case where this is useful](https://github.com/diffplug/image-grinder/blob/37a4346e0ffdbe4675551fd8e73d37cdb72ff573/src/test/java/com/diffplug/gradle/imagegrinder/ImageGrinderPluginSizeDependentTest.java)

## Probs not your top priority

Right now, the incremental API assumes:

1. None of the inputs will change (probably a pretty good assumption)
2. Responding to a changed or removed file will not require any information about the previous content (an okay assumption for most Java, not great for other kinds of tasks)

If you’re looking for simple but useful tasks which don’t meet these two assumptions, see the links above.

Thanks again for Gradle! Can’t believe the consistent improvement, release after release.

---

<div class="post-metadata">

**Author:** ![Moe](https://avatars.discourse-cdn.com/v4/letter/m/ad7895/32.png) [@Moe](https://discuss.gradle.org/u/Moe)\
**Post date:** [March 19, 2018, 9:46am UTC](https://discuss.gradle.org/t/two-cases-where-the-incremental-api-is-lacking/24266/2 "2018-03-19T09:46:54Z")

</div>

Did you get any reply outside this thread, @Ned_Twigg? We’re currently facing problem #1 as well.

A proper solution to the first problem would be nice, since that use case is not too uncommon.

---

<div class="post-metadata">

**Author:** ![Lance](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/lance/32/787_2.png) [@Lance](https://discuss.gradle.org/u/Lance)\
**Post date:** [March 19, 2018, 11:28am UTC](https://discuss.gradle.org/t/two-cases-where-the-incremental-api-is-lacking/24266/3 "2018-03-19T11:28:23Z")

</div>

Perhaps you could have two tasks

1. A Formatter task which formats files in `src/main/java` but writes changes to `$buildDir/formatted/main/java`
2. A Copy task which copies from `$buildDir/formatted/main/java` to `src/main/java`

Each of these two tasks would have separate input and output directories so you can benefit from up-to-date checking

---

<div class="post-metadata">

**Author:** ![Ned\_Twigg](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/ned_twigg/32/1516_2.png) [@Ned\_Twigg](https://discuss.gradle.org/u/Ned_Twigg)\
**Post date:** [March 19, 2018, 3:52pm UTC](https://discuss.gradle.org/t/two-cases-where-the-incremental-api-is-lacking/24266/4 "2018-03-19T15:52:49Z")

</div>

Nope. @uklance’s suggestion or the code change links above are all I’ve got.
