Cleaning up hooks
Simon Marlow
simonmarhaskell at gmail.com
Tue Apr 24 04:45:54 EDT 2007
I think the API for hooks is in need of an overhaul. It has a few problems:
1. it isn't extensible. When a new command is added, typically
all the Setup.hs scripts break because they haven't hooked then
new command.
2. it isn't composable. It ought to be easy to augment
PackageDescription in Setup.hs, but it isn't: to do it right,
you have to modify every hook.
3. It's too complicated. I'm sure we don't need all those pre- and
post- hooks.
4. tools that build on Cabal (e.g. cabal-rpm) don't work with hooks.
If your Setup.hs uses hooks to modify the PackageDescrption, then
cabal-rpm won't see the modifications.
I can fix 1-3, but 4 is more of a design problem. I'll outline a possible
partial solution to 4 later, however.
Anyway, here's the basic idea. A common thing to want to do in Setup.lhs is to
modify the PackageDescription, so we provide a way to do that:
modifyPackageDescription
:: (PackageDescription -> IO PackageDescription)
-> UserHooks -> UserHooks
modifyPackageDescriptionPostConf
:: (PackageDescription -> LocalBuildInfo -> IO PackageDescription)
-> UserHooks -> UserHooks
modifyPackageDescription supplies a function that is run before every command,
to modify the existing PackageDescription, and it can do IO.
modifyPackageDescriptionPostConf is similar, except that it does not apply to
the configure command, and it gets to see the LocalBUildInfo.
These mostly subsume all the preHooks. For example,
modifyPackageDescriptionPostConf can be used to read the results of the autoconf
script. (We'll also need to provide a way to merge a new BuildInfo with the
existing PackageDescription).
The good thing about this is it's extensible and composable. Adding more
commands to Cabal won't break Setup.lhs scripts that use these combinators.
This could also help us solve problem (4) above: Cabal can provide a way to
output the modified PackageDescription to a file, that can be read in by
cabal-rpm. For example, "cabal-setup descr" could output the real
PackageDescription.
We might still want to hook the real commands, however. So let's look at
simplifying the UserHooks type:
type ConfHook = Args -> ConfigFlags -> PackageDescription -> IO LocalBuildInfo
type Hook a = Args -> a -> PackageDescription -> LocalBuildInfo -> IO ()
data Hooks = Hooks {
confHook :: ConfHook,
postConfHook :: Hook ConfigFlags
buildHook :: Hook BuildFlags,
makefileHook :: Hook MakefileFlags,
cleanHook :: Hook CleanFlags,
copyHook :: Hook CopyFlags,
installHook :: Hook InstallFlags,
sdistHook :: Hook SDistFlags,
registerHook :: Hook RegisterFlags,
unregisterHook :: Hook UnregisterFlags,
haddockHook :: Hook HaddockFlags,
pfeHook :: Hook PfeFlags
}
I've missed out runTests and a few others, but the main idea is that I got rid
of most the pre- and post-hooks. The configure command is special, because it
doesn't see the LocalBuildInfo, so we also need a postConfHook for doing further
actions after configure (e.g. running the autoconf script).
Suppose we supply thenHook:
thenHook :: Hook a -> Hook a -> Hook a
thenHook hook1 hook2 args flags pd lbi = do
hook1 args flags pd lbi
hook2 args flags pd lbi
Then to add a post-hook to the build command you could do this:
addPostBuild :: Hook BuildFlags -> Hooks -> Hooks
addPostBuild hook hooks
= hooks { buildHook = buildHook hooks `thenHook` hook }
Alternatively, we could supply addPostBuild, addPreBuild, etc. and hide the
representation of the Hooks type completely.
Comments?
Cheers,
Simon
More information about the cabal-devel
mailing list