What is the recommended way of running some Action
if part of a file changes?
My use-case is given a file that I know exists (concretely elm-package.json
), run a shell command (elm package install --yes
) if part of the file changes (the dependencies
field).
It seems that the Oracle
abstraction exposes comparing a value to the last (via Eq
). So I tried a newtype
like:
newtype ElmDependencies = ElmDependencies () deriving ...
type instance RuleResult ElmDependencies = String
But now, I get stuck actually using this function of type ElmDependencies -> Action String
, since the rule I want to write doesn't actually care what the returned String is, it simply wants to be called if the String changes.
In other words,
action $ do
_ <- askOracle (ElmDependencies ())
cmd_ "elm package install --yes"
at the top-level doesn't work; it will run the action every time.
Your askOracle
approach is pretty close, but Shake needs to be able to
identify the "output" of the action, so it can give it a persistent name
between runs, so other steps can depend on it, and use that persistent name to avoid recomputing. One way to do that is to make the action create a stamp file, e.g.:
"packages.stamp" *> \out -> do
_ <- askOracle $ ElmDependencies ()
cmd_ "elm package install --yes"
writeFile' out ""
want ["packages.stamp"]
Separately, an alternative to using Oracle
is to have a file
elm-package-dependencies.json
which you generate from
elm-package.json
, write using writeFileIfChanged
(which gives you Eq
for files), and depend on that
file in packages.stamp
. That way you get Eq
on files, and can also
easily debug it or delete the -dependencies.json
file to force a rerun.