{-| Module : Omnifmt.Process Description : System process utilities. Copyright : (c) Henry J. Wylde, 2015 License : BSD3 Maintainer : public@hjwylde.com System process utilities. -} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} module Omnifmt.Process ( -- * Run runProcess, runProcess_, runTimedProcess, runCommand, runCommand_, runTimedCommand, runCreateProcess, runCreateProcess_, ) where import Control.Monad.Except import Control.Monad.Logger import Data.Text hiding (unwords) import Omnifmt.Exit import System.Exit import System.Process.Extra (CmdSpec (..), CreateProcess) import qualified System.Process.Extra as System -- | Runs the given executable with the arguments. -- Returns the exit code, stdout and stderr. runProcess :: (MonadIO m, MonadLogger m) => FilePath -> [String] -> m (ExitCode, String, String) runProcess cmd args = runCreateProcess (System.proc cmd args) "" -- | Runs the given executable with the arguments. -- Depending on the exit code, either logs the stderr and exits fast (128) or returns the stdout. runProcess_ :: (MonadError ExitCode m, MonadIO m, MonadLogger m) => FilePath -> [String] -> m String runProcess_ cmd args = runCreateProcess_ (System.proc cmd args) "" -- | Runs the given executable with the arguments. -- Returns the exit code, stdout and stderr. -- The command is wrapped in a `timeout -k N*2 N` call. runTimedProcess :: (MonadIO m, MonadLogger m) => Int -> FilePath -> [String] -> m (ExitCode, String, String) runTimedProcess n cmd args = runCreateProcess (System.proc "timeout" $ "-k":show (n * 2):show n:cmd:args) "" -- | Runs the given command. -- Returns the exit code, stdout and stderr. runCommand :: (MonadIO m, MonadLogger m) => String -> m (ExitCode, String, String) runCommand cmd = runCreateProcess (System.shell cmd) "" -- | Runs the given command. -- Depending on the exit code, either logs the stderr and exits fast (128) or returns the stdout. runCommand_ :: (MonadError ExitCode m, MonadIO m, MonadLogger m) => String -> m String runCommand_ cmd = runCreateProcess_ (System.shell cmd) "" -- | Runs the given command. -- Returns the exit code, stdout and stderr. -- The command is wrapped in a `timeout -k N*2 N` call. runTimedCommand :: (MonadIO m, MonadLogger m) => Int -> String -> m (ExitCode, String, String) runTimedCommand n cmd = runCreateProcess (System.shell $ unwords ["timeout -k", show $ n * 2, show n, cmd]) "" -- | Runs the given 'CreateProcess'. -- Returns the exit code, stdout and stderr. runCreateProcess :: (MonadIO m, MonadLogger m) => CreateProcess -> String -> m (ExitCode, String, String) runCreateProcess process stdin = do logDebugN $ pack (case System.cmdspec process of ShellCommand cmd -> cmd RawCommand cmd args -> unwords (cmd:args) ) liftIO $ System.readCreateProcessWithExitCode process stdin -- | Runs the given 'CreateProcess'. -- Depending on the exit code, either logs the stderr and exits fast (128) or returns the stdout. runCreateProcess_ :: (MonadError ExitCode m, MonadIO m, MonadLogger m) => CreateProcess -> String -> m String runCreateProcess_ process stdin = do (exitCode, stdout, stderr) <- runCreateProcess process stdin if exitCode == ExitSuccess then return stdout else panic stderr