process-listlike 0.6.2 → 0.7
raw patch · 9 files changed
+411/−243 lines, 9 filesdep +deepseqdep ~basedep ~processsetup-changed
Dependencies added: deepseq
Dependency ranges changed: base, process
Files
- Setup.hs +1/−1
- System/Process/Read.hs +8/−2
- System/Process/Read/Chars.hs +0/−190
- System/Process/Read/Chunks.hs +19/−0
- System/Process/Read/Instances.hs +0/−43
- System/Process/Read/Interleaved.hs +117/−0
- System/Process/Read/ListLike.hs +247/−0
- changelog +8/−0
- process-listlike.cabal +11/−7
Setup.hs view
@@ -1,9 +1,9 @@ import Distribution.Simple import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(buildDir)) import Distribution.Simple.Program-import System.Cmd import System.Directory import System.Exit+import System.Process main = copyFile "debian/changelog" "changelog" >> defaultMainWithHooks simpleUserHooks {
System/Process/Read.hs view
@@ -4,7 +4,13 @@ , readCreateProcess , readProcessWithExitCode , readProcess+ , Chunked(..)+ , readProcessInterleaved+ , readInterleaved+ , Output(..)+ , readProcessChunks ) where -import System.Process.Read.Chars-import System.Process.Read.Instances ()+import System.Process.Read.Chunks+import System.Process.Read.ListLike+import System.Process.Read.Interleaved
− System/Process/Read/Chars.hs
@@ -1,190 +0,0 @@--- | Versions of the functions in module 'System.Process.Read' specialized for type ByteString.-{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies #-}-module System.Process.Read.Chars (- ListLikePlus(..),- readCreateProcessWithExitCode,- readCreateProcess,- readProcessWithExitCode,- readProcess,- ) where--import Control.Concurrent-import Control.Exception as E (SomeException, onException, evaluate, catch, try, throwIO, mask)-import Control.Monad-import Data.ListLike (ListLike(..), ListLikeIO(..))-import Data.ListLike.Text.Text ()-import Data.ListLike.Text.TextLazy ()-import GHC.IO.Exception (IOErrorType(OtherError, ResourceVanished), IOException(ioe_type))-import Prelude hiding (null, length)-import System.Exit (ExitCode(ExitSuccess, ExitFailure))-import System.IO hiding (hPutStr, hGetContents)-import qualified System.IO.Error as IO-import System.Process (CreateProcess(..), StdStream(CreatePipe, Inherit), proc,- CmdSpec(RawCommand, ShellCommand), showCommandForUser,- createProcess, waitForProcess, terminateProcess)---- | Class of types which can be used as the input and outputs of the process functions.-class (Integral (LengthType a), ListLikeIO a c) => ListLikePlus a c where- type LengthType a- binary :: a -> [Handle] -> IO ()- -- ^ This should call 'hSetBinaryMode' on each handle if a is a- -- ByteString type, so that it doesn't attempt to decode the text- -- using the current locale.- lazy :: a -> Bool- length' :: a -> LengthType a---- | A polymorphic implementation of--- 'System.Process.readProcessWithExitCode' with a few--- generalizations:------ 1. The input and outputs can be any instance of 'ListLikePlus'.------ 2. Allows you to modify the 'CreateProcess' record before the process starts------ 3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.-readCreateProcessWithExitCode- :: forall a c.- ListLikePlus a c =>- CreateProcess -- ^ process to run- -> a -- ^ standard input- -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr, exception-readCreateProcessWithExitCode p input = mask $ \restore -> do- (Just inh, Just outh, Just errh, pid) <-- createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe })-- flip onException- (do hClose inh; hClose outh; hClose errh;- terminateProcess pid; waitForProcess pid) $ restore $ do- (out, err) <- (if lazy input then readLazy else readStrict) inh outh errh-- hClose outh- hClose errh-- -- wait on the process- ex <- waitForProcess pid-- return (ex, out, err)- where- readLazy :: Handle -> Handle -> Handle -> IO (a, a)- readLazy inh outh errh =- do out <- hGetContents outh- waitOut <- forkWait $ void $ force $ out- err <- hGetContents errh- waitErr <- forkWait $ void $ force $ err- -- now write and flush any input- writeInput inh- -- wait on the output- waitOut- waitErr- return (out, err)-- readStrict :: Handle -> Handle -> Handle -> IO (a, a)- readStrict inh outh errh =- do -- fork off a thread to start consuming stdout- waitOut <- forkWait $ hGetContents outh- -- fork off a thread to start consuming stderr- waitErr <- forkWait $ hGetContents errh- -- now write and flush any input- writeInput inh- -- wait on the output- out <- waitOut- err <- waitErr- return (out, err)-- writeInput :: Handle -> IO ()- writeInput inh = do- (do unless (null input) (hPutStr inh input >> hFlush inh)- hClose inh) `E.catch` resourceVanished (\ _ -> return ())---- | A polymorphic implementation of--- 'System.Process.readProcessWithExitCode' in terms of--- 'readCreateProcessWithExitCode'.-readProcessWithExitCode- :: ListLikePlus a c =>- FilePath -- ^ command to run- -> [String] -- ^ any arguments- -> a -- ^ standard input- -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input---- | Implementation of 'System.Process.readProcess' in terms of--- 'readCreateProcess'.-readProcess- :: ListLikePlus a c =>- FilePath -- ^ command to run- -> [String] -- ^ any arguments- -> a -- ^ standard input- -> IO a -- ^ stdout-readProcess cmd args = readCreateProcess (proc cmd args)---- | A polymorphic implementation of 'System.Process.readProcess' with a few generalizations:------ 1. The input and outputs can be any instance of 'ListLikePlus'.------ 2. Allows you to modify the 'CreateProcess' record before the process starts------ 3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.-readCreateProcess- :: ListLikePlus a c =>- CreateProcess -- ^ process to run- -> a -- ^ standard input- -> IO a -- ^ stdout-readCreateProcess p input = mask $ \restore -> do- (Just inh, Just outh, _, pid) <-- createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit })-- flip onException- (do hClose inh; hClose outh;- terminateProcess pid; waitForProcess pid) $ restore $ do- out <- (if lazy input then readLazy else readStrict) inh outh-- hClose outh-- -- wait on the process- ex <- waitForProcess pid-- case ex of- ExitSuccess -> return out- ExitFailure r -> ioError (mkError "readCreateProcess: " (cmdspec p) r)- where- readLazy inh outh =- do -- fork off a thread to start consuming stdout- out <- hGetContents outh- waitOut <- forkWait $ void $ force $ out- writeInput inh- waitOut- return out-- readStrict inh outh =- do waitOut <- forkWait $ hGetContents outh- writeInput inh- waitOut-- writeInput inh = do- (do unless (null input) (hPutStr inh input >> hFlush inh)- hClose inh) `E.catch` resourceVanished (\ _ -> return ())--forkWait :: IO a -> IO (IO a)-forkWait a = do- res <- newEmptyMVar- _ <- mask $ \restore -> forkIO $ try (restore a) >>= putMVar res- return (takeMVar res >>= either (\ex -> throwIO (ex :: SomeException)) return)---- | Wrapper for a process that provides a handler for the--- ResourceVanished exception. This is frequently an exception we--- wish to ignore, because many processes will deliberately exit--- before they have read all of their input.-resourceVanished :: (IOError -> IO a) -> IOError -> IO a-resourceVanished epipe e = if ioe_type e == ResourceVanished then epipe e else ioError e---- | Create an exception for a process that exited abnormally.-mkError :: String -> CmdSpec -> Int -> IOError-mkError prefix (RawCommand cmd args) r =- IO.mkIOError OtherError (prefix ++ showCommandForUser cmd args ++ " (exit " ++ show r ++ ")")- Nothing Nothing-mkError prefix (ShellCommand cmd) r =- IO.mkIOError OtherError (prefix ++ cmd ++ " (exit " ++ show r ++ ")")- Nothing Nothing--force :: forall a c. ListLikePlus a c => a -> IO (LengthType a)-force x = evaluate $ length' $ x
+ System/Process/Read/Chunks.hs view
@@ -0,0 +1,19 @@+module System.Process.Read.Chunks+ ( Output(..)+ , readProcessChunks+ ) where++import Control.DeepSeq (NFData)+import System.Exit (ExitCode)+import System.Process (CreateProcess)+import System.Process.Read.Interleaved++-- | This lets us use deepseq's force on the stream of data returned+-- by readProcessChunks.+instance NFData ExitCode++data Output a = Stdout a | Stderr a | Result ExitCode | Exception IOError deriving (Eq, Show)++readProcessChunks :: (Chunked a c) => CreateProcess -> a -> IO [Output a]+readProcessChunks p input =+ readProcessInterleaved (\ x -> [Result x]) (\ x -> [Stdout x]) (\ x -> [Stderr x]) p input
− System/Process/Read/Instances.hs
@@ -1,43 +0,0 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeSynonymInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module System.Process.Read.Instances where--import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as L-import Data.Int (Int64)-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import Data.Word (Word8)-import Prelude hiding (catch)-import System.IO (hSetBinaryMode)-import System.Process.Read.Chars (ListLikePlus(..))--instance ListLikePlus String Char where- type LengthType String = Int- binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles (because internally this uses lazy bytestrings)- lazy _ = True- length' = length--instance ListLikePlus B.ByteString Word8 where- type LengthType B.ByteString = Int- binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles- lazy _ = False- length' = B.length--instance ListLikePlus L.ByteString Word8 where- type LengthType L.ByteString = Int64- binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles- lazy _ = True- length' = L.length--instance ListLikePlus T.Text Char where- type LengthType T.Text = Int- binary _ _ = return ()- lazy _ = False- length' = T.length--instance ListLikePlus LT.Text Char where- type LengthType LT.Text = Int64- binary _ _ = return ()- lazy _ = True- length' = LT.length
+ System/Process/Read/Interleaved.hs view
@@ -0,0 +1,117 @@+-- | Read the output of several file descriptors concurrently,+-- preserving the order in which the chunks are read.+{-# LANGUAGE CPP, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeSynonymInstances #-}+{-# OPTIONS_GHC -Wall #-}+module System.Process.Read.Interleaved+ ( Chunked(..)+ , readProcessInterleaved+ , readInterleaved+ ) where++import Control.Concurrent (forkIO, MVar, newEmptyMVar, putMVar, takeMVar)+import Control.Exception as E (onException, catch, mask, try, throwIO, SomeException)+import Control.Monad (unless)+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Lazy as ByteString.Lazy+import Data.List as List (map)+import Data.ListLike (ListLike(..), ListLikeIO(..))+import Data.Monoid (Monoid, (<>))+import Data.Text (Text)+import qualified Data.Text.Lazy as Text.Lazy (Text, toChunks, fromChunks)+import Data.Word (Word8)+import GHC.IO.Exception (IOErrorType(ResourceVanished), IOException(ioe_type))+import Prelude hiding (null, length, rem)+import System.Exit (ExitCode)+import System.IO hiding (hPutStr, hGetContents)+import System.IO.Unsafe (unsafeInterleaveIO)+import System.Process (CreateProcess(..), StdStream(CreatePipe),+ createProcess, waitForProcess, terminateProcess)+import System.Process.Read.ListLike (ListLikePlus(..))++-- | Class of types which can also be used by 'System.Process.Read.readProcessChunks'.+class ListLikePlus a c => Chunked a c where+ toChunks :: a -> [a]++instance Chunked ByteString.Lazy.ByteString Word8 where+ toChunks = List.map (ByteString.Lazy.fromChunks . (: [])) . ByteString.Lazy.toChunks++-- I have to assume that this is not prone to utf8 decode errors.+-- When I was converting lazy ByteStrings to Text I sometimes got+-- such errors when a chunk ended in the middle of a unicode char.+instance Chunked Text.Lazy.Text Char where+ toChunks = List.map (Text.Lazy.fromChunks . (: [])) . Text.Lazy.toChunks++-- Note that the instances that use @toChunks = (: [])@ put everything+-- into a single chunk - lazy reading won't work with these types.+instance Chunked ByteString.ByteString Word8 where+ toChunks = (: [])++instance Chunked String Char where+ toChunks = (: [])++instance Chunked Data.Text.Text Char where+ toChunks = (: [])++-- | A test version of readProcessC+-- Pipes code here: http://hpaste.org/76631+readProcessInterleaved :: (Chunked a c, Monoid b) =>+ (ExitCode -> b) -> (a -> b) -> (a -> b)+ -> CreateProcess -> a -> IO b+readProcessInterleaved codef outf errf p input = mask $ \ restore -> do+ (Just inh, Just outh, Just errh, pid) <-+ createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe })++ binary input [inh, outh, errh]++ flip onException+ (do hClose inh; hClose outh; hClose errh;+ terminateProcess pid; waitForProcess pid) $ restore $ do++ waitOut <- forkWait $ readInterleaved [(outf, outh), (errf, errh)] $ waitForProcess pid >>= return . codef++ -- now write and flush any input+ (do unless (null input) (hPutStr inh input >> hFlush inh)+ hClose inh) `catch` resourceVanished (\ _e -> return ())++ -- wait on the output+ waitOut++-- | Simultaneously read the output from all the handles, using the+-- associated functions to add them to the Monoid b in the order they+-- appear. Close each handle on EOF (even though they were open when+-- we received them.)+readInterleaved :: forall a b c. (Chunked a c, Monoid b) => [(a -> b, Handle)] -> IO b -> IO b+readInterleaved pairs finish = newEmptyMVar >>= readInterleaved' pairs finish++readInterleaved' :: forall a b c. (Chunked a c, Monoid b) =>+ [(a -> b, Handle)] -> IO b -> MVar (Either Handle b) -> IO b+readInterleaved' pairs finish res = do+ mapM_ (forkIO . uncurry readHandle) pairs+ takeChunks (length pairs)+ where+ readHandle f h = do+ cs <- hGetContents h+ mapM_ (\ c -> putMVar res (Right (f c))) (toChunks cs)+ hClose h+ putMVar res (Left h)+ takeChunks :: Int -> IO b+ takeChunks 0 = finish+ takeChunks openCount = takeMVar res >>= takeChunk openCount+ takeChunk :: Int -> Either Handle b -> IO b+ takeChunk openCount (Left h) = hClose h >> takeChunks (openCount - 1)+ takeChunk openCount (Right x) =+ do xs <- unsafeInterleaveIO $ takeChunks openCount+ return (x <> xs)++forkWait :: IO a -> IO (IO a)+forkWait a = do+ res <- newEmptyMVar+ _ <- mask $ \restore -> forkIO $ try (restore a) >>= putMVar res+ return (takeMVar res >>= either (\ex -> throwIO (ex :: SomeException)) return)++-- | Wrapper for a process that provides a handler for the+-- ResourceVanished exception. This is frequently an exception we+-- wish to ignore, because many processes will deliberately exit+-- before they have read all of their input.+resourceVanished :: (IOError -> IO a) -> IOError -> IO a+resourceVanished epipe e = if ioe_type e == ResourceVanished then epipe e else ioError e
+ System/Process/Read/ListLike.hs view
@@ -0,0 +1,247 @@+-- | Versions of the functions in module 'System.Process.Read' specialized for type ByteString.+{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies #-}+module System.Process.Read.ListLike (+ ListLikePlus(..),+ readCreateProcessWithExitCode,+ readCreateProcess,+ readProcessWithExitCode,+ readProcess,+ ) where++import Control.Concurrent+import Control.Exception as E (SomeException, onException, evaluate, catch, try, throwIO, mask)+import Control.Monad+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import Data.Int (Int64)+import Data.ListLike (ListLike(..), ListLikeIO(..))+import Data.ListLike.Text.Text ()+import Data.ListLike.Text.TextLazy ()+import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import Data.Word (Word8)+import GHC.IO.Exception (IOErrorType(OtherError, ResourceVanished), IOException(ioe_type))+import Prelude hiding (null, length)+import System.Exit (ExitCode(ExitSuccess, ExitFailure))+import System.IO hiding (hPutStr, hGetContents)+import qualified System.IO.Error as IO+import System.Process (CreateProcess(..), StdStream(CreatePipe, Inherit), proc,+ CmdSpec(RawCommand, ShellCommand), showCommandForUser,+ createProcess, waitForProcess, terminateProcess)++-- | Class of types which can be used as the input and outputs of the process functions.+class (Integral (LengthType a), ListLikeIO a c) => ListLikePlus a c where+ type LengthType a+ binary :: a -> [Handle] -> IO ()+ -- ^ This should call 'hSetBinaryMode' on each handle if a is a+ -- ByteString type, so that it doesn't attempt to decode the text+ -- using the current locale.+ lazy :: a -> Bool+ length' :: a -> LengthType a++-- | A polymorphic implementation of+-- 'System.Process.readProcessWithExitCode' with a few+-- generalizations:+--+-- 1. The input and outputs can be any instance of 'ListLikePlus'.+--+-- 2. Allows you to modify the 'CreateProcess' record before the process starts+--+-- 3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.+readCreateProcessWithExitCode+ :: forall a c.+ ListLikePlus a c =>+ CreateProcess -- ^ process to run+ -> a -- ^ standard input+ -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr, exception+#if 1+readCreateProcessWithExitCode p input =+ readProcessInterleaved p input (\ a -> (a, mempty, mempty))+ (\ a -> (mempty, a, mempty))+ (\ code -> (mempty, mempty, code))++instance forall a c. ListLikePlus a c => Monoid (a, a, ExitCode) where+ mempty = (mempty, mempty, ExitFailure 0)+ mappend (a, b, c) (d, e, f) = (mappend a d, mappend b e, mappend c f)++instance Monoid ExitCode where+ mempty = ExitFailure 0 -- A hack, but this should not occur.+ mappend x (ExitFailure 0) = x+ mappend _ x = x++#else+readCreateProcessWithExitCode p input = mask $ \restore -> do+ (Just inh, Just outh, Just errh, pid) <-+ createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe })++ flip onException+ (do hClose inh; hClose outh; hClose errh;+ terminateProcess pid; waitForProcess pid) $ restore $ do+ (out, err) <- (if lazy input then readLazy else readStrict) inh outh errh++ hClose outh+ hClose errh++ -- wait on the process+ ex <- waitForProcess pid++ return (ex, out, err)+ where+ readLazy :: Handle -> Handle -> Handle -> IO (a, a)+ readLazy inh outh errh =+ do out <- hGetContents outh+ waitOut <- forkWait $ void $ force $ out+ err <- hGetContents errh+ waitErr <- forkWait $ void $ force $ err+ -- now write and flush any input+ writeInput inh+ -- wait on the output+ waitOut+ waitErr+ return (out, err)++ readStrict :: Handle -> Handle -> Handle -> IO (a, a)+ readStrict inh outh errh =+ do -- fork off a thread to start consuming stdout+ waitOut <- forkWait $ hGetContents outh+ -- fork off a thread to start consuming stderr+ waitErr <- forkWait $ hGetContents errh+ -- now write and flush any input+ writeInput inh+ -- wait on the output+ out <- waitOut+ err <- waitErr+ return (out, err)++ writeInput :: Handle -> IO ()+ writeInput inh = do+ (do unless (null input) (hPutStr inh input >> hFlush inh)+ hClose inh) `E.catch` resourceVanished (\ _ -> return ())+#endif++-- | A polymorphic implementation of+-- 'System.Process.readProcessWithExitCode' in terms of+-- 'readCreateProcessWithExitCode'.+readProcessWithExitCode+ :: ListLikePlus a c =>+ FilePath -- ^ command to run+ -> [String] -- ^ any arguments+ -> a -- ^ standard input+ -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr+readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input++-- | Implementation of 'System.Process.readProcess' in terms of+-- 'readCreateProcess'.+readProcess+ :: ListLikePlus a c =>+ FilePath -- ^ command to run+ -> [String] -- ^ any arguments+ -> a -- ^ standard input+ -> IO a -- ^ stdout+readProcess cmd args = readCreateProcess (proc cmd args)++-- | A polymorphic implementation of 'System.Process.readProcess' with a few generalizations:+--+-- 1. The input and outputs can be any instance of 'ListLikePlus'.+--+-- 2. Allows you to modify the 'CreateProcess' record before the process starts+--+-- 3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.+readCreateProcess+ :: ListLikePlus a c =>+ CreateProcess -- ^ process to run+ -> a -- ^ standard input+ -> IO a -- ^ stdout+#if 0+readCreateProcess p input = readProcessInterleaved (\ x -> x) (\ _ -> mempty) (\ _ -> mempty) p input+#else+readCreateProcess p input = mask $ \restore -> do+ (Just inh, Just outh, _, pid) <-+ createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit })++ flip onException+ (do hClose inh; hClose outh;+ terminateProcess pid; waitForProcess pid) $ restore $ do+ out <- (if lazy input then readLazy else readStrict) inh outh++ hClose outh++ -- wait on the process+ ex <- waitForProcess pid++ case ex of+ ExitSuccess -> return out+ ExitFailure r -> ioError (mkError "readCreateProcess: " (cmdspec p) r)+ where+ readLazy inh outh =+ do -- fork off a thread to start consuming stdout+ out <- hGetContents outh+ waitOut <- forkWait $ void $ force $ out+ writeInput inh+ waitOut+ return out++ readStrict inh outh =+ do waitOut <- forkWait $ hGetContents outh+ writeInput inh+ waitOut++ writeInput inh = do+ (do unless (null input) (hPutStr inh input >> hFlush inh)+ hClose inh) `E.catch` resourceVanished (\ _ -> return ())+#endif++forkWait :: IO a -> IO (IO a)+forkWait a = do+ res <- newEmptyMVar+ _ <- mask $ \restore -> forkIO $ try (restore a) >>= putMVar res+ return (takeMVar res >>= either (\ex -> throwIO (ex :: SomeException)) return)++-- | Wrapper for a process that provides a handler for the+-- ResourceVanished exception. This is frequently an exception we+-- wish to ignore, because many processes will deliberately exit+-- before they have read all of their input.+resourceVanished :: (IOError -> IO a) -> IOError -> IO a+resourceVanished epipe e = if ioe_type e == ResourceVanished then epipe e else ioError e++-- | Create an exception for a process that exited abnormally.+mkError :: String -> CmdSpec -> Int -> IOError+mkError prefix (RawCommand cmd args) r =+ IO.mkIOError OtherError (prefix ++ showCommandForUser cmd args ++ " (exit " ++ show r ++ ")")+ Nothing Nothing+mkError prefix (ShellCommand cmd) r =+ IO.mkIOError OtherError (prefix ++ cmd ++ " (exit " ++ show r ++ ")")+ Nothing Nothing++force :: forall a c. ListLikePlus a c => a -> IO (LengthType a)+force x = evaluate $ length' $ x++instance ListLikePlus String Char where+ type LengthType String = Int+ binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles (because internally this uses lazy bytestrings)+ lazy _ = True+ length' = length++instance ListLikePlus B.ByteString Word8 where+ type LengthType B.ByteString = Int+ binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles+ lazy _ = False+ length' = B.length++instance ListLikePlus L.ByteString Word8 where+ type LengthType L.ByteString = Int64+ binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles+ lazy _ = True+ length' = L.length++instance ListLikePlus T.Text Char where+ type LengthType T.Text = Int+ binary _ _ = return ()+ lazy _ = False+ length' = T.length++instance ListLikePlus LT.Text Char where+ type LengthType LT.Text = Int64+ binary _ _ = return ()+ lazy _ = True+ length' = LT.length
changelog view
@@ -1,3 +1,11 @@+haskell-process-listlike (0.7) unstable; urgency=low++ * Add module System.Process.Read.Interleaved (from process-progress)+ * Add module System.Process.Read.Chunks (from process-progress)+ * Rename module System.Process.Read.Chars -> System.Process.Read.ListLike++ -- David Fox <dsf@seereason.com> Tue, 26 Aug 2014 11:16:13 -0700+ haskell-process-listlike (0.6.2) unstable; urgency=low * Make changelog visible in hackage.
process-listlike.cabal view
@@ -1,8 +1,10 @@ Name: process-listlike-Version: 0.6.2+Version: 0.7 Synopsis: Enhanced version of process-extras-Description: Extra functionality for the Process library- <http://hackage.haskell.org/package/process>.+Description: Extra functionality for the Process library <http://hackage.haskell.org/package/process>.+ This is a drop-in replacement for <http://hackage.haskell.org/package/process-extras>,+ which adds support for creating processes from a CreateProcess, more access to the+ internals, and completes support for the String type. Homepage: http://src.seereason.com/process-listlike License: MIT License-file: LICENSE@@ -15,15 +17,16 @@ source-repository head Type: darcs- Location: http://src.seereason.com/process-extras+ Location: https://github.com/ddssff/process-listlike.git Library ghc-options: -Wall -O2 Exposed-modules: System.Process.Read- System.Process.Read.Chars- System.Process.Read.Instances+ System.Process.Read.Chunks+ System.Process.Read.Interleaved+ System.Process.Read.ListLike System.Process.ByteString System.Process.ByteString.Lazy System.Process.String@@ -32,8 +35,8 @@ Build-depends: base >= 4 && < 5,- process, bytestring,+ deepseq, HUnit, ListLike >= 4.0, process,@@ -46,6 +49,7 @@ Build-Depends: base >= 4 && < 5, bytestring,+ deepseq, HUnit, ListLike, process,