{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE CPP #-}

-- | See documentation for "Shh".
module Shh.Internal where

import Prelude hiding (lines, unlines)

import Control.Concurrent.Async
import Control.Concurrent.MVar
import Control.DeepSeq (force,NFData)
import Control.Exception as C
import Control.Monad
import Control.Monad.IO.Class
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Unsafe as ByteString
import Data.ByteString.Lazy (ByteString, hGetContents, toStrict, fromStrict)
import qualified Data.ByteString.Lazy as BS
import Data.ByteString.Builder
import qualified Data.ByteString.Lazy.Char8 as BC8
import qualified Data.ByteString.Lazy.Search as Search
import Data.ByteString.Lazy.UTF8 (toString)
import Data.Char (isLower, isSpace, isAlphaNum, ord)
import qualified Data.List.Split as Split
import qualified Data.Map as Map
import Data.Maybe (isJust)
import Data.Typeable
import GHC.IO.BufferedIO
import GHC.IO.Device as IODevice hiding (read)
import GHC.IO.Encoding
import GHC.Foreign (peekCStringLen, newCStringLen)
import GHC.IO.Exception (IOErrorType(ResourceVanished))
import GHC.IO.Handle hiding (hGetContents)
import GHC.IO.Handle.Internals
import GHC.IO.Handle.Types
import GHC.Stack
import Language.Haskell.TH
import qualified System.Directory as Dir
import System.Environment (getEnv, setEnv)
import System.Exit (ExitCode(..))
import System.FilePath (takeFileName, (</>))
import System.IO (IOMode(..), withFile, withBinaryFile, stderr, stdout, stdin)
import System.IO.Unsafe (unsafePerformIO)
import System.IO.Error
import System.Posix.Signals
import System.Process
import Text.Printf

-- $setup
-- For doc-tests. Not sure I can use TH in doc tests.
-- >>> :seti -XOverloadedStrings
-- >>> import Data.Monoid
-- >>> import Data.ByteString.Lazy.Char8 (lines)
-- >>> let cat = exe "cat"
-- >>> let echo = exe "echo"
-- >>> let false = exe "false"
-- >>> let head = exe "head"
-- >>> let md5sum = exe "md5sum"
-- >>> let printf = exe "printf"
-- >>> let sleep = exe "sleep"
-- >>> let true = exe "true"
-- >>> let wc = exe "wc"
-- >>> let xargs = exe "xargs"
-- >>> let yes = exe "yes"
-- >>> let some_command = writeOutput "this is stdout" >> (writeOutput "this is stderr" &> StdErr)

-- | This function needs to be called in order to use the library successfully
-- from GHCi. If you use the @formatPrompt@ function from the @shh-extras@
-- package, this will be automatically called for you.
initInteractive :: IO ()
initInteractive :: IO ()
initInteractive = do
    Handle -> BufferMode -> IO ()
hSetBuffering Handle
stdin BufferMode
LineBuffering

-- | When a process exits with a non-zero exit code
-- we throw this @Failure@ exception.
--
-- The only exception to this is when a process is terminated
-- by @SIGPIPE@ in a pipeline, in which case we ignore it.
data Failure = Failure
    { Failure -> ByteString
failureProg   :: ByteString
    , Failure -> [ByteString]
failureArgs   :: [ByteString]
    , Failure -> CallStack
failureStack  :: CallStack
    , Failure -> Int
failureCode   :: Int
    -- | Failure can optionally contain the stderr of a process.
    , Failure -> Maybe ByteString
failureStdErr :: Maybe ByteString
    }

instance Show Failure where
    show :: Failure -> String
show Failure
f = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$
        [ String
"Command `"
        ]
        forall a. [a] -> [a] -> [a]
++ [[String] -> String
unwords (ByteString -> String
toString (Failure -> ByteString
failureProg Failure
f) forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map forall a. Show a => a -> String
show (Failure -> [ByteString]
failureArgs Failure
f))]
        forall a. [a] -> [a] -> [a]
++
        [ String
"` failed [exit "
        , forall a. Show a => a -> String
show (Failure -> Int
failureCode Failure
f)
        , String
"] at "
        , CallStack -> String
prettyCallStack (Failure -> CallStack
failureStack Failure
f)
        ]
        forall a. [a] -> [a] -> [a]
++ forall a b c. (a -> b -> c) -> b -> a -> c
flip (forall b a. b -> (a -> b) -> Maybe a -> b
maybe []) (Failure -> Maybe ByteString
failureStdErr Failure
f) (\ByteString
s ->
           [String
"\n-- stderr --\n" forall a. [a] -> [a] -> [a]
++ ByteString -> String
toString ByteString
s])

instance Exception Failure

-- | This class is used to allow most of the operators in Shh to be
-- polymorphic in their return value. This makes using them in an `IO` context
-- easier (we can avoid having to prepend everything with a `runProc`).
class Shell f where
    runProc :: HasCallStack => Proc a -> f a

-- | Helper function that creates and potentially executes a @`Proc`@
buildProc :: Shell f => (Handle -> Handle -> Handle -> IO a) -> f a
buildProc :: forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (Handle -> Handle -> Handle -> IO a) -> Proc a
Proc

-- | Like @`|>`@ except that it keeps both return results. Be aware
-- that the @fst@ element of this tuple may be hiding a @SIGPIPE@
-- exception that will explode on you once you look at it.
--
-- You probably want to use @`|>`@ unless you know you don't.
pipe :: Shell f => Proc a -> Proc b -> f (a, b)
pipe :: forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f (a, b)
pipe (Proc Handle -> Handle -> Handle -> IO a
a) (Proc Handle -> Handle -> Handle -> IO b
b) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e ->
    forall a. (Handle -> Handle -> IO a) -> IO a
withPipe forall a b. (a -> b) -> a -> b
$ \Handle
r Handle
w -> do
        let
            a' :: IO a
a' = Handle -> Handle -> Handle -> IO a
a Handle
i Handle
w Handle
e forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
w
            b' :: IO b
b' = Handle -> Handle -> Handle -> IO b
b Handle
r Handle
o Handle
e forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
r
        forall a b. IO a -> IO b -> IO (a, b)
concurrently IO a
a' IO b
b'

-- | Like @`pipe`@, but plumbs stderr. See the warning in @`pipe`@.
pipeErr :: Shell f => Proc a -> Proc b -> f (a, b)
pipeErr :: forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f (a, b)
pipeErr (Proc Handle -> Handle -> Handle -> IO a
a) (Proc Handle -> Handle -> Handle -> IO b
b) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> do
    forall a. (Handle -> Handle -> IO a) -> IO a
withPipe forall a b. (a -> b) -> a -> b
$ \Handle
r Handle
w -> do
        let
            a' :: IO a
a' = Handle -> Handle -> Handle -> IO a
a Handle
i Handle
o Handle
w forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
w
            b' :: IO b
b' = Handle -> Handle -> Handle -> IO b
b Handle
r Handle
o Handle
e forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
r
        forall a b. IO a -> IO b -> IO (a, b)
concurrently IO a
a' IO b
b'


-- | Use this to send the output of one process into the input of another.
-- This is just like a shell's `|` operator.
--
-- The result is polymorphic in its output, and can result in either
-- another `Proc a` or an `IO a` depending on the context in which it is
-- used.
--
-- If any intermediate process throws an exception, the whole pipeline
-- is canceled.
--
-- The result of the last process in the chain is the result returned
-- by the pipeline. 
--
-- >>> echo "Hello" |> wc
--       1       1       6
(|>) :: Shell f => Proc a -> Proc b -> f b
Proc a
a |> :: forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
|> Proc b
b = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd (Proc a
a forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f (a, b)
`pipe` Proc b
b)
infixl 1 |>


-- | Similar to `|>` except that it connects stderr to stdin of the
-- next process in the chain.
--
-- NB: The next command to be `|>` on will recapture the stdout of
-- both preceding processes, because they are both going to the same
-- handle!
--                                            
-- See the `&>` and `&!>` operators for redirection.
--
-- >>> echo "Ignored" |!> wc "-c"
-- Ignored
-- 0
(|!>) :: Shell f => Proc a -> Proc b -> f b
Proc a
a |!> :: forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
|!> Proc b
b = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd (Proc a
a forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f (a, b)
`pipeErr` Proc b
b)
infixl 1 |!>

-- | Things that can be converted to a @`FilePath`@.
--
-- The results must use the file system encoding. Use this
-- if you want to pass a @ByteString@ to @`System.IO.openFile`@,
-- or if you want to turn a @FilePath@ into a @ByteString@.
--
-- If you never change the file system encoding, it should be safe to use
-- @`unsafePerformIO`@ on these functions.
class ToFilePath a where
    toFilePath :: a -> IO FilePath
    fromFilePath :: FilePath -> IO a

instance ToFilePath FilePath where
    toFilePath :: String -> IO String
toFilePath = forall (f :: * -> *) a. Applicative f => a -> f a
pure
    fromFilePath :: String -> IO String
fromFilePath = forall (f :: * -> *) a. Applicative f => a -> f a
pure

instance ToFilePath ByteString.ByteString where
    toFilePath :: ByteString -> IO String
toFilePath ByteString
bs = do
        TextEncoding
enc <- IO TextEncoding
getFileSystemEncoding
        forall a. ByteString -> (CStringLen -> IO a) -> IO a
ByteString.useAsCStringLen ByteString
bs (TextEncoding -> CStringLen -> IO String
peekCStringLen TextEncoding
enc)
    fromFilePath :: String -> IO ByteString
fromFilePath String
fp = do
        TextEncoding
enc <- IO TextEncoding
getFileSystemEncoding
        TextEncoding -> String -> IO CStringLen
newCStringLen TextEncoding
enc String
fp forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CStringLen -> IO ByteString
ByteString.unsafePackMallocCStringLen

instance ToFilePath ByteString where
    toFilePath :: ByteString -> IO String
toFilePath = forall a. ToFilePath a => a -> IO String
toFilePath forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
toStrict
    fromFilePath :: String -> IO ByteString
fromFilePath = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> ByteString
fromStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToFilePath a => String -> IO a
fromFilePath

--
-- | Redirect stdout of this process to another location
--
-- >>> echo "Ignore me" &> Append "/dev/null"
(&>) :: Shell f => Proc a -> Stream -> f a
Proc a
p &> :: forall (f :: * -> *) a. Shell f => Proc a -> Stream -> f a
&> Stream
StdOut = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc Proc a
p
(Proc Handle -> Handle -> Handle -> IO a
f) &> Stream
StdErr = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
_ Handle
e -> Handle -> Handle -> Handle -> IO a
f Handle
i Handle
e Handle
e
(Proc Handle -> Handle -> Handle -> IO a
f) &> (Truncate ByteString
path) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
_ Handle
e -> do
    String
path' <- forall a. ToFilePath a => a -> IO String
toFilePath ByteString
path
    forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile String
path' IOMode
WriteMode forall a b. (a -> b) -> a -> b
$ \Handle
h -> Handle -> Handle -> Handle -> IO a
f Handle
i Handle
h Handle
e
(Proc Handle -> Handle -> Handle -> IO a
f) &> (Append ByteString
path) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
_ Handle
e -> do
    String
path' <- forall a. ToFilePath a => a -> IO String
toFilePath ByteString
path
    forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile String
path' IOMode
AppendMode forall a b. (a -> b) -> a -> b
$ \Handle
h -> Handle -> Handle -> Handle -> IO a
f Handle
i Handle
h Handle
e
infixl 9 &>

-- | Redirect stderr of this process to another location
--
-- >>> echo "Shh" &!> StdOut
-- Shh
(&!>) :: Shell f => Proc a -> Stream -> f a
Proc a
p &!> :: forall (f :: * -> *) a. Shell f => Proc a -> Stream -> f a
&!> Stream
StdErr = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc Proc a
p
(Proc Handle -> Handle -> Handle -> IO a
f) &!> Stream
StdOut = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
_ -> Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
o
(Proc Handle -> Handle -> Handle -> IO a
f) &!> (Truncate ByteString
path) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
_ -> do
    String
path' <- forall a. ToFilePath a => a -> IO String
toFilePath ByteString
path
    forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile String
path' IOMode
WriteMode forall a b. (a -> b) -> a -> b
$ \Handle
h -> Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
h
(Proc Handle -> Handle -> Handle -> IO a
f) &!> (Append ByteString
path) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
_ -> do
    String
path' <- forall a. ToFilePath a => a -> IO String
toFilePath ByteString
path
    forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile String
path' IOMode
AppendMode forall a b. (a -> b) -> a -> b
$ \Handle
h -> Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
h
infixl 9 &!>

-- | Lift a Haskell function into a @`Proc`@. The handles are the @stdin@
-- @stdout@ and @stderr@ of the resulting @`Proc`@
nativeProc :: (Shell f, NFData a) => (Handle -> Handle -> Handle -> IO a) -> f a
nativeProc :: forall (f :: * -> *) a.
(Shell f, NFData a) =>
(Handle -> Handle -> Handle -> IO a) -> f a
nativeProc Handle -> Handle -> Handle -> IO a
f = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall a b. (a -> b) -> a -> b
$ forall a. (Handle -> Handle -> Handle -> IO a) -> Proc a
Proc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle forall a. IOError -> IO a
handler forall a b. (a -> b) -> a -> b
$ do
    -- We duplicate these so that you can't accidentally close the
    -- real ones.
    forall a.
Handle
-> Handle -> Handle -> (Handle -> Handle -> Handle -> IO a) -> IO a
withDuplicates Handle
i Handle
o Handle
e forall a b. (a -> b) -> a -> b
$ \Handle
i' Handle
o' Handle
e' -> do
        (Handle -> Handle -> Handle -> IO a
f Handle
i' Handle
o' Handle
e' forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a. a -> IO a
C.evaluate forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. NFData a => a -> a
force)
            forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
i'
            forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
o'
            forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
e'

    where
        -- The resource vanished error only occurs when upstream pipe closes.
        -- This can only happen with the `|>` combinator, which will discard
        -- the result of this `Proc` anyway. If the return value is somehow
        -- inspected, or maybe if the exception is somehow legitimate, we
        -- simply package it up as an exploding return value. `runProc` will
        -- make sure to evaluate all `Proc`'s to WHNF in order to uncover it.
        -- This should never happen. *nervous*
        handler :: IOError -> IO a
        handler :: forall a. IOError -> IO a
handler IOError
e
            | IOError -> IOErrorType
ioeGetErrorType IOError
e forall a. Eq a => a -> a -> Bool
== IOErrorType
ResourceVanished = forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a e. Exception e => e -> a
throw IOError
e)
            | Bool
