Take the following task trees:
[install node] -> [npm install] -+-> [npm run compileSass ] + -> [npm run concatMinify]
+-> [npm run compileTypescript] +
[start docker] -> [run command in docker] -> [stop docker]
- the group of tasks can easily be defined as
f(inputs) = output_files
- but individually they can't, because some steps modify the environment
- you can't cache
start docker
...
- you can't cache
- if you could somehow cache the group, then you could avoid not just a task, but an entire toolchain
- ...but you can easily cache
f(dockerfile, input_files) -> output_files
- ...but you can easily cache
plugins {
id 'com.diffplug.cache-horizon'
}
cacheHorizon {
add 'nodeInstall', 'npmInstall', 'compileSass', 'compileTypescript'
inputsAndOutputs {
inputs.property('nodeVersion', nodeTask.nodeVersion)
inputs.file('package-lock.json').withPathSensitivity(PathSensitivity.RELATIVE)
inputs.dir('src/main/typescript').withPathSensitivity(PathSensitivity.RELATIVE)
outputs.file('build/index.js')
}
}
This will add two tasks with the following dependency arrangement
+------------------------------+
cacheHorizonIsCached -> | nodeInstall, npmInstall, ... | -> cacheHorizon
+------------------------------+
When cacheHorizonIsCached
executes, it looks forward to check if cacheHorizon
is able to be restored from cache. If it is, then it disables nodeInstall
, npmInstall
, etc. When cacheHorizon
eventually runs, it will just restore index.js
from cache, avoiding all the intermediate work.
DANGER no outside task should depend on anything within the horizon (e.g. test
dependsOn compileTypescript
is bad, it should instead depend on cacheHorizon
). It is fine if tasks within the horizon depend on anything outside the horizon (e.g. compileTypescript
dependsOn lintTypescript
is fine).
Usually you only need one cacheHorizon
per project. But if you want more, you can do this:
cacheHorizon {
named 'dockerHorizon', {
add 'dockerStart', 'dockerRun', 'dockerStop'
inputsAndOutputs { ... }
}
Now you'll have dockerHorizon
and dockerHorizonIsCached
tasks.
We started to implement it, got stuck, and found an easier way around. We're publishing what we did in case it helps you get to the finish line. See this issue for the latest on our progress. If somebody builds something else which solves this problem we'll link out from there.
Cache horizon uses Gradle's internal API, so there will be compatibility delays (e.g. when Gradle N comes out, it might be a little while until cache-horizon
has been tested and fixed for the new version).
- Maintained by DiffPlug.