Open tgross35 opened 8 months ago
I think this would probably create a long-tail of tricky issues. I've had the experience with a few build systems that sometimes things get cached when they shouldn't, like if a file on disk, environment variable, or binary changes, but the build system isn't aware of it. So I'm open to adding this, but only if it has a simple, minimal implementation which is easy for users to understand. I kind of suspect that this isn't possible, but I'll leave this open in case someone can come up with something clever.
Something that I have done in the past is use ||
in the command to short-circuit the recipe. This can work well for simple things, but can get a little clumsy as the logic gets more complicated (as in @tgross35's original example).
E.g.
configure:
[ -f configured ] || ./run-slow-process-to-configure.sh
In this example, it just checks for the existence of the file configured
, and if it exists, it doesn't do the rest.
If we could better structure this sort of short-circuiting in just
this might provide a straightforward way for users to define how they want to control any skipping behaviour in recipes.
Creating another recipe that defines the logic might be a natural way to achieve this.
configured-file-exists:
[ -f configured ]
Then it would be a case of deciding how to best express this requirement.
E.g. an attribute
[short_circuit(configured-file-exists)]
configure:
./run-slow-process-to-configure.sh
As part of the recipe line:
configured-file-exists || configure:
./run-slow-process-to-configure.sh
Or some other way.
Another approach that leverages the existing method for defining dependencies. Create independent recipes for each of the alternative branches and then a "gate" recipe as the mechanism to combine them.
[private]
check-if-already-configured:
# do the check
[private]
do-actual-configure:
# do the configure
configure: (check-if-already-configured || do-actual-configure)
I like that this approach leverages the existing recipe mechanism, although it does lean into having a recipe failing (albeit with a path to recover the overall run).
Hi, I found this issue after having implemented a first draft for our own solution :
# Handle recipe cached completions
# completion cache directory
completions_cache_dir := justfile_directory() / ".recipe.completions"
clear_cached_runs:
@rm -rf {{completions_cache_dir}}
@echo "Completions cleared"
# exec a recipe only if it has not been successfully completed yet
cached_run recipe:
#!/usr/bin/env sh
if
test -f {{completions_cache_dir}}/{{recipe}}.completed
then
echo "'{{recipe}}' already completed"
else
just "{{recipe}}"
mkdir -p {{completions_cache_dir}}
touch {{completions_cache_dir}}/{{recipe}}.completed
fi
######################################
# ----- EXAMPLES ----- #
# test recipe (this is a syntaxe test, we'll have to declare 1 more line for each recipe)
init_mob:
@echo "INIT_MOB"
test_mob: (cached_run "init_mob")
@echo "TEST_MOB"
build_mob: (cached_run "test_mob")
@echo "BUILD_MOB"
publish_mob: init_mob build_mob
Using this example :
$ just test_mob
'init_mob' already completed
TEST_MOB
$ just build_mob
'init_mob' already completed
TEST_MOB
BUILD_MOB
$ just publish_mob
INIT_MOB
'test_mob' already completed
BUILD_MOB
Would be awesome to have a special syntax for that ! 🚀
For quite a few CMake projects, I have a separate recipes for configuration and build, with
configure
being a dependency ofbuild
. Normally the configuration does not need to be rerun unless variables change, and I would prefer it runs as little as possible because it can sometimes take longer than the build.Currently I have something a bit messy that stores a hash of all captured variables to check if anything changed:
My suggestion is to add a way to do this by default. The above would become:
And Just would need to do the following:
A more flexible alternative is to have the user specify what gets set as a cache key. This would be easier for Just to implement too, but is less user friendly.
This is slightly related to https://github.com/casey/just/issues/867 since a lot of the use of file dependencies is cache.