    {-# LANGUAGE TupleSections, ConstraintKinds #-}

    -- | Extra functions for creating processes. Specifically variants that automatically check
    --   the 'ExitCode' and capture the 'stdout' \/ 'stderr' handles.
    module System.Process.Extra(
        module System.Process,
        system_, systemOutput, systemOutput_
        ) where

    import Control.Monad
    import System.IO.Extra
    import System.Process
    import System.Exit
    import Data.Functor
    import Partial
    import Prelude

    -- | A version of 'system' that also captures the output, both 'stdout' and 'stderr'.
    --   Returns a pair of the 'ExitCode' and the output.
    systemOutput :: String -> IO (ExitCode, String)
    systemOutput :: String -> IO (ExitCode, String)
    systemOutput x :: String
    x = (String -> IO (ExitCode, String)) -> IO (ExitCode, String)
    forall a. (String -> IO a) -> IO a
    withTempFile ((String -> IO (ExitCode, String)) -> IO (ExitCode, String))
    -> (String -> IO (ExitCode, String)) -> IO (ExitCode, String)
    forall a b. (a -> b) -> a -> b
    $ \file :: String
    file -> do
        ExitCode
    exit <- String -> IOMode -> (Handle -> IO ExitCode) -> IO ExitCode
    forall r. String -> IOMode -> (Handle -> IO r) -> IO r
    withFile String
    file IOMode
    WriteMode ((Handle -> IO ExitCode) -> IO ExitCode)
    -> (Handle -> IO ExitCode) -> IO ExitCode
    forall a b. (a -> b) -> a -> b
    $ \h :: Handle
    h -> do
            (_, _, _, pid :: ProcessHandle
    pid) <- CreateProcess
    -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
    createProcess (String -> CreateProcess
    shell String
    x){std_out :: StdStream
    std_out=Handle -> StdStream
    UseHandle Handle
    h, std_err :: StdStream
    std_err=Handle -> StdStream
    UseHandle Handle
    h}
            ProcessHandle -> IO ExitCode
    waitForProcess ProcessHandle
    pid
        (ExitCode
    exit,) (String -> (ExitCode, String))
    -> IO String -> IO (ExitCode, String)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> IO String
    readFile' String
    file

    -- | A version of 'system' that throws an error if the 'ExitCode' is not 'ExitSuccess'.
    system_ :: Partial => String -> IO ()
    system_ :: String -> IO ()
    system_ x :: String
    x = do
        ExitCode
    res <- String -> IO ExitCode
    system String
    x
        Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (ExitCode
    res ExitCode -> ExitCode -> Bool
    forall a. Eq a => a -> a -> Bool
    /= ExitCode
    ExitSuccess) (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $
            String -> IO ()
    forall a. HasCallStack => String -> a
    error (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ "Failed when running system command: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    x

    -- | A version of 'system' that captures the output (both 'stdout' and 'stderr')
    --   and throws an error if the 'ExitCode' is not 'ExitSuccess'.
    systemOutput_ :: Partial => String -> IO String
    systemOutput_ :: String -> IO String
    systemOutput_ x :: String
    x = do
        (res :: ExitCode
    res,out :: String
    out) <- String -> IO (ExitCode, String)
    systemOutput String
    x
        Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (ExitCode
    res ExitCode -> ExitCode -> Bool
    forall a. Eq a => a -> a -> Bool
    /= ExitCode
    ExitSuccess) (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $
            String -> IO ()
    forall a. HasCallStack => String -> a
    error (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ "Failed when running system command: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    x
        String -> IO String
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure String
    out