{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Simple.UserHooks
-- Copyright   :  Isaac Jones 2003-2005
-- License     :  BSD3
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- This defines the API that @Setup.hs@ scripts can use to customise the way
-- the build works. This module just defines the 'UserHooks' type. The
-- predefined sets of hooks that implement the @Simple@, @Make@ and @Configure@
-- build systems are defined in "Distribution.Simple". The 'UserHooks' is a big
-- record of functions. There are 3 for each action, a pre, post and the action
-- itself. There are few other miscellaneous hooks, ones to extend the set of
-- programs and preprocessors and one to override the function used to read the
-- @.cabal@ file.
--
-- This hooks type is widely agreed to not be the right solution. Partly this
-- is because changes to it usually break custom @Setup.hs@ files and yet many
-- internal code changes do require changes to the hooks. For example we cannot
-- pass any extra parameters to most of the functions that implement the
-- various phases because it would involve changing the types of the
-- corresponding hook. At some point it will have to be replaced.

module Distribution.Simple.UserHooks (
        UserHooks(..), Args,
        emptyUserHooks,
  ) where

import Prelude ()
import Distribution.Compat.Prelude

import Distribution.PackageDescription
import Distribution.Simple.Program
import Distribution.Simple.Command
import Distribution.Simple.PreProcess
import Distribution.Simple.Setup
import Distribution.Simple.LocalBuildInfo

type Args = [String]

-- | Hooks allow authors to add specific functionality before and after a
-- command is run, and also to specify additional preprocessors.
--
-- * WARNING: The hooks interface is under rather constant flux as we try to
-- understand users needs. Setup files that depend on this interface may
-- break in future releases.
data UserHooks = UserHooks {

    -- | Read the description file
    UserHooks -> IO (Maybe GenericPackageDescription)
readDesc :: IO (Maybe GenericPackageDescription),
    -- | Custom preprocessors in addition to and overriding 'knownSuffixHandlers'.
    UserHooks -> [PPSuffixHandler]
hookedPreProcessors :: [ PPSuffixHandler ],
    -- | These programs are detected at configure time.  Arguments for them are
    -- added to the configure command.
    UserHooks -> [Program]
hookedPrograms :: [Program],

    -- |Hook to run before configure command
    UserHooks -> Args -> ConfigFlags -> IO HookedBuildInfo
preConf  :: Args -> ConfigFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during configure.
    UserHooks
-> (GenericPackageDescription, HookedBuildInfo)
-> ConfigFlags
-> IO LocalBuildInfo
confHook :: (GenericPackageDescription, HookedBuildInfo)
            -> ConfigFlags -> IO LocalBuildInfo,
    -- |Hook to run after configure command
    UserHooks
-> Args
-> ConfigFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before build command.  Second arg indicates verbosity level.
    UserHooks -> Args -> BuildFlags -> IO HookedBuildInfo
preBuild  :: Args -> BuildFlags -> IO HookedBuildInfo,

    -- |Over-ride this hook to get different behavior during build.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> BuildFlags
-> IO ()
buildHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO (),
    -- |Hook to run after build command.  Second arg indicates verbosity level.
    UserHooks
-> Args
-> BuildFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postBuild :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before repl command.  Second arg indicates verbosity level.
    UserHooks -> Args -> ReplFlags -> IO HookedBuildInfo
preRepl  :: Args -> ReplFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during interpretation.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> ReplFlags
-> Args
-> IO ()
replHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> ReplFlags -> [String] -> IO (),
    -- |Hook to run after repl command.  Second arg indicates verbosity level.
    UserHooks
-> Args
-> ReplFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postRepl :: Args -> ReplFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before clean command.  Second arg indicates verbosity level.
    UserHooks -> Args -> CleanFlags -> IO HookedBuildInfo
preClean  :: Args -> CleanFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during clean.
    UserHooks
-> PackageDescription -> () -> UserHooks -> CleanFlags -> IO ()
cleanHook :: PackageDescription -> () -> UserHooks -> CleanFlags -> IO (),
    -- |Hook to run after clean command.  Second arg indicates verbosity level.
    UserHooks
-> Args -> CleanFlags -> PackageDescription -> () -> IO ()
postClean :: Args -> CleanFlags -> PackageDescription -> () -> IO (),

    -- |Hook to run before copy command
    UserHooks -> Args -> CopyFlags -> IO HookedBuildInfo
preCopy  :: Args -> CopyFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during copy.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> CopyFlags
-> IO ()
copyHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> CopyFlags -> IO (),
    -- |Hook to run after copy command
    UserHooks
-> Args
-> CopyFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postCopy :: Args -> CopyFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before install command
    UserHooks -> Args -> InstallFlags -> IO HookedBuildInfo
preInst  :: Args -> InstallFlags -> IO HookedBuildInfo,

    -- |Over-ride this hook to get different behavior during install.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> InstallFlags
-> IO ()
instHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> InstallFlags -> IO (),
    -- |Hook to run after install command.  postInst should be run
    -- on the target, not on the build machine.
    UserHooks
-> Args
-> InstallFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postInst :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before register command
    UserHooks -> Args -> RegisterFlags -> IO HookedBuildInfo
preReg  :: Args -> RegisterFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during registration.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> RegisterFlags
-> IO ()
regHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO (),
    -- |Hook to run after register command
    UserHooks
-> Args
-> RegisterFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postReg :: Args -> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before unregister command
    UserHooks -> Args -> RegisterFlags -> IO HookedBuildInfo
preUnreg  :: Args -> RegisterFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during unregistration.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> RegisterFlags
-> IO ()
unregHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO (),
    -- |Hook to run after unregister command
    UserHooks
-> Args
-> RegisterFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postUnreg :: Args -> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before hscolour command.  Second arg indicates verbosity level.
    UserHooks -> Args -> HscolourFlags -> IO HookedBuildInfo
preHscolour  :: Args -> HscolourFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during hscolour.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> HscolourFlags
-> IO ()
hscolourHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> HscolourFlags -> IO (),
    -- |Hook to run after hscolour command.  Second arg indicates verbosity level.
    UserHooks
-> Args
-> HscolourFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postHscolour :: Args -> HscolourFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before haddock command.  Second arg indicates verbosity level.
    UserHooks -> Args -> HaddockFlags -> IO HookedBuildInfo
preHaddock  :: Args -> HaddockFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during haddock.
    UserHooks
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> HaddockFlags
-> IO ()
haddockHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> HaddockFlags -> IO (),
    -- |Hook to run after haddock command.  Second arg indicates verbosity level.
    UserHooks
-> Args
-> HaddockFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postHaddock :: Args -> HaddockFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before test command.
    UserHooks -> Args -> TestFlags -> IO HookedBuildInfo
preTest :: Args -> TestFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during test.
    UserHooks
-> Args
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> TestFlags
-> IO ()
testHook :: Args -> PackageDescription -> LocalBuildInfo -> UserHooks -> TestFlags -> IO (),
    -- |Hook to run after test command.
    UserHooks
-> Args
-> TestFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postTest :: Args -> TestFlags -> PackageDescription -> LocalBuildInfo -> IO (),

    -- |Hook to run before bench command.
    UserHooks -> Args -> BenchmarkFlags -> IO HookedBuildInfo
preBench :: Args -> BenchmarkFlags -> IO HookedBuildInfo,
    -- |Over-ride this hook to get different behavior during bench.
    UserHooks
-> Args
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> BenchmarkFlags
-> IO ()
benchHook :: Args -> PackageDescription -> LocalBuildInfo -> UserHooks -> BenchmarkFlags -> IO (),
    -- |Hook to run after bench command.
    UserHooks
-> Args
-> BenchmarkFlags
-> PackageDescription
-> LocalBuildInfo
-> IO ()
postBench :: Args -> BenchmarkFlags -> PackageDescription -> LocalBuildInfo -> IO ()
  }

-- |Empty 'UserHooks' which do nothing.
emptyUserHooks :: UserHooks
emptyUserHooks :: UserHooks
emptyUserHooks
  = UserHooks {
      readDesc :: IO (Maybe GenericPackageDescription)
readDesc  = Maybe GenericPackageDescription
-> IO (Maybe GenericPackageDescription)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe GenericPackageDescription
forall a. Maybe a
Nothing,
      hookedPreProcessors :: [PPSuffixHandler]
hookedPreProcessors = [],
      hookedPrograms :: [Program]
hookedPrograms      = [],
      preConf :: Args -> ConfigFlags -> IO HookedBuildInfo
preConf   = Args -> ConfigFlags -> IO HookedBuildInfo
forall {m :: * -> *} {p} {p}.
Monad m =>
p -> p -> m HookedBuildInfo
rn',
      confHook :: (GenericPackageDescription, HookedBuildInfo)
-> ConfigFlags -> IO LocalBuildInfo
confHook  = (\(GenericPackageDescription, HookedBuildInfo)
_ ConfigFlags
_ -> LocalBuildInfo -> IO LocalBuildInfo
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> LocalBuildInfo
forall a. HasCallStack => [Char] -> a
error [Char]
"No local build info generated during configure. Over-ride empty configure hook.")),
      postConf :: Args
-> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postConf  = Args
-> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preBuild :: Args -> BuildFlags -> IO HookedBuildInfo
preBuild  = Args -> BuildFlags -> IO HookedBuildInfo
forall {m :: * -> *} {p} {p}.
Monad m =>
p -> p -> m HookedBuildInfo
rn',
      buildHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
buildHook = PackageDescription
-> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postBuild :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postBuild = Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preRepl :: Args -> ReplFlags -> IO HookedBuildInfo
preRepl   = \Args
_ ReplFlags
_ -> HookedBuildInfo -> IO HookedBuildInfo
forall (m :: * -> *) a. Monad m => a -> m a
return HookedBuildInfo
emptyHookedBuildInfo,
      replHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> ReplFlags -> Args -> IO ()
replHook  = \PackageDescription
_ LocalBuildInfo
_ UserHooks
_ ReplFlags
_ Args
_ -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return (),
      postRepl :: Args -> ReplFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postRepl  = Args -> ReplFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preClean :: Args -> CleanFlags -> IO HookedBuildInfo
preClean  = Args -> CleanFlags -> IO HookedBuildInfo
forall {p}. Args -> p -> IO HookedBuildInfo
rn,
      cleanHook :: PackageDescription -> () -> UserHooks -> CleanFlags -> IO ()
cleanHook = PackageDescription -> () -> UserHooks -> CleanFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postClean :: Args -> CleanFlags -> PackageDescription -> () -> IO ()
postClean = Args -> CleanFlags -> PackageDescription -> () -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preCopy :: Args -> CopyFlags -> IO HookedBuildInfo
preCopy   = Args -> CopyFlags -> IO HookedBuildInfo
forall {m :: * -> *} {p} {p}.
Monad m =>
p -> p -> m HookedBuildInfo
rn',
      copyHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> CopyFlags -> IO ()
copyHook  = PackageDescription
-> LocalBuildInfo -> UserHooks -> CopyFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postCopy :: Args -> CopyFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postCopy  = Args -> CopyFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preInst :: Args -> InstallFlags -> IO HookedBuildInfo
preInst   = Args -> InstallFlags -> IO HookedBuildInfo
forall {p}. Args -> p -> IO HookedBuildInfo
rn,
      instHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> InstallFlags -> IO ()
instHook  = PackageDescription
-> LocalBuildInfo -> UserHooks -> InstallFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postInst :: Args
-> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postInst  = Args
-> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preReg :: Args -> RegisterFlags -> IO HookedBuildInfo
preReg    = Args -> RegisterFlags -> IO HookedBuildInfo
forall {m :: * -> *} {p} {p}.
Monad m =>
p -> p -> m HookedBuildInfo
rn',
      regHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO ()
regHook   = PackageDescription
-> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postReg :: Args
-> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postReg   = Args
-> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preUnreg :: Args -> RegisterFlags -> IO HookedBuildInfo
preUnreg  = Args -> RegisterFlags -> IO HookedBuildInfo
forall {p}. Args -> p -> IO HookedBuildInfo
rn,
      unregHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO ()
unregHook = PackageDescription
-> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postUnreg :: Args
-> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postUnreg = Args
-> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preHscolour :: Args -> HscolourFlags -> IO HookedBuildInfo
preHscolour  = Args -> HscolourFlags -> IO HookedBuildInfo
forall {p}. Args -> p -> IO HookedBuildInfo
rn,
      hscolourHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> HscolourFlags -> IO ()
hscolourHook = PackageDescription
-> LocalBuildInfo -> UserHooks -> HscolourFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postHscolour :: Args
-> HscolourFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postHscolour = Args
-> HscolourFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preHaddock :: Args -> HaddockFlags -> IO HookedBuildInfo
preHaddock   = Args -> HaddockFlags -> IO HookedBuildInfo
forall {m :: * -> *} {p} {p}.
Monad m =>
p -> p -> m HookedBuildInfo
rn',
      haddockHook :: PackageDescription
-> LocalBuildInfo -> UserHooks -> HaddockFlags -> IO ()
haddockHook  = PackageDescription
-> LocalBuildInfo -> UserHooks -> HaddockFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postHaddock :: Args
-> HaddockFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postHaddock  = Args
-> HaddockFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preTest :: Args -> TestFlags -> IO HookedBuildInfo
preTest  = Args -> TestFlags -> IO HookedBuildInfo
forall {m :: * -> *} {p} {p}.
Monad m =>
p -> p -> m HookedBuildInfo
rn',
      testHook :: Args
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> TestFlags
-> IO ()
testHook = \Args
_ -> PackageDescription
-> LocalBuildInfo -> UserHooks -> TestFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postTest :: Args -> TestFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postTest = Args -> TestFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      preBench :: Args -> BenchmarkFlags -> IO HookedBuildInfo
preBench = Args -> BenchmarkFlags -> IO HookedBuildInfo
forall {m :: * -> *} {p} {p}.
Monad m =>
p -> p -> m HookedBuildInfo
rn',
      benchHook :: Args
-> PackageDescription
-> LocalBuildInfo
-> UserHooks
-> BenchmarkFlags
-> IO ()
benchHook = \Args
_ -> PackageDescription
-> LocalBuildInfo -> UserHooks -> BenchmarkFlags -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru,
      postBench :: Args
-> BenchmarkFlags -> PackageDescription -> LocalBuildInfo -> IO ()
postBench = Args
-> BenchmarkFlags -> PackageDescription -> LocalBuildInfo -> IO ()
forall {m :: * -> *} {p} {p} {p} {p}.
Monad m =>
p -> p -> p -> p -> m ()
ru
    }
    where rn :: Args -> p -> IO HookedBuildInfo
rn  Args
args p
_ = Args -> IO ()
noExtraFlags Args
args IO () -> IO HookedBuildInfo -> IO HookedBuildInfo
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> HookedBuildInfo -> IO HookedBuildInfo
forall (m :: * -> *) a. Monad m => a -> m a
return HookedBuildInfo
emptyHookedBuildInfo
          rn' :: p -> p -> m HookedBuildInfo
rn' p
_    p
_ = HookedBuildInfo -> m HookedBuildInfo
forall (m :: * -> *) a. Monad m => a -> m a
return HookedBuildInfo
emptyHookedBuildInfo
          ru :: p -> p -> p -> p -> m ()
ru p
_ p
_ p
_ p
_ = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()