Search code examples
haskellshake-build-system

How do I skip a shake Action?


I'd like to download a bunch of web pages with shake, then do some processing on them. However, I'd also like the option to download the pages outside of shake, tell shake I've done so, and let shake continue with the remainder of the processing steps. Right now I'm working step two, "tell shake I've done some of its work for it".

To give a minimal example, here's a very short shake script:

import Development.Shake

main = shakeArgs shakeOptions $ do
    want ["test.txt"]
    "test.txt" %> \_ -> liftIO (putStrLn "yikes!")

I would like to find a way to prevent this script from printing yikes! (but still updating the database entry for test.txt). Running this with --help, I see in part:

--touch                     Assume targets are clean.

Which sounds promising. However:

% rm -r .shake && ./test --touch
yikes!
Build completed in 0:01m

Perhaps it needs an explicit list of files to mark as new?

% rm -r .shake && ./test --touch test.txt
yikes!
Build completed in 0:01m

Okay. Well, the --help also lists this:

-o FILE, --old-file=FILE, --assume-old=FILE
                            Consider FILE to be very old and don't remake it.

I find that a little puzzling: we now have a "clean/dirty" metaphor and a "old/new" metaphor, and it's not clear how if at all they are related. Moreover, surely if the file was old that would mean we would want to remake it, right? In any case, it doesn't seem to do what I want:

% rm -r .shake && ./test -o test.txt
yikes!
Build completed in 0:01m

Okay... well, perhaps this option, which says the exact opposite of that one, will do what I want:

-W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE
                        Consider FILE to be infinitely new.

No dice:

% r .shake && ./test -W test.txt
yikes!
Build completed in 0:01m

This leaves me with several questions:

  • Most importantly: how can I ask shake just to update its database entry for test.txt without running the Action associated with test.txt?
  • What does --touch do, and why didn't that help?
  • What do -o/-W do, and why didn't they help?
  • What is the relationship between old/new and clean/dirty?

Solution

  • The observation that there are mixed metaphors is correct, and part of the problem. In the current released version of Shake the flags are taken from Make, which has different semantics to Shake, and thus maps over poorly. In the current HEAD version of Shake it's been rewritten and is much simpler - but let's focus on the released version for now.

    In Shake 0.15 (the current released version) a rule can only be skipped if Shake has run it successfully before. As a result, when you rm the Shake database, Shake cannot skip the rule on the test execution as it has never been run before.

    Before Shake 0.16 comes out one reliable and simple option is to add a flag to your build system whose presence skips all downloading - so Shake still runs the rule, but the effect of the rule is a no-op.