export createProcess with debug logging from Propellor.Property.Cmd

This commit is contained in:
Joey Hess 2015-05-30 11:05:34 -04:00
parent 3548033280
commit aa7dcad9ba
3 changed files with 47 additions and 45 deletions

7
debian/changelog vendored
View File

@ -4,9 +4,10 @@ propellor (2.5.0) UNRELEASED; urgency=medium
more generic cmdProperty' (API change) more generic cmdProperty' (API change)
* Add docker image related properties. * Add docker image related properties.
Thanks, Antoine Eiche. Thanks, Antoine Eiche.
* Export CommandParam, boolSystem, safeSystem and shellEscape from * Export CommandParam, boolSystem, safeSystem, shellEscape, and
Propellor.Property.Cmd, so they are available for use in constricting * createProcess from Propellor.Property.Cmd, so they are available
your own Properties when using propellor as a library. for use in constricting your own Properties when using propellor
as a library.
* Improve enter-machine scripts for nspawn containers to unset most * Improve enter-machine scripts for nspawn containers to unset most
environment variables. environment variables.
* Fix Postfix.satellite bug; the default relayhost was set to the * Fix Postfix.satellite bug; the default relayhost was set to the

View File

@ -14,18 +14,19 @@ module Propellor.Property.Cmd (
boolSystemEnv, boolSystemEnv,
safeSystem, safeSystem,
safeSystemEnv, safeSystemEnv,
shellEscape shellEscape,
createProcess,
) where ) where
import Control.Applicative import Control.Applicative
import Data.List import Data.List
import "mtl" Control.Monad.Reader import "mtl" Control.Monad.Reader
import System.Process (CreateProcess)
import Propellor.Types import Propellor.Types
import Propellor.Property import Propellor.Property
import Utility.SafeCommand import Utility.SafeCommand
import Utility.Env import Utility.Env
import Utility.Process (createProcess, CreateProcess)
-- | A property that can be satisfied by running a command. -- | A property that can be satisfied by running a command.
-- --

View File

