packages feed

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 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,