    {-# LANGUAGE CPP #-}
    module Distribution.Compat.Process (
        -- * Redefined functions
        createProcess,
        runInteractiveProcess,
        rawSystem,
        -- * Additions
        enableProcessJobs,
        ) where

    import System.Exit (ExitCode (..))
    import System.IO   (Handle)

    import           System.Process (CreateProcess, ProcessHandle)
    import qualified System.Process as Process

    #if MIN_VERSION_process(1,2,0)
    import           System.Process (waitForProcess)
    #endif

    -------------------------------------------------------------------------------
    -- enableProcessJobs
    -------------------------------------------------------------------------------

    -- | Enable process jobs to ensure accurate determination of process completion
    -- in the presence of @exec(3)@ on Windows.
    --
    -- Unfortunately the process job support is badly broken in @process@ releases
    -- prior to 1.6.9, so we disable it in these versions, despite the fact that
    -- this means we may see sporatic build failures without jobs.
    enableProcessJobs :: CreateProcess -> CreateProcess
    #ifdef MIN_VERSION_process
    #if MIN_VERSION_process(1,6,9)
    enableProcessJobs :: CreateProcess -> CreateProcess
    enableProcessJobs CreateProcess
    cp = CreateProcess
    cp {use_process_jobs :: Bool
    Process.use_process_jobs = Bool
    True}
    #else
    enableProcessJobs cp = cp
    #endif
    #else
    enableProcessJobs cp = cp
    #endif

    -------------------------------------------------------------------------------
    -- process redefinitions
    -------------------------------------------------------------------------------

    -- | 'System.Process.createProcess' with process jobs enabled when appropriate.
    -- See 'enableProcessJobs'.
    createProcess :: CreateProcess
                  -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess :: CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess = CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    Process.createProcess (CreateProcess
     -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle))
    -> (CreateProcess -> CreateProcess)
    -> CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CreateProcess -> CreateProcess
    enableProcessJobs

    -- | 'System.Process.rawSystem' with process jobs enabled when appropriate.
    -- See 'enableProcessJobs'.
    rawSystem :: String -> [String] -> IO ExitCode
    rawSystem :: String -> [String] -> IO ExitCode
    rawSystem String
    cmd [String]
    args = do
    #if MIN_VERSION_process(1,2,0)
      (Maybe Handle
    _,Maybe Handle
    _,Maybe Handle
    _,ProcessHandle
    p) <- CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess (String -> [String] -> CreateProcess
    Process.proc String
    cmd [String]
    args) { delegate_ctlc :: Bool
    Process.delegate_ctlc = Bool
    True }
      ProcessHandle -> IO ExitCode
    waitForProcess ProcessHandle
    p
    #else
      -- With very old 'process', just do its rawSystem
      Process.rawSystem cmd args
    #endif

    -- | 'System.Process.runInteractiveProcess' with process jobs enabled when
    -- appropriate. See 'enableProcessJobs'.
    runInteractiveProcess
      :: FilePath                   -- ^ Filename of the executable (see 'RawCommand' for details)
      -> [String]                   -- ^ Arguments to pass to the executable
      -> Maybe FilePath             -- ^ Optional path to the working directory
      -> Maybe [(String,String)]    -- ^ Optional environment (otherwise inherit)
      -> IO (Handle,Handle,Handle,ProcessHandle)
    runInteractiveProcess :: String
    -> [String]
    -> Maybe String
    -> Maybe [(String, String)]
    -> IO (Handle, Handle, Handle, ProcessHandle)
    runInteractiveProcess String
    cmd [String]
    args Maybe String
    mb_cwd Maybe [(String, String)]
    mb_env = do
      (Maybe Handle
    mb_in, Maybe Handle
    mb_out, Maybe Handle
    mb_err, ProcessHandle
    p) <-
          CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess (String -> [String] -> CreateProcess
    Process.proc String
    cmd [String]
    args)
                  { std_in :: StdStream
    Process.std_in  = StdStream
    Process.CreatePipe,
                    std_out :: StdStream
    Process.std_out = StdStream
    Process.CreatePipe,
                    std_err :: StdStream
    Process.std_err = StdStream
    Process.CreatePipe,
                    env :: Maybe [(String, String)]
    Process.env     = Maybe [(String, String)]
    mb_env,
                    cwd :: Maybe String
    Process.cwd     = Maybe String
    mb_cwd }
      (Handle, Handle, Handle, ProcessHandle)
    -> IO (Handle, Handle, Handle, ProcessHandle)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe Handle -> Handle
    forall {b}. Maybe b -> b
    fromJust Maybe Handle
    mb_in, Maybe Handle -> Handle
    forall {b}. Maybe b -> b
    fromJust Maybe Handle
    mb_out, Maybe Handle -> Handle
    forall {b}. Maybe b -> b
    fromJust Maybe Handle
    mb_err, ProcessHandle
    p)
      where
        fromJust :: Maybe b -> b
    fromJust = b -> (b -> b) -> Maybe b -> b
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (String -> b
    forall a. HasCallStack => String -> a
    error String
    "runInteractiveProcess: fromJust") b -> b
    forall a. a -> a
    id