otherwise = forall e a. Exception e => e -> IO a
throwIO IOError
e

-- | Flipped version of `|>` with lower precedence.
--
-- >>> captureTrim <| (echo "Hello" |> wc "-c")
-- "6"
(<|) :: Shell f => Proc a -> Proc b -> f a
<| :: forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f a
(<|) = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
(|>)
infixr 1 <|

-- | Create a pipe, and close both ends on exception. The first argument
-- is the read end, the second is the write end.
--
-- >>> withPipe $ \r w -> hPutStr w "test" >> hClose w >> hGetLine r
-- "test"
withPipe :: (Handle -> Handle -> IO a) -> IO a
withPipe :: forall a. (Handle -> Handle -> IO a) -> IO a
withPipe Handle -> Handle -> IO a
k =
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
        IO (Handle, Handle)
createPipe
        (\(Handle
r,Handle
w) -> Handle -> IO ()
hClose Handle
r forall a b. IO a -> IO b -> IO a
`finally` Handle -> IO ()
hClose Handle
w)
        (\(Handle
r,Handle
w) -> Handle -> Handle -> IO a
k Handle
r Handle
w)

-- | Simple @`Proc`@ that writes its argument to its @stdout@. This behaves
-- very much like the standard @printf@ utility, except that there is no
-- restriction as to what can be in the argument.
--
-- NB: @String@ arguments are encoded as UTF8, while @ByteString@ is passed
-- through. Be aware if you are using @OverloadedStrings@ that you will get
-- wrong results if using unicode in your string literal and it inferes
-- anything other than @String@.
--
-- >>> writeOutput "Hello"
-- Hello
writeOutput :: (ExecArg a, Shell io) => a -> io ()
writeOutput :: forall a (io :: * -> *). (ExecArg a, Shell io) => a -> io ()
writeOutput a
s = forall (f :: * -> *) a.
(Shell f, NFData a) =>
(Handle -> Handle -> Handle -> IO a) -> f a
nativeProc forall a b. (a -> b) -> a -> b
$ \Handle
_ Handle
o Handle
_ -> do
    forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Handle -> ByteString -> IO ()
BS.hPutStr Handle
o) (forall a. ExecArg a => a -> [ByteString]
asArg a
s)

-- | Simple @`Proc`@ that writes its argument to its @stderr@.
-- See also @`writeOutput`@.
--
-- >>> writeError "Hello" &> devNull
-- Hello
writeError :: (ExecArg a, Shell io) => a -> io ()
writeError :: forall a (io :: * -> *). (ExecArg a, Shell io) => a -> io ()
writeError a
s = forall (f :: * -> *) a.
(Shell f, NFData a) =>
(Handle -> Handle -> Handle -> IO a) -> f a
nativeProc forall a b. (a -> b) -> a -> b
$ \Handle
_ Handle
_ Handle
e -> do
   forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Handle -> ByteString -> IO ()
BS.hPutStr Handle
e) (forall a. ExecArg a => a -> [ByteString]
asArg a
s)

-- | Simple @`Proc`@ that reads its input, and can react to it with an IO
-- action. Does not write anything to its output. See also @`capture`@.
--
-- @`readInput`@ uses lazy IO to read its stdin, and works with infinite
-- inputs.
--
-- >>> yes |> readInput (pure . unlines . take 3 . lines)
-- "y\ny\ny\n"
readInput :: (NFData a, Shell io) => (ByteString -> IO a) -> io a
readInput :: forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput ByteString -> IO a
f = forall (f :: * -> *) a.
(Shell f, NFData a) =>
(Handle -> Handle -> Handle -> IO a) -> f a
nativeProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
_ Handle
_ -> do
    Handle -> IO ByteString
hGetContents Handle
i forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString -> IO a
f

-- | Join a list of @ByteString@s with newline characters, terminating it
-- with a newline.
unlines :: [ByteString] -> ByteString
unlines :: [ByteString] -> ByteString
unlines = Builder -> ByteString
toLazyByteString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Monoid a => [a] -> a
mconcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (\ByteString
l -> ByteString -> Builder
lazyByteString ByteString
l forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'\n')

-- | Like @`readInput`@, but @`endBy`@s the string.
--
-- >>> yes |> readInputEndBy "\n" (pure . take 3)
-- ["y","y","y"]
readInputEndBy :: (NFData a, Shell io) => ByteString -> ([ByteString] -> IO a) -> io a
readInputEndBy :: forall a (io :: * -> *).
(NFData a, Shell io) =>
ByteString -> ([ByteString] -> IO a) -> io a
readInputEndBy ByteString
s [ByteString] -> IO a
f = forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput ([ByteString] -> IO a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> [ByteString]
endBy ByteString
s)

-- | Like @`readInput`@, but @`endBy`@s the string on the 0 byte.
--
-- >>> writeOutput "1\0\&2\0" |> readInputEndBy0 pure
-- ["1","2"]
readInputEndBy0 :: (NFData a, Shell io) => ([ByteString] -> IO a) -> io a
readInputEndBy0 :: forall a (io :: * -> *).
(NFData a, Shell io) =>
([ByteString] -> IO a) -> io a
readInputEndBy0 = forall a (io :: * -> *).
(NFData a, Shell io) =>
ByteString -> ([ByteString] -> IO a) -> io a
readInputEndBy ByteString
"\0"

