I have a project where I use shake to generate a bunch of reports based on input-files, and run as a restful webservice. One reason why I chose Shake is that is should not rebuild anything if input-files have not changed (e.g. based on Digest, configurable via shakeOptions
).
I noticed that the processes would run even if I had just built them and no file change had happened in between runs. So I tried a simple example it should simulate the process of one of my builds
import Control.Monad.IO.Class
import Development.Shake
wanted = "foo.3"
main = shake shakeOptions $ do
want [wanted] -- (1)
"*.1" %> \out -> do -- (2)
liftIO $ putStrLn out
unit $ cmd Shell "touch" "foo.2"
"*.2" %> \out -> do need [out] -- (3)
unit $ cmd "touch" wanted
action $ unit $ cmd Shell "touch" wanted -- (4)
while the %>
rules never run - the action
rule is always done.
If I comment out (4) and create a file "foo.1" manually - the rule (1) is failing because it does not figure out that (2) -> (3) can build the result.
If on the other hand I comment out (2) and (3) and leave (4) - the rule runs even if "foo.3" exists and has been "built" by shake before.
I am using shake-0.15.11 in combination with shake - using shake runhaskell Main.hs --package shake
or shake exec -- testshake
does not make any difference. Compiler is GHC-8.0.2. All of this is done on a Linux (Mint).
I read How does Shake decide whether to rebuild a target? - from which I gathered that shake rebuilds stuff only if either the input-file(s) or the output-file change (where change is determined by the shakeOptions
configuration)
First of all, pat %> act
mean that you create the file-build-rule, which will be run for any file path witch will be accepted with the pattern pat
. It's mean that if some one call need [foo]
and pat ?== foo
then will be run the action act
with argument foo
. So, the action act
should to try build foo
.
Secondly, about action
, as wrote in the documentation:
The action will be run in every build execution (unless withoutActions is used).
And wand
defined like this: want = action . need
.
For example, I redesign your example with some assumptions about dependencies between your files. Namely, foo.3 need foo.2, foo.2 need foo.1 and foo.1 already exists (it's source).
wanted = "foo.3"
main = shake shakeOptions $ do
want [wanted]
"*.3" %> \out -> do
putNormal out
need [out -<.> ".2"]
unit $ cmd Shell "touch" out
"*.2" %> \out -> do
putNormal out
need [out -<.> ".1"]
unit $ cmd Shell "touch" out