I suspect the below isn't a good idea, because the remember needs repeating lots of times for every user of a rule. The new design seems to eliminate these issues more cleanly, but it's an interesting point in the design space.
The current Rule
typeclass has a number of issues. It's a bit complex to use, it often results in more dependencies than you were hoping, it's hard to control. People often end up defining oracles instead or rules but then you don't get options for other things. This document attempts to rethink that.
Shake runs rules that produce values. These rules track the current state of the system (other rules) and external values (files on disk). Currently the value produced by a rule is tracked automatically. This is often awkward. Imagine we want:
foo : bar; cp bar foo
bar : baz; cp baz bar
Currently, if we manually touch bar
, then bar
rebuilds (since its value changed) and foo
rebuilds (since bar
changes). What if we only want foo
to rebuild? That's currently very difficult to arrange.
apply :: [k] -> Action [v]
Apply, much as before. Doesn't work unless we cache the output value, so we can return it if we decide it doesn't change. And to do that, we have to store the output value. Maybe we also need:
apply_ :: [k] -> Action ()
That way we can put File and Files behind the same input.
register :: (ShakeValue from, Typeable to) => (from -> Maybe (Action to)) -> Rules ()
The register function now doesn't have a storable result - the result is passed back to apply
, but is not stored or tracked.
remember :: (ShakeValue from, ShakeValue to) => from -> to -> Action ()
Rule call remember
which remembers a fact about the world.
confirm :: ShakeValue fact => (ShakeOptions -> from -> to -> IO (Result to)) -> Rules ()
The confirm
function checks a remember
ed fact. Result will be something like:
data Result x = Equal | ChangeEqual x | ChangeDifferent x | ChangeGone
There would be a more efficient registerAt
which can be used to form a big lookup table of registered functions.
registerAt :: (ShakeValue from, Typeable to) => from -> Action to -> Rules ()
registerAt a b = register (\x -> if x == a then Just b else Nothing)
There would be a way to register against the current key (might be slightly more efficient):
rememberSelf :: ShakeValue to => to -> Action ()
Should we have an explicit share
function that shares a chunk of the tree?
The file rules would be roughly:
priority 0 $ register $ \(s :: FilePath) -> Just $ do
h <- hash <$> readFile s
remember s h
return ()
rememberImplicit :: ShakeValue fact -> fact -> Action () rememberImplicit = remember with the current key as well
confirm :: ShakeValue fact => ShakeOptions -> (Maybe fact -> IO (Result fact)) -> Rules () -- Just = confirm the fact is True, tell me details about that -- Nothing = please generate the fact, if you can (assume clean mode)
sharing? caching?
alwaysRerun is just remember () (), with check that always returns False plus says something about