-- | Like @`readInput`@, but @`endBy`@s the string on new lines.
--
-- >>> writeOutput "a\nb\n" |> readInputLines pure
-- ["a","b"]
readInputLines :: (NFData a, Shell io) => ([ByteString] -> IO a) -> io a
readInputLines :: forall a (io :: * -> *).
(NFData a, Shell io) =>
([ByteString] -> IO a) -> io a
readInputLines = forall a (io :: * -> *).
(NFData a, Shell io) =>
ByteString -> ([ByteString] -> IO a) -> io a
readInputEndBy ByteString
"\n"

-- | Creates a pure @`Proc`@ that simple transforms the @stdin@ and writes
-- it to @stdout@. The input can be infinite.
--
-- >>> yes |> pureProc (BS.take 4) |> capture
-- "y\ny\n"
pureProc :: Shell io => (ByteString -> ByteString) -> io ()
pureProc :: forall (io :: * -> *).
Shell io =>
(ByteString -> ByteString) -> io ()
pureProc ByteString -> ByteString
f = forall (f :: * -> *) a.
(Shell f, NFData a) =>
(Handle -> Handle -> Handle -> IO a) -> f a
nativeProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
_ -> do
    ByteString
s <- Handle -> IO ByteString
hGetContents Handle
i
    Handle -> ByteString -> IO ()
BS.hPutStr Handle
o (ByteString -> ByteString
f ByteString
s)

-- | Captures the stdout of a process and prefixes all the lines with
-- the given string.
--
-- >>> some_command |> prefixLines "stdout: " |!> prefixLines "stderr: " &> StdErr
-- stdout: this is stdout
-- stderr: this is stderr
prefixLines :: Shell io => ByteString -> io ()
prefixLines :: forall (io :: * -> *). Shell io => ByteString -> io ()
prefixLines ByteString
s = forall (io :: * -> *).
Shell io =>
(ByteString -> ByteString) -> io ()
pureProc forall a b. (a -> b) -> a -> b
$ \ByteString
inp -> Builder -> ByteString
toLazyByteString forall a b. (a -> b) -> a -> b
$
    forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (\ByteString
l -> ByteString -> Builder
lazyByteString ByteString
s forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
lazyByteString ByteString
l forall a. Semigroup a => a -> a -> a
<> Char -> Builder
char7 Char
'\n') (ByteString -> [ByteString]
BC8.lines ByteString
inp)

-- | Provide the stdin of a `Proc` from a `ByteString`
--
-- Same as @`writeOutput` s |> p@
writeProc :: Shell io => Proc a -> ByteString -> io a
writeProc :: forall (io :: * -> *) a. Shell io => Proc a -> ByteString -> io a
writeProc Proc a
p ByteString
s = forall a (io :: * -> *). (ExecArg a, Shell io) => a -> io ()
writeOutput ByteString
s forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
|> Proc a
p

-- | Run a process and capture its output lazily. Once the continuation
-- is completed, the handles are closed. However, the process is run
-- until it naturally terminates in order to capture the correct exit
-- code. Most utilities behave correctly with this (e.g. @cat@ will
-- terminate if you close the handle).
--
-- Same as @p |> readInput f@
withRead :: (Shell f, NFData b) => Proc a -> (ByteString -> IO b) -> f b
withRead :: forall (f :: * -> *) b a.
(Shell f, NFData b) =>
Proc a -> (ByteString -> IO b) -> f b
withRead Proc a
p ByteString -> IO b
f = Proc a
p forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
|> forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput ByteString -> IO b
f

-- | Type used to represent destinations for redirects. @`Truncate` file@
-- is like @> file@ in a shell, and @`Append` file@ is like @>> file@.
data Stream = StdOut | StdErr | Truncate ByteString | Append ByteString

-- | Shortcut for @`Truncate` "\/dev\/null"@
-- 
-- >>> echo "Hello" &> devNull
devNull :: Stream
devNull :: Stream
devNull = ByteString -> Stream
Truncate ByteString
"/dev/null"

-- | Type representing a series or pipeline (or both) of shell commands.
--
-- @Proc@'s can communicate to each other via @stdin@, @stdout@ and @stderr@
-- and can communicate to Haskell via their parameterised return type, or by
-- throwing an exception.
newtype Proc a = Proc (Handle -> Handle -> Handle -> IO a)
    deriving forall a b. a -> Proc b -> Proc a
forall a b. (a -> b) -> Proc a -> Proc b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Proc b -> Proc a
$c<$ :: forall a b. a -> Proc b -> Proc a
fmap :: forall a b. (a -> b) -> Proc a -> Proc b
$cfmap :: forall a b. (a -> b) -> Proc a -> Proc b
Functor

instance MonadIO Proc where
    liftIO :: forall a. IO a -> Proc a
liftIO IO a
a = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
_ Handle
_ Handle
_ -> IO a
a

-- | The `Semigroup` instance for `Proc` pipes the stdout of one process
-- into the stdin of the next. However, consider using `|>` instead which
-- behaves when used in an `IO` context. If you use `<>` in an IO monad
-- you will be using the `IO` instance of semigroup which is a sequential
-- execution. `|>` prevents that error.
instance Semigroup (Proc a) where
    <> :: Proc a -> Proc a -> Proc a
(<>) = forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
(|>)

instance (a ~ ()) => Monoid (Proc a) where
    mempty :: Proc a
mempty = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
_ Handle
_ Handle
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

instance Applicative Proc where
    pure :: forall a. a -> Proc a
pure a
a = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
_ Handle
_ Handle
_  -> do
        forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a

    Proc (a -> b)
f <*> :: forall a b. Proc (a -> b) -> Proc a -> Proc b
<*> Proc a
a = do
        a -> b
f' <- Proc (a -> b)
f
        a -> b
f' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Proc a
a
        
instance Monad Proc where
    (Proc Handle -> Handle -> Handle -> IO a
a) >>= :: forall a b. Proc a -> (a -> Proc b) -> Proc b
>>= a -> Proc b
f = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> do
        a
ar <- Handle -> Handle -> Handle -> IO a
a Handle
i Handle
o Handle
e
        let
            Proc Handle -> Handle -> Handle -> IO b
f' = a -> Proc b
f a
ar
        Handle -> Handle -> Handle -> IO b
f' Handle
i Handle
o Handle
e

instance Shell IO where
    runProc :: forall a. HasCallStack => Proc a -> IO a
runProc = forall a. Handle -> Handle -> Handle -> Proc a -> IO a
runProc' Handle
stdin Handle
stdout Handle
stderr

instance Shell Proc where
    runProc :: forall a. HasCallStack => Proc a -> Proc a
runProc = forall a. a -> a
id

-- | Runs a `Proc` in `IO`. Like `runProc`, but you get to choose the handles.
-- This is UNSAFE to expose externally, because there are restrictions on what
-- the Handle can be. Within shh, we never call `runProc'` with invalid handles,
-- so we ignore that corner case (see `hDup`).
runProc' :: Handle -> Handle -> Handle -> Proc a -> IO a
runProc' :: forall a. Handle -> Handle -> Handle -> Proc a -> IO a
runProc' Handle
i Handle
o Handle
e (Proc Handle -> Handle -> Handle -> IO a
f) = do
    -- Flush stdout and stderr so that sequencing commands with
    -- Haskell IO functions looks right.
    Handle -> IO ()
hFlush Handle
stdout
    Handle -> IO ()
hFlush Handle
stderr
    a
r <- Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
e
    -- Evaluate to WHNF to uncover any ResourceVanished exceptions
    -- that may be hiding in there from `nativeProc`. These should
    -- not happen under normal circumstances, but we would at least
    -- like to have the exception thrown ASAP if, for whatever reason,
    -- it does happen.
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$! a
r

-- | Create a `Proc` from a command and a list of arguments.
-- The boolean represents whether we should delegate control-c
-- or not. Most uses of @`mkProc'`@ in Shh do not delegate control-c.
{-# DEPRECATED mkProc' "Use mkProcWith instead" #-}
mkProc' :: HasCallStack => Bool -> ByteString -> [ByteString] -> Proc ()
mkProc' :: HasCallStack => Bool -> ByteString -> [ByteString] -> Proc ()
mkProc' Bool
delegate = HasCallStack =>
ProcOptions -> ByteString -> [ByteString] -> Proc ()
mkProcWith ProcOptions
defaultProcOptions { delegateCtlc :: Bool
delegateCtlc = Bool
delegate }

-- | Options for making processes.
data ProcOptions = ProcOptions
    { ProcOptions -> Bool
delegateCtlc :: Bool -- ^ Delegate control-c handling to the child.
    , ProcOptions -> Bool
closeFds     :: Bool -- ^ Close file descriptors before @exec@ing.
    }

-- | Default ProcOptions as used by most of this library.
defaultProcOptions :: ProcOptions
defaultProcOptions :: ProcOptions
defaultProcOptions = ProcOptions
    { delegateCtlc :: Bool
delegateCtlc = Bool
True
    , closeFds :: Bool
closeFds     = Bool
True
    }

-- | Create a `Proc` with custom options.
mkProcWith :: HasCallStack => ProcOptions -> ByteString -> [ByteString] -> Proc ()
mkProcWith :: HasCallStack =>
ProcOptions -> ByteString -> [ByteString] -> Proc ()
mkProcWith ProcOptions
options ByteString
cmd [ByteString]
args = forall a. (Handle -> Handle -> Handle -> IO a) -> Proc a
Proc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> do
    String
cmd' <- forall a. ToFilePath a => a -> IO String
toFilePath ByteString
cmd
    [String]
args' <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall a. ToFilePath a => a -> IO String
toFilePath [ByteString]
args
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
        (String
-> CreateProcess
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
createProcess_ String
cmd' (String -> [String] -> CreateProcess
proc String
cmd' [String]
args')
            { std_in :: StdStream
std_in = Handle -> StdStream
UseHandle Handle
i
            , std_out :: StdStream
std_out = Handle -> StdStream
UseHandle Handle
o
            , std_err :: StdStream
std_err = Handle -> StdStream
UseHandle Handle
e
            , close_fds :: Bool
close_fds = ProcOptions -> Bool
closeFds ProcOptions
options
            , delegate_ctlc :: Bool
delegate_ctlc = ProcOptions -> Bool
delegateCtlc ProcOptions
options
            }
        )
        (\(Maybe Handle
_,Maybe Handle
_,Maybe Handle
_,ProcessHandle
ph) -> ProcessHandle -> IO ()
terminateProcess ProcessHandle
ph forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
ph)
        forall a b. (a -> b) -> a -> b
$ \(Maybe Handle
_,Maybe Handle
_,Maybe Handle
_,ProcessHandle
ph) -> HasCallStack =>
ByteString -> [ByteString] -> ProcessHandle -> IO ()
waitProc ByteString
cmd [ByteString]
args ProcessHandle
ph forall a b. IO a -> IO b -> IO a
`onException` (ProcessHandle -> IO ()
terminateProcess ProcessHandle
ph forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
ph)

-- | Create a `Proc` from a command and a list of arguments. Does not delegate
-- control-c handling.
mkProc :: HasCallStack => ByteString -> [ByteString] -> Proc ()
mkProc :: HasCallStack => ByteString -> [ByteString] -> Proc ()
mkProc = HasCallStack =>
ProcOptions -> ByteString -> [ByteString] -> Proc ()
mkProcWith ProcOptions
defaultProcOptions

-- | A special `Proc` which captures its stdin and presents it as a `ByteString`
-- to Haskell.
--
-- >>> printf "Hello" |> md5sum |> capture
-- "8b1a9953c4611296a827abf8c47804d7  -\n"
--
-- This is just @`readInput` pure@. Note that it is not lazy, and will read
-- the entire @ByteString@ into memory.
capture :: Shell io => io ByteString
capture :: forall (io :: * -> *). Shell io => io ByteString
capture = forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | Like @'capture'@, except that it @'trim'@s leading and trailing white
-- space.
--
-- >>> printf "Hello" |> md5sum |> captureTrim
-- "8b1a9953c4611296a827abf8c47804d7  -"
captureTrim :: Shell io => io ByteString
captureTrim :: forall (io :: * -> *). Shell io => io ByteString
captureTrim = forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
trim)

