shh 0.1.0.0 → 0.1.0.1
raw patch · 6 files changed
+66/−47 lines, 6 files
Files
- ChangeLog.md +8/−1
- shh.cabal +2/−3
- src/Shh.hs +19/−12
- src/Shh/Example.hs +0/−7
- src/Shh/Internal.hs +35/−22
- test/Test.hs +2/−2
ChangeLog.md view
@@ -1,5 +1,12 @@ # Revision history for execpath -## 0.1.0.0 -- YYYY-mm-dd+## 0.1.0.1 -- 2019-01-22++* Force output of lazy read functions to normal form to prevent+ people from accidentally holding onto resources.++* New helper functions for reading.+ +## 0.1.0.0 -- 2018-11-02 * First version. Released on an unsuspecting world.
shh.cabal view
@@ -1,5 +1,5 @@ name: shh-version: 0.1.0.0+version: 0.1.0.1 synopsis: Simple shell scripting from Haskell description: Provides a shell scripting environment for Haskell. It helps you all external binaries, and allows you to@@ -21,9 +21,8 @@ library exposed-modules: Shh- , Shh.Example , Shh.Internal- build-depends: base >=4.9 && <4.12+ build-depends: base >=4.9 && <4.13 , async , deepseq , directory
src/Shh.hs view
@@ -1,11 +1,3 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE GADTs #-} -- | Shh provides a shell-like environment for Haskell. module Shh ( initInteractive@@ -22,19 +14,34 @@ , Stream(..) , devNull -- | == Reading @stdout@- , readProc+ -- === Lazy/Streaming reads+ -- These reads are lazy. The process is run long enough to produce+ -- the amount of output that is actually used. It is therefor suitable+ -- for use with infinite output streams. The process is terminated+ -- as soon the function finishes. Note that the result is forced to+ -- normal form to prevent any accidental reading after the process has+ -- terminated. , withRead- , trim+ , withReadSplit0+ , withReadLines+ , withReadWords+ -- | === Strict reads+ , readProc , readTrim- , split0 , readSplit0 , readLines+ , readWords , readAuto+ -- | === String manipulation+ -- Utility functions for dealing with common string issues in shell+ -- scripting.+ , trim+ , split0 -- | == Writing to @stdin@ , writeProc , (<<<), (>>>) , readWriteProc- , mapP+ , apply -- | == Exceptions -- If any exception is allowed to propagate out of a pipeline, all the -- processes comprising the pipeline will be terminated. This is contrary
− src/Shh/Example.hs
@@ -1,7 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Shh.Example where--import Shh--$(loadAnnotatedEnv (\s -> s ++ "_"))
src/Shh/Internal.hs view
@@ -12,7 +12,7 @@ import Control.Concurrent.Async-import Control.DeepSeq (rnf)+import Control.DeepSeq (rnf,force,NFData) import Control.Exception as C import Control.Monad import Control.Monad.IO.Class@@ -217,27 +217,34 @@ -- This is strict, so the whole output is read into a `String`. See `withRead` -- for a lazy version that can be used for streaming. readProc :: MonadIO io => Proc a -> io String-readProc (Proc f) = liftIO $ do- (r,w) <- createPipe- (_,o) <- concurrently- (f stdin w stderr (pure ()) (hClose w))- (do- output <- hGetContents r- C.evaluate $ rnf output- hClose r- pure output- )- pure o+readProc p = withRead p pure -- | Run a process and capture it's output lazily. Once the continuation -- is completed, the handles are closed, and the process is terminated.-withRead :: MonadIO io => Proc a -> (String -> IO b) -> io b+withRead :: (NFData b, MonadIO io) => Proc a -> (String -> IO b) -> io b withRead (Proc f) k = liftIO $ withPipe $ \r w -> do withAsync (f stdin w stderr (pure ()) (hClose w)) $ \_ ->- (hGetContents r >>= k) `finally` hClose r+ (hGetContents r >>= k >>= C.evaluate . force) `finally` hClose r +-- | Apply a transformation function to the string before the IO action.+withRead' :: (NFData b, MonadIO io) => (String -> a) -> Proc x -> (a -> IO b) -> io b+withRead' f p io = withRead p (io . f) +-- | Like @'withRead'@ except it splits the string with @'split0'@ first.+withReadSplit0 :: (NFData b, MonadIO io) => Proc a -> ([String] -> IO b) -> io b+withReadSplit0 = withRead' split0++-- | Like @'withRead'@ except it splits the string with @'lines'@ first.+--+-- NB: Please consider using @'withReadSplit0'@ where you can.+withReadLines :: (NFData b, MonadIO io) => Proc a -> ([String] -> IO b) -> io b+withReadLines = withRead' lines++-- | Like @'withRead'@ except it splits the string with @'words'@ first.+withReadWords :: (NFData b, MonadIO io) => Proc a -> ([String] -> IO b) -> io b+withReadWords = withRead' words+ -- | Read and write to a `Proc`... readWriteProc :: MonadIO io => Proc a -> String -> io String readWriteProc (Proc f) input = liftIO $ do@@ -255,12 +262,12 @@ ) pure o --- | Some as `readWriteProc`. Map a `Proc` over a `String`.+-- | Some as `readWriteProc`. Apply a `Proc` to a `String`. ----- >>> mapP shasum "Hello"+-- >>> apply shasum "Hello" -- "f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0 -\n"-mapP :: MonadIO io => Proc a -> String -> io String-mapP = readWriteProc+apply :: MonadIO io => Proc a -> String -> io String+apply = readWriteProc -- | Provide the stdin of a `Proc` from a `String` writeProc :: MonadIO io => Proc a -> String -> io a@@ -328,7 +335,6 @@ readTrim :: MonadIO io => Proc a -> io String readTrim = fmap trim . readProc - -- | A class for things that can be converted to arguments on the command -- line. The default implementation is to use `show`. class ExecArg a where@@ -440,7 +446,8 @@ | validIdentifier (f s) = Just (f s, s) | otherwise = Nothing --- | Function that splits '\0' seperated list of strings.+-- | Function that splits '\0' seperated list of strings. Useful in conjuction+-- with @find . "-print0"@. split0 :: String -> [String] split0 = endBy "\0" @@ -449,11 +456,17 @@ -- -- > readSplit0 $ find "-print0" readSplit0 :: Proc () -> IO [String]-readSplit0 p = split0 <$> readProc p+readSplit0 p = withReadSplit0 p pure -- | A convinience function for reading the output lines of a `Proc`.+--+-- Note: Please consider using @'readSplit0'@ instead if you can. readLines :: Proc () -> IO [String]-readLines p = lines <$> readProc p+readLines p = withReadLines p pure++-- | Read output into a list of words+readWords :: Proc () -> IO [String]+readWords p = withReadWords p pure -- | Like `readProc`, but attempts to `Prelude.read` the result. readAuto :: Read a => Proc () -> IO a
test/Test.hs view
@@ -70,8 +70,8 @@ writeProc (cat &> Truncate t) "Goodbye" r <- readProc (cat t) r @?= "Goodbye"- , testCase "mapP" $ do- r <- mapP shasum "test"+ , testCase "apply" $ do+ r <- apply shasum "test" r @?= "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 -\n" , testCase "ignoreFailure" $ do r <- readProc $ ignoreFailure false |> echo "Hello"