{-# 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 x = withTempFile $ \file -> do
    exit <- withFile file WriteMode $ \h -> do
        (_, _, _, pid) <- createProcess (shell x){std_out=UseHandle h, std_err=UseHandle h}
        waitForProcess pid
    (exit,) <$> readFile' file


-- | A version of 'system' that throws an error if the 'ExitCode' is not 'ExitSuccess'.
system_ :: Partial => String -> IO ()
system_ x = do
    res <- system x
    when (res /= ExitSuccess) $
        error $ "Failed when running system command: " ++ 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_ x = do
    (res,out) <- systemOutput x
    when (res /= ExitSuccess) $
        error $ "Failed when running system command: " ++ x
    pure out