-- | Like @'capture'@, but splits the input using the provided separator.
--
-- NB: This is strict. If you want a streaming version, use `readInput`
captureEndBy :: Shell io => ByteString -> io [ByteString]
captureEndBy :: forall (io :: * -> *). Shell io => ByteString -> io [ByteString]
captureEndBy ByteString
s = forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> [ByteString]
endBy ByteString
s)

-- | Same as @'captureEndBy' "\\0"@.
captureEndBy0 :: Shell io => io [ByteString]
captureEndBy0 :: forall (io :: * -> *). Shell io => io [ByteString]
captureEndBy0 = forall (io :: * -> *). Shell io => ByteString -> io [ByteString]
captureEndBy ByteString
"\0"

-- | Same as @'captureEndBy' "\\n"@.
captureLines :: Shell io => io [ByteString]
captureLines :: forall (io :: * -> *). Shell io => io [ByteString]
captureLines = forall (io :: * -> *). Shell io => ByteString -> io [ByteString]
captureEndBy ByteString
"\n"

-- | Capture stdout, splitting it into words.
captureWords :: Shell io => io [ByteString]
captureWords :: forall (io :: * -> *). Shell io => io [ByteString]
captureWords = forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
BC8.words)

-- | Capture stdout, and attempt to @`read`@ it
captureRead :: (Shell io, Read a, NFData a) => io a
captureRead :: forall (io :: * -> *) a. (Shell io, Read a, NFData a) => io a
captureRead = forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> IO a) -> io a
readInput (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Read a => String -> a
read forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
toString)

-- | Apply a `Proc` to a `ByteString`. That is, feed the bytestring to
-- the @stdin@ of the process and read the @stdout@.
--
-- >> apply md5sum "Hello"
-- "8b1a9953c4611296a827abf8c47804d7  -\n"
apply :: (ExecArg a, Shell io) => Proc v -> a -> io ByteString
apply :: forall a (io :: * -> *) v.
(ExecArg a, Shell io) =>
Proc v -> a -> io ByteString
apply Proc v
p a
b = forall a (io :: * -> *). (ExecArg a, Shell io) => a -> io ()
writeOutput a
b forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
|> Proc v
p forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f b
|> forall (io :: * -> *). Shell io => io ByteString
capture

-- | Flipped, infix version of `writeProc`
(>>>) :: Shell io => ByteString -> Proc a -> io a
>>> :: forall (io :: * -> *) a. Shell io => ByteString -> Proc a -> io a
(>>>) = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (io :: * -> *) a. Shell io => Proc a -> ByteString -> io a
writeProc


-- | Infix version of `writeProc`
(<<<) :: Shell io => Proc a -> ByteString -> io a
<<< :: forall (io :: * -> *) a. Shell io => Proc a -> ByteString -> io a
(<<<) = forall (io :: * -> *) a. Shell io => Proc a -> ByteString -> io a
writeProc

-- | Wait on a given `ProcessHandle`, and throw an exception of
-- type `Failure` if its exit code is non-zero (ignoring SIGPIPE)
waitProc :: HasCallStack => ByteString -> [ByteString] -> ProcessHandle -> IO ()
waitProc :: HasCallStack =>
ByteString -> [ByteString] -> ProcessHandle -> IO ()
waitProc ByteString
cmd [ByteString]
arg ProcessHandle
ph = ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
ph forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    ExitFailure Int
c
        | forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
c forall a. Eq a => a -> a -> Bool
== forall a. Num a => a -> a
negate CInt
sigPIPE -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        | Bool
otherwise -> forall e a. Exception e => e -> IO a
throwIO forall a b. (a -> b) -> a -> b
$ ByteString
-> [ByteString] -> CallStack -> Int -> Maybe ByteString -> Failure
Failure ByteString
cmd [ByteString]
arg HasCallStack => CallStack
callStack Int
c forall a. Maybe a
Nothing
    ExitCode
ExitSuccess -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()


-- | Drop trailing characters from a @ByteString@ while the given predicate
-- matches.
--
-- >>> dropWhileEnd isSpace "a line \n"
-- "a line"
dropWhileEnd :: (Char -> Bool) -> ByteString -> ByteString
dropWhileEnd :: (Char -> Bool) -> ByteString -> ByteString
dropWhileEnd Char -> Bool
p ByteString
b = case ByteString -> Maybe (ByteString, Char)
BC8.unsnoc ByteString
b of
    Just (ByteString
i, Char
l) -> if Char -> Bool
p Char
l then (Char -> Bool) -> ByteString -> ByteString
dropWhileEnd Char -> Bool
p ByteString
i else ByteString
b
    Maybe (ByteString, Char)
Nothing     -> ByteString
b

-- | Trim leading and tailing whitespace.
--
-- >>> trim " a string \n"
-- "a string"
trim :: ByteString -> ByteString
trim :: ByteString -> ByteString
trim = (Char -> Bool) -> ByteString -> ByteString
dropWhileEnd Char -> Bool
isSpace forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ByteString -> ByteString
BC8.dropWhile Char -> Bool
isSpace

-- | Run a `Proc` action, catching any `Failure` exceptions
-- and returning them.
tryFailure :: Shell m => Proc a -> m (Either Failure a)
tryFailure :: forall (m :: * -> *) a. Shell m => Proc a -> m (Either Failure a)
tryFailure (Proc Handle -> Handle -> Handle -> IO a
f) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> forall e a. Exception e => IO a -> IO (Either e a)
try forall a b. (a -> b) -> a -> b
$ Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
e

-- | Like @`tryFailure`@ except that it takes an exception predicate which
-- selects which exceptions to catch. Any exception not matching the predicate
-- (returning @Nothing@) is re-thrown.
tryFailureJust :: Shell m => (Failure -> Maybe b) -> Proc a -> m (Either b a)
tryFailureJust :: forall (m :: * -> *) b a.
Shell m =>
(Failure -> Maybe b) -> Proc a -> m (Either b a)
tryFailureJust Failure -> Maybe b
pr (Proc Handle -> Handle -> Handle -> IO a
f) = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> forall e b a.
Exception e =>
(e -> Maybe b) -> IO a -> IO (Either b a)
tryJust Failure -> Maybe b
pr (Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
e)

-- | Run a `Proc` with an action to take if an exception is thrown.
catchFailure :: Shell m => Proc a -> (Failure -> Proc a) -> m a
catchFailure :: forall (m :: * -> *) a.
Shell m =>
Proc a -> (Failure -> Proc a) -> m a
catchFailure (Proc Handle -> Handle -> Handle -> IO a
f) Failure -> Proc a
pr = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
e) (forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall b c a. (b -> c) -> (a -> b) -> a -> c
. Failure -> Proc a
pr)

-- | Like @`catchFailureJust`@ except that it takes an exception predicate
-- which selects which exceptions to catch. Any exceptions not matching the
-- predicate (returning @Nothing@) are re-thrown.
catchFailureJust :: Shell m => (Failure -> Maybe b) -> Proc a -> (b -> Proc a) -> m a
catchFailureJust :: forall (m :: * -> *) b a.
Shell m =>
(Failure -> Maybe b) -> Proc a -> (b -> Proc a) -> m a
catchFailureJust Failure -> Maybe b
pr (Proc Handle -> Handle -> Handle -> IO a
f) b -> Proc a
h = forall (f :: * -> *) a.
Shell f =>
(Handle -> Handle -> Handle -> IO a) -> f a
buildProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> forall e b a.
Exception e =>
(e -> Maybe b) -> IO a -> (b -> IO a) -> IO a
catchJust Failure -> Maybe b
pr (Handle -> Handle -> Handle -> IO a
f Handle
i Handle
o Handle
e) (forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Proc a
h)

-- | Apply a function that translates non-0 exit codes to results. Any code
-- that returns a @Nothing@ will be thrown as a @`Failure`@.
translateCode' :: Shell m => (Int -> Maybe b) -> Proc a -> m (Either b a)
translateCode' :: forall (m :: * -> *) b a.
Shell m =>
(Int -> Maybe b) -> Proc a -> m (Either b a)
translateCode' Int -> Maybe b
f = forall (m :: * -> *) b a.
Shell m =>
(Failure -> Maybe b) -> Proc a -> m (Either b a)
tryFailureJust (Int -> Maybe b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. Failure -> Int
failureCode)

