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

_______________________________________________
cabal-devel mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/cabal-devel

Reply via email to