@ -1,7 +1,7 @@
{- System.Process enhancements, including additional ways of running {- System.Process enhancements, including additional ways of running
- processes, and logging. - processes, and logging.
- -
- Copyright 2012 Joey Hess <id@joeyh.name> - Copyright 2012-2015 Joey Hess <id@joeyh.name>
- -
- License: BSD-2-clause - License: BSD-2-clause
-} -}
@ -65,8 +65,8 @@ type CreateProcessRunner = forall a. CreateProcess -> ((Maybe Handle, Maybe Hand
data StdHandle = StdinHandle | StdoutHandle | StderrHandle data StdHandle = StdinHandle | StdoutHandle | StderrHandle
deriving (Eq) deriving (Eq)
{- Normally, when reading from a process, it does not need to be fed any -- | Normally, when reading from a process, it does not need to be fed any
- standard input. -} -- standard input.
readProcess :: FilePath -> [String] -> IO String readProcess :: FilePath -> [String] -> IO String
readProcess cmd args = readProcessEnv cmd args Nothing readProcess cmd args = readProcessEnv cmd args Nothing
@ -84,9 +84,8 @@ readProcess' p = withHandle StdoutHandle createProcessSuccess p $ \h -> do
hClose h hClose h
return output return output
{- Runs an action to write to a process on its stdin, -- | Runs an action to write to a process on its stdin,
- returns its output, and also allows specifying the environment. -- returns its output, and also allows specifying the environment.
-}
writeReadProcessEnv writeReadProcessEnv
:: FilePath :: FilePath
-> [String] -> [String]
@ -126,8 +125,8 @@ writeReadProcessEnv cmd args environ writestdin adjusthandle = do
, env = environ , env = environ
} }
{- Waits for a ProcessHandle, and throws an IOError if the process -- | Waits for a ProcessHandle, and throws an IOError if the process
- did not exit successfully. -} -- did not exit successfully.
forceSuccessProcess :: CreateProcess -> ProcessHandle -> IO () forceSuccessProcess :: CreateProcess -> ProcessHandle -> IO ()
forceSuccessProcess p pid = do forceSuccessProcess p pid = do
code <- waitForProcess pid code <- waitForProcess pid
@ -135,10 +134,10 @@ forceSuccessProcess p pid = do
ExitSuccess -> return () ExitSuccess -> return ()
ExitFailure n -> fail $ showCmd p ++ " exited " ++ show n ExitFailure n -> fail $ showCmd p ++ " exited " ++ show n
{- Waits for a ProcessHandle and returns True if it exited successfully. -- | Waits for a ProcessHandle and returns True if it exited successfully.
- Note that using this with createProcessChecked will throw away -- Note that using this with createProcessChecked will throw away
- the Bool, and is only useful to ignore the exit code of a process, -- the Bool, and is only useful to ignore the exit code of a process,
- while still waiting for it. -} -- while still waiting for it. -}
checkSuccessProcess :: ProcessHandle -> IO Bool checkSuccessProcess :: ProcessHandle -> IO Bool
checkSuccessProcess pid = do checkSuccessProcess pid = do
code <- waitForProcess pid code <- waitForProcess pid
@ -149,13 +148,13 @@ ignoreFailureProcess pid = do
void $ waitForProcess pid void $ waitForProcess pid
return True return True
{- Runs createProcess, then an action on its handles, and then -- | Runs createProcess, then an action on its handles, and then
- forceSuccessProcess. -} -- forceSuccessProcess.
createProcessSuccess :: CreateProcessRunner createProcessSuccess :: CreateProcessRunner
createProcessSuccess p a = createProcessChecked (forceSuccessProcess p) p a createProcessSuccess p a = createProcessChecked (forceSuccessProcess p) p a
{- Runs createProcess, then an action on its handles, and then -- | Runs createProcess, then an action on its handles, and then
- a checker action on its exit code, which must wait for the process. -} -- a checker action on its exit code, which must wait for the process.
createProcessChecked :: (ProcessHandle -> IO b) -> CreateProcessRunner createProcessChecked :: (ProcessHandle -> IO b) -> CreateProcessRunner
createProcessChecked checker p a = do createProcessChecked checker p a = do
t@(_, _, _, pid) <- createProcess p t@(_, _, _, pid) <- createProcess p
@ -163,14 +162,14 @@ createProcessChecked checker p a = do
_ <- checker pid _ <- checker pid
either E.throw return r either E.throw return r
{- Leaves the process running, suitable for lazy streaming. -- | Leaves the process running, suitable for lazy streaming.
- Note: Zombies will result, and must be waited on. -} -- Note: Zombies will result, and must be waited on.
createBackgroundProcess :: CreateProcessRunner createBackgroundProcess :: CreateProcessRunner
createBackgroundProcess p a = a =<< createProcess p createBackgroundProcess p a = a =<< createProcess p
{- Runs a process, optionally feeding it some input, and -- | Runs a process, optionally feeding it some input, and
- returns a transcript combining its stdout and stderr, and -- returns a transcript combining its stdout and stderr, and
- whether it succeeded or failed. -} -- whether it succeeded or failed.
processTranscript :: String -> [String] -> (Maybe String) -> IO (String, Bool) processTranscript :: String -> [String] -> (Maybe String) -> IO (String, Bool)
processTranscript cmd opts input = processTranscript' cmd opts Nothing input processTranscript cmd opts input = processTranscript' cmd opts Nothing input
@ -234,9 +233,9 @@ processTranscript' cmd opts environ input = do
hClose inh hClose inh
writeinput Nothing _ = return () writeinput Nothing _ = return ()
{- Runs a CreateProcessRunner, on a CreateProcess structure, that -- | Runs a CreateProcessRunner, on a CreateProcess structure, that
- is adjusted to pipe only from/to a single StdHandle, and passes -- is adjusted to pipe only from/to a single StdHandle, and passes
- the resulting Handle to an action. -} -- the resulting Handle to an action.
withHandle withHandle
:: StdHandle :: StdHandle
-> CreateProcessRunner -> CreateProcessRunner
@ -258,7 +257,7 @@ withHandle h creator p a = creator p' $ a . select
| h == StderrHandle = | h == StderrHandle =
(stderrHandle, base { std_err = CreatePipe }) (stderrHandle, base { std_err = CreatePipe })
{- Like withHandle, but passes (stdin, stdout) handles to the action. -} -- | Like withHandle, but passes (stdin, stdout) handles to the action.
withIOHandles withIOHandles
:: CreateProcessRunner :: CreateProcessRunner
-> CreateProcess -> CreateProcess
@ -272,7 +271,7 @@ withIOHandles creator p a = creator p' $ a . ioHandles
, std_err = Inherit , std_err = Inherit
} }
{- Like withHandle, but passes (stdout, stderr) handles to the action. -} -- | Like withHandle, but passes (stdout, stderr) handles to the action.
withOEHandles withOEHandles
:: CreateProcessRunner :: CreateProcessRunner
-> CreateProcess -> CreateProcess
@ -286,8 +285,8 @@ withOEHandles creator p a = creator p' $ a . oeHandles
, std_err = CreatePipe , std_err = CreatePipe
} }
{- Forces the CreateProcessRunner to run quietly; -- | Forces the CreateProcessRunner to run quietly;
- both stdout and stderr are discarded. -} -- both stdout and stderr are discarded.
withQuietOutput withQuietOutput
:: CreateProcessRunner :: CreateProcessRunner
-> CreateProcess -> CreateProcess
@ -299,8 +298,8 @@ withQuietOutput creator p = withFile devNull WriteMode $ \nullh -> do
} }
creator p' $ const $ return () creator p' $ const $ return ()
{- Stdout and stderr are discarded, while the process is fed stdin -- | Stdout and stderr are discarded, while the process is fed stdin
- from the handle. -} -- from the handle.
feedWithQuietOutput feedWithQuietOutput
:: CreateProcessRunner :: CreateProcessRunner
-> CreateProcess -> CreateProcess
@ -321,11 +320,11 @@ devNull = "/dev/null"
devNull = "NUL" devNull = "NUL"
#endif #endif
{- Extract a desired handle from createProcess's tuple. -- | Extract a desired handle from createProcess's tuple.
- These partial functions are safe as long as createProcess is run -- These partial functions are safe as long as createProcess is run
- with appropriate parameters to set up the desired handle. -- with appropriate parameters to set up the desired handle.
- Get it wrong and the runtime crash will always happen, so should be -- Get it wrong and the runtime crash will always happen, so should be
- easily noticed. -} -- easily noticed.
type HandleExtractor = (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle type HandleExtractor = (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> Handle
stdinHandle :: HandleExtractor stdinHandle :: HandleExtractor
stdinHandle (Just h, _, _, _) = h stdinHandle (Just h, _, _, _) = h
@ -346,7 +345,7 @@ oeHandles _ = error "expected oeHandles"
processHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> ProcessHandle processHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> ProcessHandle
processHandle (_, _, _, pid) = pid processHandle (_, _, _, pid) = pid
{- Debugging trace for a CreateProcess. -} -- | Debugging trace for a CreateProcess.
debugProcess :: CreateProcess -> IO () debugProcess :: CreateProcess -> IO ()
debugProcess p = do debugProcess p = do
debugM "Utility.Process" $ unwords debugM "Utility.Process" $ unwords
@ -362,15 +361,15 @@ debugProcess p = do
piped Inherit = False piped Inherit = False
piped _ = True piped _ = True
{- Shows the command that a CreateProcess will run. -} -- | Shows the command that a CreateProcess will run.
showCmd :: CreateProcess -> String showCmd :: CreateProcess -> String
showCmd = go . cmdspec showCmd = go . cmdspec
where where
go (ShellCommand s) = s go (ShellCommand s) = s
go (RawCommand c ps) = c ++ " " ++ show ps go (RawCommand c ps) = c ++ " " ++ show ps
{- Starts an interactive process. Unlike runInteractiveProcess in -- | Starts an interactive process. Unlike runInteractiveProcess in
- System.Process, stderr is inherited. -} -- System.Process, stderr is inherited.
startInteractiveProcess startInteractiveProcess
:: FilePath :: FilePath
-> [String] -> [String]
@ -386,7 +385,8 @@ startInteractiveProcess cmd args environ = do
(Just from, Just to, _, pid) <- createProcess p (Just from, Just to, _, pid) <- createProcess p
return (pid, to, from) return (pid, to, from)
{- Wrapper around System.Process function that does debug logging. -} -- | Wrapper around 'System.Process.createProcess' from System.Process,
-- that does debug logging.
createProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) createProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
createProcess p = do createProcess p = do
debugProcess p debugProcess p