-- | Apply a function to non-0 exit codes to extract a result. If @Nothing@
-- is produced, the @`Failure`@ is thrown.
translateCode :: Shell m => (Int -> Maybe a) -> Proc a -> m a
translateCode :: forall (m :: * -> *) a.
Shell m =>
(Int -> Maybe a) -> Proc a -> m a
translateCode Int -> Maybe a
f Proc a
p = forall (m :: * -> *) b a.
Shell m =>
(Failure -> Maybe b) -> Proc a -> (b -> Proc a) -> m a
catchFailureJust (Int -> Maybe a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. Failure -> Int
failureCode) Proc a
p forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | Capture the stderr of the proc, and attach it to any @`Failure`@
-- exceptions that are thrown. The stderr is also forwarded to downstream
-- processes, or the inherited stderr handle. Note that capturing stderr
-- inherently requires that the stderr is accumulated in memory, so be
-- careful about processes that dump a lot of information.
failWithStdErr :: Shell io => Proc a -> io a
failWithStdErr :: forall (io :: * -> *) a. Shell io => Proc a -> io a
failWithStdErr Proc a
p = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall a b. (a -> b) -> a -> b
$ do
    (Either Failure a, ByteString)
r <- forall (m :: * -> *) a. Shell m => Proc a -> m (Either Failure a)
tryFailure Proc a
p forall (f :: * -> *) a b. Shell f => Proc a -> Proc b -> f (a, b)
`pipeErr` forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> Proc a) -> io a
readInputP (\ByteString
i -> do
        forall a (io :: * -> *). (ExecArg a, Shell io) => a -> io ()
writeError ByteString
i
        forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString
i
        )
    case (Either Failure a, ByteString)
r of
        (Right a
a, ByteString
_) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
        (Left Failure
f, ByteString
err) -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall e a. Exception e => e -> IO a
throwIO forall a b. (a -> b) -> a -> b
$ Failure
f {failureStdErr :: Maybe ByteString
failureStdErr = forall a. a -> Maybe a
Just ByteString
err}

-- | Run a `Proc` action, ignoring any `Failure` exceptions.
-- This can be used to prevent a process from interrupting a whole pipeline.
--
-- >>> false |> (sleep "0.1" >> echo 1)
-- *** Exception: Command `false` failed [exit 1] at CallStack (from HasCallStack):
-- ...
--
-- >>> (ignoreFailure false) |> (sleep "0.1" >> echo 1)
-- 1
ignoreFailure :: (Functor m, Shell m) => Proc a -> m ()
ignoreFailure :: forall (m :: * -> *) a. (Functor m, Shell m) => Proc a -> m ()
ignoreFailure = forall (f :: * -> *) a. Functor f => f a -> f ()
void forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Shell m => Proc a -> m (Either Failure a)
tryFailure

-- | Run a `Proc` action returning the exit code of the process instead of
-- throwing an exception.
--
-- >>> exitCode false
-- 1
exitCode :: (Functor m, Shell m) => Proc a -> m Int
exitCode :: forall (m :: * -> *) a. (Functor m, Shell m) => Proc a -> m Int
exitCode = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall {b}. Either Failure b -> Int
getCode forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Shell m => Proc a -> m (Either Failure a)
tryFailure
    where
        getCode :: Either Failure b -> Int
getCode (Right b
_) = Int
0
        getCode (Left  Failure
f) = Failure -> Int
failureCode Failure
f

-- | Run the @`Proc`@, but don't throw an exception if it exits with the
-- given code. Note, that from this point on, if the proc did fail with the
-- code, everything else now sees it as having exited with 0. If you need
-- to know the code, you have to use `exitCode`.
ignoreCode :: (Monad m, Shell m) => Int -> Proc a -> m ()
ignoreCode :: forall (m :: * -> *) a. (Monad m, Shell m) => Int -> Proc a -> m ()
ignoreCode Int
code Proc a
p = forall (m :: * -> *) b a.
Shell m =>
(Failure -> Maybe b) -> Proc a -> (b -> Proc a) -> m a
catchFailureJust Failure -> Maybe ()
pr (forall (f :: * -> *) a. Functor f => f a -> f ()
void Proc a
p) forall (f :: * -> *) a. Applicative f => a -> f a
pure
    where
        pr :: Failure -> Maybe ()
pr Failure
f
            | Failure -> Int
failureCode Failure
f forall a. Eq a => a -> a -> Bool
== Int
code = forall a. a -> Maybe a
Just ()
            | Bool
otherwise             = forall a. Maybe a
Nothing

-- | A class for things that can be converted to arguments on the command
-- line. The default implementation is to use `show` and then encode it using
-- the file system encoding.
class ExecArg a where
    asArg :: a -> [ByteString]
    default asArg :: Show a => a -> [ByteString]
    asArg a
a = [forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. ToFilePath a => String -> IO a
fromFilePath forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show a
a]

    -- God, I hate that String is [Char]...
    asArgFromList :: [a] -> [ByteString]
    default asArgFromList :: Show a => [a] -> [ByteString]
    asArgFromList = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall a. ExecArg a => a -> [ByteString]
asArg

-- | The @Char@ and @String@ instances encode using the file system encoding.
instance ExecArg Char where
    asArg :: Char -> [ByteString]
asArg Char
s = [forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. ToFilePath a => String -> IO a
fromFilePath [Char
s]]
    asArgFromList :: String -> [ByteString]
asArgFromList String
s = [forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ forall a. ToFilePath a => String -> IO a
fromFilePath String
s]

-- | The @[Char]@/@String@ instance encodes using the file system encoding.
instance ExecArg a => ExecArg [a] where
    asArg :: [a] -> [ByteString]
asArg = forall a. ExecArg a => [a] -> [ByteString]
asArgFromList
    asArgFromList :: [[a]] -> [ByteString]
asArgFromList = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall a. ExecArg a => a -> [ByteString]
asArg

instance ExecArg ByteString where
    asArg :: ByteString -> [ByteString]
asArg ByteString
s = [ByteString
s]

instance ExecArg ByteString.ByteString where
    asArg :: ByteString -> [ByteString]
asArg ByteString
s = [ByteString -> ByteString
BS.fromStrict ByteString
s]

instance ExecArg Int
instance ExecArg Integer
instance ExecArg Word

-- | A class for building up a command.
class Command a where
    toArgs :: HasCallStack => [ByteString] -> a

instance (a ~ ()) => Command (Proc a) where
    toArgs :: HasCallStack => [ByteString] -> Proc a
toArgs (ByteString
cmd:[ByteString]
args) = HasCallStack => ByteString -> [ByteString] -> Proc ()
mkProc ByteString
cmd [ByteString]
args
    toArgs [ByteString]
_ = forall a. HasCallStack => String -> a
error String
"The impossible happened. How did you construct this?"

instance (ExecArg b, Command a) => Command (b -> a) where
    toArgs :: HasCallStack => [ByteString] -> b -> a
toArgs [ByteString]
f b
i = forall a. (Command a, HasCallStack) => [ByteString] -> a
toArgs forall a b. (a -> b) -> a -> b
$ [ByteString]
f forall a. [a] -> [a] -> [a]
++ forall a. ExecArg a => a -> [ByteString]
asArg b
i

-- | Commands can be executed directly in IO
instance (a ~ ()) => Command (IO a) where
    toArgs :: HasCallStack => [ByteString] -> IO a
toArgs = forall (f :: * -> *) a. (Shell f, HasCallStack) => Proc a -> f a
runProc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (Command a, HasCallStack) => [ByteString] -> a
toArgs

instance Command [ByteString] where
    toArgs :: HasCallStack => [ByteString] -> [ByteString]
toArgs = forall a. a -> a
id

instance Command [ByteString.ByteString] where
    toArgs :: HasCallStack => [ByteString] -> [ByteString]
toArgs = forall a b. (a -> b) -> [a] -> [b]
map ByteString -> ByteString
toStrict

-- | This type represents a partially built command. Further arguments
-- can be supplied to it, or it can be turned into a `Proc` or directly
-- executed in a context which supports that (such as `IO`).
type Cmd = HasCallStack => forall a. (Command a) => a

-- | This function turns a `Cmd` into a list of @`ByteString`@s.
--
-- >>> displayCommand $ echo "Hello, world!"
-- ["echo","Hello, world!"]
displayCommand :: Cmd -> [ByteString]
displayCommand :: Cmd -> [ByteString]
displayCommand = \Cmd
c -> forall a. (Command a, HasCallStack) => [ByteString] -> a
toArgs Cmd
c

-- | Get all executables on your `$PATH`.
pathBins :: IO [FilePath]
pathBins :: IO [String]
pathBins = forall a b. (a -> b) -> [a] -> [b]
map String -> String
takeFileName forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO [String]
pathBinsAbs

-- | Get all uniquely named executables on your `$PATH` as absolute
-- file names. The uniqueness is determined by the filename, and not
-- the whole path. First one found wins.
pathBinsAbs :: IO [FilePath]
pathBinsAbs :: IO [String]
pathBinsAbs = do
    [String]
pathsVar <- forall a. Eq a => [a] -> [a] -> [[a]]
Split.splitOn String
":" forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO String
getEnv String
"PATH"
    [String]
paths <- forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
Dir.doesDirectoryExist [String]
pathsVar
    [String] -> IO [String]
findBinsIn [String]
paths

-- | Get all uniquely named executables from the list of directories. Returns
-- a list of absolute file names.
findBinsIn :: [FilePath] -> IO [FilePath]
findBinsIn :: [String] -> IO [String]
findBinsIn [String]
paths = do
    [String]
ps <- forall b a. Ord b => (a -> b) -> [a] -> [a]
ordNubOn String -> String
takeFileName forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\String
d -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\String
x -> String
dforall a. [a] -> [a] -> [a]
++(Char
'/'forall a. a -> [a] -> [a]
:String
x)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [String]
Dir.getDirectoryContents String
d) [String]
paths
    forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (IO Bool -> IO Bool
tryBool forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Permissions -> Bool
Dir.executable forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO Permissions
Dir.getPermissions) [String]
ps

    where
        -- TODO: Eventually replace this with nubOrdOn (containers 0.6.0.1 dep)
        ordNubOn :: Ord b => (a -> b) -> [a] -> [a]
        ordNubOn :: forall b a. Ord b => (a -> b) -> [a] -> [a]
ordNubOn a -> b
f [a]
as = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Map k a -> [(k, a)]
Map.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. [a] -> [b] -> [(a, b)]
zip (forall a b. (a -> b) -> [a] -> [b]
map a -> b
f [a]
as) [a]
as

        tryBool :: IO Bool -> IO Bool
        tryBool :: IO Bool -> IO Bool
tryBool IO Bool
a = forall e a. Exception e => IO a -> IO (Either e a)
try IO Bool
a forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            Left (SomeException e
_) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
            Right Bool
r -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
r

-- | Execute the given command. Further arguments can be passed in.
--
-- > exe "ls" "-l"
--
-- See also `loadExe` and `loadEnv`.
--
-- NB: It is recommended that you use the template haskell functions to load
-- executables from your path. If you do it manually, it is recommended to
-- use @withFrozenCallStack@ from @GHC.Stack@
--
-- > echo :: Cmd
-- > echo = withFrozenCallStack (exe "echo")
exe :: (Command a, ExecArg str, HasCallStack) => str -> a
exe :: forall a str. (Command a, ExecArg str, HasCallStack) => str -> a
exe str
s = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ forall a. (Command a, HasCallStack) => [ByteString] -> a
toArgs (forall a. ExecArg a => a -> [ByteString]
asArg str
s)

-- | Create a function for the executable named
loadExe :: ExecReference -> String -> Q [Dec]
loadExe :: ExecReference -> String -> Q [Dec]
loadExe ExecReference
ref String
s = ExecReference -> String -> String -> Q [Dec]
loadExeAs ExecReference
ref String
s String
s

-- | Specify how executables should be referenced.
data ExecReference
    = Absolute -- ^ Find executables on PATH, but store their absolute path
    | SearchPath -- ^ Always search on PATH

-- | Template Haskell function to create a function from a path that will be
-- called. This does not check for executability at compile time.
rawExe :: String -> String -> Q [Dec]
rawExe :: String -> String -> Q [Dec]
rawExe String
fnName String
executable = do
    let
        name :: Name
name = String -> Name
mkName String
fnName
        impl :: Q Dec
impl = forall (m :: * -> *).
Quote m =>
m Pat -> m Body -> [m Dec] -> m Dec
valD (forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
name) (forall (m :: * -> *). Quote m => m Exp -> m Body
normalB [|
            withFrozenCallStack $ exe executable
            |]) []
        typ :: Dec
typ = Name -> Type -> Dec
SigD Name
name (Name -> Type
ConT ''Cmd)
    Dec
i <- Q Dec
impl
    forall (m :: * -> *) a. Monad m => a -> m a
return [Dec
typ,Dec
i]

-- | @$(loadExeAs ref fnName executable)@ defines a function called @fnName@
-- which executes the path in @executable@. If @executable@ is an absolute path
-- it is used directly. If it is just an executable name, then it is searched
-- for in the PATH environment variable. If @ref@ is @SearchPath@, the short
-- name is retained, and your PATH will be searched at runtime. If @ref@
-- is @Absolute@, a executable name will be turned into an absolute path, which
-- will be used at runtime.
loadExeAs :: ExecReference -> String -> String -> Q [Dec]
loadExeAs :: ExecReference -> String -> String -> Q [Dec]
loadExeAs ExecReference
ref String
fnName String
executable = do
    -- TODO: Can we place haddock markup in TH generated functions.
    -- TODO: Can we place the man page for each function in there xD
    -- https://ghc.haskell.org/trac/ghc/ticket/5467
    forall a. IO a -> Q a
runIO (String -> IO (Maybe String)
Dir.findExecutable String
executable) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Maybe String
Nothing -> forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"Attempted to load '" forall a. [a] -> [a] -> [a]
++ String
executable forall a. [a] -> [a] -> [a]
++ String
"', but it is not executable"
        Just String
absExe ->
            String -> String -> Q [Dec]
rawExe String
fnName (case ExecReference
ref of { ExecReference
Absolute -> String
absExe; ExecReference
SearchPath -> String
executable })


-- | Takes a string, and makes a Haskell identifier out of it. If the string
-- is a path, the filename portion is used. The exact transformation is that
-- alphanumeric characters are unchanged, @-@ becomes @_@, and @'@ is used to
-- escape all other characters. @_@ becomes @'_@, @.@ becomes @''@ and
-- anthing else is becomes a hex encoded number surrounded by @'@ characters.
--
-- Justification for changing @-@ to @_@ is that @-@ appears far more commonly
-- in executable names than @_@ does, and so we give it the more ergonomic
-- encoding.
--
-- >>> encodeIdentifier "nix-shell"
-- "nix_shell"
--
-- >>> encodeIdentifier "R"
-- "_R"
--
-- >>> encodeIdentifier "x86_64-unknown-linux-gnu-gcc"
-- "x86'_64_unknown_linux_gnu_gcc"
--
-- >>> encodeIdentifier "release.sh"
-- "release''sh"
encodeIdentifier :: String -> String
encodeIdentifier :: String -> String
encodeIdentifier String
ident =
    let
        fixBody :: String -> String
        fixBody :: String -> String
fixBody (Char
c:String
cs)
            | Char -> Bool
isAlphaNum Char
c = Char
c forall a. a -> [a] -> [a]
: String -> String
fixBody String
cs
            | Char
c forall a. Eq a => a -> a -> Bool
== Char
'-'     = Char
'_' forall a. a -> [a] -> [a]
: String -> String
fixBody String
cs
            | Char
c forall a. Eq a => a -> a -> Bool
== Char
'_'     = Char
'\'' forall a. a -> [a] -> [a]
: Char
'_' forall a. a -> [a] -> [a]
: String -> String
fixBody String
cs
            | Char
c forall a. Eq a => a -> a -> Bool
== Char
'.'     = Char
'\'' forall a. a -> [a] -> [a]
: Char
'\'' forall a. a -> [a] -> [a]
: String -> String
fixBody String
cs
            | Bool
otherwise    = forall r. PrintfType r => String -> r
printf String
"'%x'%s" (Char -> Int
ord Char
c) (String -> String
fixBody String
cs)
        fixBody [] = []

        fixStart :: String -> String
        fixStart :: String -> String
fixStart s :: String
s@(Char
c : String
_)
            | Char -> Bool
isLower Char
c = String
s
            | Bool
otherwise = Char
'_' forall a. a -> [a] -> [a]
: String
s
        fixStart [] = []

        i :: String
i = String -> String
fixStart forall a b. (a -> b) -> a -> b
$ String -> String
fixBody forall a b. (a -> b) -> a -> b
$ String -> String
takeFileName String
ident
        -- Includes cd, which has to be a built-in
        reserved :: [String]
reserved = [ String
"import", String
"if", String
"else", String
"then", String
"do", String
"in", String
"let", String
"type"
            , String
"as", String
"case", String
"of", String
"class", String
"data", String
"default", String
"deriving"
            , String
"instance", String
"forall", String
"foreign", String
"hiding", String
"infix", String
"infixl"
            , String
"infixr", String
"mdo", String
"module", String
"newtype", String
"proc", String
"qualified"
            , String
"rec", String
"where", String
"cd"]
    in if String
i forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
reserved then String
i forall a. [a] -> [a] -> [a]
++ String
"_" else String
i


-- | Scans your '$PATH' environment variable and creates a function for each
-- executable found. Binaries that would not create valid Haskell identifiers
-- are encoded using the @'encodeIdentifier'@ function.
loadEnv :: ExecReference -> Q [Dec]
loadEnv :: ExecReference -> Q [Dec]
loadEnv ExecReference
ref = ExecReference -> (String -> String) -> Q [Dec]
loadAnnotatedEnv ExecReference
ref String -> String
encodeIdentifier

-- | Test to see if an executable can be found either on the $PATH or absolute.
checkExecutable :: FilePath -> IO Bool
checkExecutable :: String -> IO Bool
checkExecutable = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO (Maybe String)
Dir.findExecutable

-- | Load the given executables into the program, checking their executability
-- and creating a function @missingExecutables@ to do a runtime check for their
-- availability. Uses the @'encodeIdentifier'@ function to create function
-- names.
load :: ExecReference -> [FilePath] -> Q [Dec]
load :: ExecReference -> [String] -> Q [Dec]
load ExecReference
ref = ExecReference -> (String -> String) -> [String] -> Q [Dec]
loadAnnotated ExecReference
ref String -> String
encodeIdentifier

-- | Same as `load`, but allows you to modify the function names.
loadAnnotated :: ExecReference -> (String -> String) -> [FilePath] -> Q [Dec]
loadAnnotated :: ExecReference -> (String -> String) -> [String] -> Q [Dec]
loadAnnotated ExecReference
ref String -> String
f [String]
bins = do
    let pairs :: [(String, String)]
pairs = forall a b. [a] -> [b] -> [(a, b)]
zip (forall a b. (a -> b) -> [a] -> [b]
map String -> String
f [String]
bins) [String]
bins
    [Dec]
ds <- forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (ExecReference -> String -> String -> Q [Dec]
loadExeAs ExecReference
ref)) [(String, String)]
pairs
    Dec
d <- forall (m :: * -> *).
Quote m =>
m Pat -> m Body -> [m Dec] -> m Dec
valD (forall (m :: * -> *). Quote m => Name -> m Pat
varP (String -> Name
mkName String
"missingExecutables")) (forall (m :: * -> *). Quote m => m Exp -> m Body
normalB [|
                filterM (fmap not . checkExecutable) bins
            |]) []

    forall (f :: * -> *) a. Applicative f => a -> f a
pure (Dec
dforall a. a -> [a] -> [a]
:[Dec]
ds)

-- | Like `loadEnv`, but allows you to modify the function name that would
-- be generated.
loadAnnotatedEnv :: ExecReference -> (String -> String) -> Q [Dec]
loadAnnotatedEnv :: ExecReference -> (String -> String) -> Q [Dec]
loadAnnotatedEnv ExecReference
ref String -> String
f = do
    [String]
bins <- forall a. IO a -> Q a
runIO forall a b. (a -> b) -> a -> b
$ case ExecReference
ref of
        ExecReference
Absolute -> IO [String]
pathBinsAbs
        ExecReference
SearchPath -> IO [String]
pathBins
    [[Dec]]
i <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [String]
bins forall a b. (a -> b) -> a -> b
$ \String
bin -> do
        String -> String -> Q [Dec]
rawExe (String -> String
f forall a b. (a -> b) -> a -> b
$ String -> String
takeFileName String
bin) String
bin
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Dec]]
i)


-- | Split a string separated by the provided separator. A trailing separator
-- is ignored, and does not produce an empty string. Compatible with the
-- output of most CLI programs, such as @find -print0@.
--
-- >>> endBy "\n" "a\nb\n"
-- ["a","b"]
--
-- >>> endBy "\n" "a\nb"
-- ["a","b"]
--
-- >>> endBy "\n" "a\nb\n\n"
-- ["a","b",""]
endBy :: ByteString -> ByteString -> [ByteString]
endBy :: ByteString -> ByteString -> [ByteString]
endBy ByteString
s ByteString
str =
    let splits :: [ByteString]
splits = ByteString -> ByteString -> [ByteString]
Search.split (ByteString -> ByteString
toStrict ByteString
s) ByteString
str
    in [ByteString] -> [ByteString]
dropLastNull [ByteString]
splits

    where
        dropLastNull :: [ByteString] -> [ByteString]
        dropLastNull :: [ByteString] -> [ByteString]
dropLastNull []   = []
        dropLastNull [ByteString
""] = []
        dropLastNull (ByteString
a : [ByteString]
as) = ByteString
a forall a. a -> [a] -> [a]
: [ByteString] -> [ByteString]
dropLastNull [ByteString]
as

-- | Load executables from the given directories
loadFromDirs :: [FilePath] -> Q [Dec]
loadFromDirs :: [String] -> Q [Dec]
loadFromDirs [String]
ps = [String] -> (String -> String) -> Q [Dec]
loadAnnotatedFromDirs [String]
ps String -> String
encodeIdentifier

-- | Load executables from the given directories appended with @"/bin"@.
--
-- Useful for use with Nix.
loadFromBins :: [FilePath] -> Q [Dec]
loadFromBins :: [String] -> Q [Dec]
loadFromBins = [String] -> Q [Dec]
loadFromDirs forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String -> String -> String
</> String
"bin")

-- | Load executables from the given dirs, applying the given transformation
-- to the filenames.
loadAnnotatedFromDirs :: [FilePath] -> (String -> String) -> Q [Dec]
loadAnnotatedFromDirs :: [String] -> (String -> String) -> Q [Dec]
loadAnnotatedFromDirs [String]
ps String -> String
f = do
    [String]
bins <- forall a. IO a -> Q a
runIO forall a b. (a -> b) -> a -> b
$ [String] -> IO [String]
findBinsIn [String]
ps
    [[Dec]]
i <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [String]
bins forall a b. (a -> b) -> a -> b
$ \String
bin -> do
        String -> String -> Q [Dec]
rawExe (String -> String
f forall a b. (a -> b) -> a -> b
$ String -> String
takeFileName String
bin) String
bin
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Dec]]
i)

-- | Function that splits '\0' separated list of strings. Useful in conjunction
-- with @find . "-print0"@.
endBy0 :: ByteString -> [ByteString]
endBy0 :: ByteString -> [ByteString]
endBy0 = ByteString -> ByteString -> [ByteString]
endBy ByteString
"\0"

-- | Mimics the shell builtin "cd".
cd' :: FilePath -> IO ()
cd' :: String -> IO ()
cd' String
p = do
    String -> IO ()
Dir.setCurrentDirectory String
p
    String
a <- IO String
Dir.getCurrentDirectory
    String -> String -> IO ()
setEnv String
"PWD" String
a

-- | Helper class for variable number of arguments to @cd@ builtin.
class Cd a where
    -- | Mimics the shell builtin "cd". Be careful using this function
    -- in a program, as it doesn't play well with multiple threads. Best
    -- to just use it in an interactive shell or for very simple
    -- transliterations of shell scripts.
    cd :: a

instance (io ~ IO ()) => Cd io where
    cd :: io
cd = String -> IO String
getEnv String
"HOME" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ()
cd'

instance {-# OVERLAPS #-} (io ~ IO (), path ~ FilePath) => Cd (path -> io) where
    cd :: path -> io
cd = String -> IO ()
cd'

-- | @xargs1 n f@ runs @f@ for each item in the input separated by @n@. Similar
-- to the standard @xargs@ utility, but you get to choose the separator, and it
-- only does one argument per command. Compare the following two lines, which
-- do the same thing.
--
-- >>> printf "a\\0b" |> xargs "--null" "-L1" "echo" |> cat
-- a
-- b
-- >>> printf "a\\0b" |> xargs1 "\0" echo |> cat
-- a
-- b
--
-- One benefit of this method over the standard @xargs@ is that we can run
-- Haskell functions as well.
--
-- >>> yes |> head "-n" 5 |> xargs1 "\n" (const $ pure $ Sum 1)
-- Sum {getSum = 5}
xargs1 :: (NFData a, Monoid a) => ByteString -> (ByteString -> Proc a) -> Proc a
xargs1 :: forall a.
(NFData a, Monoid a) =>
ByteString -> (ByteString -> Proc a) -> Proc a
xargs1 ByteString
n ByteString -> Proc a
f = forall a (io :: * -> *).
(NFData a, Shell io) =>
ByteString -> ([ByteString] -> Proc a) -> io a
readInputEndByP ByteString
n (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Monoid a => [a] -> a
mconcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ByteString -> Proc a
f)

-- | Simple @`Proc`@ that reads its input and can react to the output by
-- calling other @`Proc`@'s which can write something to its stdout.
-- The internal @`Proc`@ is given @/dev/null@ as its input.
readInputP :: (NFData a, Shell io) => (ByteString -> Proc a) -> io a
readInputP :: forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> Proc a) -> io a
readInputP ByteString -> Proc a
f = forall (f :: * -> *) a.
(Shell f, NFData a) =>
(Handle -> Handle -> Handle -> IO a) -> f a
nativeProc forall a b. (a -> b) -> a -> b
$ \Handle
i Handle
o Handle
e -> do
    ByteString
s <- Handle -> IO ByteString
hGetContents Handle
i
    forall a. (Handle -> IO a) -> IO a
withNullInput forall a b. (a -> b) -> a -> b
$ \Handle
i' ->
        forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. Handle -> Handle -> Handle -> Proc a -> IO a
runProc' Handle
i' Handle
o Handle
e (ByteString -> Proc a
f ByteString
s)

-- | Like @`readInputP`@, but splits the input.
readInputEndByP :: (NFData a, Shell io) => ByteString -> ([ByteString] -> Proc a) -> io a
readInputEndByP :: forall a (io :: * -> *).
(NFData a, Shell io) =>
ByteString -> ([ByteString] -> Proc a) -> io a
readInputEndByP ByteString
s [ByteString] -> Proc a
f = forall a (io :: * -> *).
(NFData a, Shell io) =>
(ByteString -> Proc a) -> io a
readInputP ([ByteString] -> Proc a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> [ByteString]
endBy ByteString
s)

-- | Like @`readInputP`@, but splits the input on 0 bytes.
readInputEndBy0P :: (NFData a, Shell io) => ([ByteString] -> Proc a) -> io a
readInputEndBy0P :: forall a (io :: * -> *).
(NFData a, Shell io) =>
([ByteString] -> Proc a) -> io a
readInputEndBy0P = forall a (io :: * -> *).
(NFData a, Shell io) =>
ByteString -> ([ByteString] -> Proc a) -> io a
readInputEndByP ByteString
"\0"

-- | Like @`readInputP`@, but splits the input on new lines.
readInputLinesP :: (NFData a, Shell io) => ([ByteString] -> Proc a) -> io a
readInputLinesP :: forall a (io :: * -> *).
(NFData a, Shell io) =>
([ByteString] -> Proc a) -> io a
readInputLinesP = forall a (io :: * -> *).
(NFData a, Shell io) =>
ByteString -> ([ByteString] -> Proc a) -> io a
readInputEndByP ByteString
"\n"

-- | Create a null file handle.
withNullInput :: (Handle -> IO a) -> IO a
withNullInput :: forall a. (Handle -> IO a) -> IO a
withNullInput = forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withFile String
"/dev/null" IOMode
ReadMode

-- | Bracket a @`hDup`@
withDuplicate :: Handle -> (Handle -> IO a) -> IO a
withDuplicate :: forall a. Handle -> (Handle -> IO a) -> IO a
withDuplicate Handle
h = forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (Handle -> IO Handle
hDup Handle
h) Handle -> IO ()
hClose

-- | Bracket three @`hDup`@s
withDuplicates :: Handle -> Handle -> Handle -> (Handle -> Handle -> Handle -> IO a) -> IO a
withDuplicates :: forall a.
Handle
-> Handle -> Handle -> (Handle -> Handle -> Handle -> IO a) -> IO a
withDuplicates Handle
a Handle
b Handle
c Handle -> Handle -> Handle -> IO a
f =
    forall a. Handle -> (Handle -> IO a) -> IO a
withDuplicate Handle
a forall a b. (a -> b) -> a -> b
$ \Handle
a' -> forall a. Handle -> (Handle -> IO a) -> IO a
withDuplicate Handle
b forall a b. (a -> b) -> a -> b
$ \Handle
b' -> forall a. Handle -> (Handle -> IO a) -> IO a
withDuplicate Handle
c forall a b. (a -> b) -> a -> b
$ \Handle
c' -> Handle -> Handle -> Handle -> IO a
f Handle
a' Handle
b' Handle
c'

-- | Bracket two @`hDup`@s and provide a null input handle.
withDuplicateNullInput :: Handle -> Handle -> (Handle -> Handle -> Handle -> IO a) -> IO a
withDuplicateNullInput :: forall a.
Handle -> Handle -> (Handle -> Handle -> Handle -> IO a) -> IO a
withDuplicateNullInput Handle
a Handle
b Handle -> Handle -> Handle -> IO a
f = do
    forall a. (Handle -> IO a) -> IO a
withNullInput forall a b. (a -> b) -> a -> b
$ \Handle
i -> do
        forall a. Handle -> (Handle -> IO a) -> IO a
withDuplicate Handle
a forall a b. (a -> b) -> a -> b
$ \Handle
a' -> forall a. Handle -> (Handle -> IO a) -> IO a
withDuplicate Handle
b forall a b. (a -> b) -> a -> b
$ \Handle
b' -> Handle -> Handle -> Handle -> IO a
f Handle
i Handle
a' Handle
b'

-- | Duplicate a @`Handle`@ without trying to flush buffers. Only works on @`FileHandle`@s.
--
-- hDuplicate tries to "flush" read buffers by seeking backwards, which doesn't
-- work for streams/pipes. Since we are simulating a @fork + exec@ in @`nativeProc`@,
-- losing the buffers is actually the expected behaviour. (System.Process doesn't
-- attempt to flush the buffers).
--
-- NB: An alternate solution that we could implement (even for System.Process forks)
-- is to create a fresh pipe and spawn an async task to forward buffered content
-- from the original handle if there is something in the buffer. My concern would
-- be that it might be a performance hit that people aren't expecting.
--
-- Code basically copied from
-- http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.IO.Handle.html#hDuplicate
-- with minor modifications.
hDup :: Handle -> IO Handle
hDup :: Handle -> IO Handle
hDup h :: Handle
h@(FileHandle String
path MVar Handle__
m) = do
    forall a.
String -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' String
"hDup" Handle
h MVar Handle__
m forall a b. (a -> b) -> a -> b
$ \Handle__
h_ ->
        String
-> Handle
-> Maybe (MVar Handle__)
-> Handle__
-> Maybe HandleFinalizer
-> IO Handle
dupHandleShh String
path Handle
h forall a. Maybe a
Nothing Handle__
h_ (forall a. a -> Maybe a
Just HandleFinalizer
handleFinalizer)
hDup h :: Handle
h@(DuplexHandle String
path MVar Handle__
r MVar Handle__
w) = do
    (FileHandle String
_ MVar Handle__
write_m) <-
        forall a.
String -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' String
"hDup" Handle
h MVar Handle__
w forall a b. (a -> b) -> a -> b
$ \Handle__
h_ ->
            String
-> Handle
-> Maybe (MVar Handle__)
-> Handle__
-> Maybe HandleFinalizer
-> IO Handle
dupHandleShh String
path Handle
h forall a. Maybe a
Nothing Handle__
h_ (forall a. a -> Maybe a
Just HandleFinalizer
handleFinalizer)
    (FileHandle String
_ MVar Handle__
read_m) <-
        forall a.
String -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' String
"hDup" Handle
h MVar Handle__
r forall a b. (a -> b) -> a -> b
$ \Handle__
h_ ->
            String
-> Handle
-> Maybe (MVar Handle__)
-> Handle__
-> Maybe HandleFinalizer
-> IO Handle
dupHandleShh String
path Handle
h (forall a. a -> Maybe a
Just MVar Handle__
write_m) Handle__
h_  forall a. Maybe a
Nothing
    forall (m :: * -> *) a. Monad m => a -> m a
return (String -> MVar Handle__ -> MVar Handle__ -> Handle
DuplexHandle String
path MVar Handle__
read_m MVar Handle__
write_m)

-- | Helper function for duplicating a Handle
dupHandleShh
    :: FilePath
    -> Handle
    -> Maybe (MVar Handle__)
    -> Handle__
    -> Maybe HandleFinalizer
    -> IO Handle
dupHandleShh :: String
-> Handle
-> Maybe (MVar Handle__)
-> Handle__
-> Maybe HandleFinalizer
-> IO Handle
dupHandleShh String
filepath Handle
h Maybe (MVar Handle__)
other_side h_ :: Handle__
h_@Handle__{dev
Maybe TextEncoding
Maybe (TextEncoder enc_state)
Maybe (TextDecoder dec_state)
Maybe (MVar Handle__)
Newline
HandleType
BufferMode
IORef (dec_state, Buffer Word8)
IORef (BufferList Char)
IORef (Buffer Char)
IORef (Buffer Word8)
haBufferMode :: Handle__ -> BufferMode
haBuffers :: Handle__ -> IORef (BufferList Char)
haByteBuffer :: Handle__ -> IORef (Buffer Word8)
haCharBuffer :: Handle__ -> IORef (Buffer Char)
haCodec :: Handle__ -> Maybe TextEncoding
haDecoder :: ()
haDevice :: ()
haEncoder :: ()
haInputNL :: Handle__ -> Newline
haLastDecode :: ()
haOtherSide :: Handle__ -> Maybe (MVar Handle__)
haOutputNL :: Handle__ -> Newline
haType :: Handle__ -> HandleType
haOtherSide :: Maybe (MVar Handle__)
haOutputNL :: Newline
haInputNL :: Newline
haCodec :: Maybe TextEncoding
haDecoder :: Maybe (TextDecoder dec_state)
haEncoder :: Maybe (TextEncoder enc_state)
haBuffers :: IORef (BufferList Char)
haCharBuffer :: IORef (Buffer Char)
haLastDecode :: IORef (dec_state, Buffer Word8)
haBufferMode :: BufferMode
haByteBuffer :: IORef (Buffer Word8)
haType :: HandleType
haDevice :: dev
..} Maybe HandleFinalizer
mb_finalizer = do
    case Maybe (MVar Handle__)
other_side of
        Maybe (MVar Handle__)
Nothing -> do
            dev
new_dev <- forall a. IODevice a => a -> IO a
IODevice.dup dev
haDevice
            forall dev.
(RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> String
-> Maybe (MVar Handle__)
-> Handle__
-> Maybe HandleFinalizer
-> IO Handle
dupHandleShh_ dev
new_dev String
filepath Maybe (MVar Handle__)
other_side Handle__
h_ Maybe HandleFinalizer
mb_finalizer
        Just MVar Handle__
r  ->
            forall a.
String -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' String
"dupHandleShh" Handle
h MVar Handle__
r forall a b. (a -> b) -> a -> b
$ \Handle__{haDevice :: ()
haDevice=dev
dev} -> do
                forall dev.
(RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> String
-> Maybe (MVar Handle__)
-> Handle__
-> Maybe HandleFinalizer
-> IO Handle
dupHandleShh_ dev
dev String
filepath Maybe (MVar Handle__)
other_side Handle__
h_ Maybe HandleFinalizer
mb_finalizer

-- | Helper function for duplicating a Handle
dupHandleShh_
#if __GLASGOW_HASKELL__ < 900
    :: (IODevice dev, BufferedIO dev, Typeable dev) => dev
#else
    :: (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) => dev
#endif
    -> FilePath
    -> Maybe (MVar Handle__)
    -> Handle__
    -> Maybe HandleFinalizer
    -> IO Handle
dupHandleShh_ :: forall dev.
(RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> String
-> Maybe (MVar Handle__)
-> Handle__
-> Maybe HandleFinalizer
-> IO Handle
dupHandleShh_ dev
new_dev String
filepath Maybe (MVar Handle__)
other_side Handle__{dev
Maybe TextEncoding
Maybe (TextEncoder enc_state)
Maybe (TextDecoder dec_state)
Maybe (MVar Handle__)
Newline
HandleType
BufferMode
IORef (dec_state, Buffer Word8)
IORef (BufferList Char)
IORef (Buffer Char)
IORef (Buffer Word8)
haOtherSide :: Maybe (MVar Handle__)
haOutputNL :: Newline
haInputNL :: Newline
haCodec :: Maybe TextEncoding
haDecoder :: Maybe (TextDecoder dec_state)
haEncoder :: Maybe (TextEncoder enc_state)
haBuffers :: IORef (BufferList Char)
haCharBuffer :: IORef (Buffer Char)
haLastDecode :: IORef (dec_state, Buffer Word8)
haBufferMode :: BufferMode
haByteBuffer :: IORef (Buffer Word8)
haType :: HandleType
haDevice :: dev
haBufferMode :: Handle__ -> BufferMode
haBuffers :: Handle__ -> IORef (BufferList Char)
haByteBuffer :: Handle__ -> IORef (Buffer Word8)
haCharBuffer :: Handle__ -> IORef (Buffer Char)
haCodec :: Handle__ -> Maybe TextEncoding
haDecoder :: ()
haDevice :: ()
haEncoder :: ()
haInputNL :: Handle__ -> Newline
haLastDecode :: ()
haOtherSide :: Handle__ -> Maybe (MVar Handle__)
haOutputNL :: Handle__ -> Newline
haType :: Handle__ -> HandleType
..} Maybe HandleFinalizer
mb_finalizer = do
    -- XXX wrong!
    Maybe TextEncoding
mb_codec <- if forall a. Maybe a -> Bool
isJust Maybe (TextEncoder enc_state)
haEncoder then forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just IO TextEncoding
getLocaleEncoding else forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
    forall dev.
(RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> String
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
mkHandle dev
new_dev String
filepath HandleType
haType Bool
True{-buffered-} Maybe TextEncoding
mb_codec
        NewlineMode { inputNL :: Newline
inputNL = Newline
haInputNL, outputNL :: Newline
outputNL = Newline
haOutputNL }
        Maybe HandleFinalizer
mb_finalizer Maybe (MVar Handle__)
other_side