packages feed

streamly-process 0.4.0 → 0.4.1

raw patch · 5 files changed

+75/−62 lines, 5 filesdep ~QuickCheckdep ~tasty-benchdep ~unix

Dependency ranges changed: QuickCheck, tasty-bench, unix

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Changelog +## 0.4.1 (Apr 2026)++* Rename quotedWord to shellWord+ ## 0.4.0 (Sep 2025)  * Remove buffering from the pipe chunked APIs.
src/Streamly/Internal/System/Command.hs view
@@ -35,11 +35,14 @@     , foreground     , daemon -    -- * Helpers-    , quotedWord+    -- * Low-level Functions+    , shellWord     , runWith     , streamWith     , pipeWith++    -- * Deprecated+    , quotedWord     ) where @@ -63,8 +66,11 @@  #include "DocTestCommand.hs" --- | Posix compliant quote escaping:+-- | Posix compliant quoted shell command string parsing with escaping: --+-- Quotes and escapes are parsed as in a standard POSIX shell.+-- Examples (using shell @echo@ command):+-- -- $ echo 'hello\\"world' -- hello\\"world --@@ -73,9 +79,9 @@ -- -- $ echo 'hello\' -- hello\-{-# INLINE quotedWord #-}-quotedWord :: MonadCatch m => Parser Char m String-quotedWord =+{-# INLINE shellWord #-}+shellWord :: MonadCatch m => Parser Char m String+shellWord =     let toRQuote x =             case x of                 '"' -> Just x@@ -92,6 +98,11 @@         trEsc _ _ = Nothing      in Parser.wordWithQuotes False trEsc '\\' toRQuote isSpace Fold.toList +{-# DEPRECATED quotedWord "Use shellWord instead." #-}+{-# INLINE quotedWord #-}+quotedWord :: MonadCatch m => Parser Char m String+quotedWord = shellWord+ -- | A modifier for stream generation APIs in "Streamly.System.Process" to -- generate streams from command strings. --@@ -110,7 +121,7 @@     Stream.concatEffect $ do         xs <- Stream.fold Fold.toList                 $ Stream.catRights-                $ Stream.parseMany quotedWord+                $ Stream.parseMany shellWord                 $ Stream.fromList cmd         case xs of             y:ys -> return $ f y ys@@ -133,7 +144,7 @@ runWith f cmd = do     xs <- Stream.fold Fold.toList             $ Stream.catRights-            $ Stream.parseMany quotedWord+            $ Stream.parseMany shellWord             $ Stream.fromList cmd     case xs of         y:ys -> f y ys@@ -161,7 +172,7 @@     Stream.concatEffect $ do         xs <- Stream.fold Fold.toList                 $ Stream.catRights-                $ Stream.parseMany quotedWord+                $ Stream.parseMany shellWord                 $ Stream.fromList cmd         case xs of             y:ys -> return $ f y ys input
src/Streamly/System/Command.hs view
@@ -38,10 +38,9 @@ -- With the "Streamly.System.Command" module you can write the examples in the -- "Streamly.System.Process" module more conveniently. ----- = Executables as functions+-- = Executables as Functions ----- The shell command @echo "hello world" | tr [a-z] [A-Z]@ can be written as--- follows using this module:+-- The shell command @echo "hello world" | tr [a-z] [A-Z]@ can be expressed as: -- -- >>> :{ --    Command.toBytes [str|echo "hello world"|]@@ -50,12 +49,17 @@ --  :} --  HELLO WORLD ----- = Shell commands as functions+-- In the example above, system commands are run as independent processes and+-- composed directly in Haskell, without invoking a shell. This offers a+-- powerful, type-safe, and efficient alternative to shell scripting, using+-- Streamly’s streaming APIs for composition. ----- We recommend using streamly to compose commands natively in Haskell rather--- than using the shell as shown in the previous example. However, if for some--- reason you want to execute commands using the shell:+-- = Shell Commands as Functions --+-- Prefer running commands directly and composing their output in Haskell (see+-- previous example) instead of using shell pipes. But if you really want to+-- run a command using shell as interpreter, you can do that too like this:+-- -- >>> :{ --    Command.toBytes [str|sh "-c" "echo 'hello world' | tr [a-z] [A-Z]"|] --  & Stream.fold Stdio.write@@ -168,16 +172,3 @@ -- Keep it synced with the Internal module  #include "DocTestCommand.hs"--- Note: Commands are not executed using shell------ You can use this module to execute system commands and compose them with--- Haskell.  It does not use the system shell to execute commands, they are--- executed as independent processes. This provides a convenient and powerful--- way to replace shell scripting with Haskell. Instead of composing commands--- using shell you can use Haskell Streamly streaming APIs to compose them with--- better efficiency and type safety.------ Normally, you should not need the system shell but if you want to use shell--- scripts in your program then you can take a look at the @streamly-shell@--- package which provides convenient wrapper over "Streamly.System.Process" to--- execute shell scripts, commands.
streamly-process.cabal view
@@ -1,14 +1,21 @@ cabal-version:       2.2 name:                streamly-process-version:             0.4.0-synopsis:            Use OS processes as stream transformation functions+version:             0.4.1+synopsis:            Write shell-like command pipelines in Haskell description:-  Use operating system (OS) commands in Haskell programs as if they were-  native Haskell functions, by treating their inputs and outputs as-  Haskell streams. This allows you to write high-level Haskell scripts-  that can perform tasks similar to shell scripts, but with C-like-  performance, and with strong safety guarantees, refactorability, and-  modularity.+  Treat operating system (OS) processes as first-class stream+  transformations in Haskell. This package lets you compose external+  commands as if they were native Haskell functions, connecting+  their inputs and outputs through typed streams and perform tasks+  concurrently. It let's you do your scripting tasks in Haskell with+  near-native performance.+  .+  The API is designed to be concise and ergonomic, making it easy+  to express complex pipelines with minimal boilerplate. You can+  build high-level, declarative workflows similar to shell scripts+  while retaining Haskell’s strengths: type safety, composability,+  refactorability, and modular design. Moreover, you get the concurrent+  compositions and C-like performance of streamly. homepage:            https://streamly.composewell.com bug-reports:         https://github.com/composewell/streamly-process/issues license:             Apache-2.0@@ -18,21 +25,21 @@ copyright:           Composewell Technologies category:            Streamly, Streaming, System stability:           Experimental-tested-with:         GHC==9.10.1-                   , GHC==9.8.1-                   , GHC==9.6.3-                   , GHC==9.4.4-                   , GHC==9.2.7-                   , GHC==9.0.2-                   , GHC==8.10.7-                   , GHC==8.8.4-                   , GHC==8.6.5-build-type:          Simple-extra-source-files:+tested-with:+    GHC==9.14.1+  , GHC==9.12.4+  , GHC==9.10.3+  , GHC==9.8.4+  , GHC==9.6.3+  , GHC==9.4.8+  , GHC==8.10.7+build-type: Simple+extra-doc-files:   CHANGELOG.md   NOTICE   README.md   design/proposal.md+extra-source-files:   src/DocTestCommand.hs   src/DocTestProcess.hs   test/data/failExec.bat@@ -107,7 +114,7 @@   else      if !os(windows)        build-depends:-         unix >= 2.5 && < 2.8+         unix >= 2.5 && < 2.9  ------------------------------------------------------------------------------- -- Benchmarks@@ -130,7 +137,7 @@     , directory         >= 1.2.2 && < 1.4     -- Uses internal APIs     , streamly-core-    , tasty-bench >= 0.2.5 && < 0.5+    , tasty-bench >= 0.2.5 && < 0.6    if flag(fusion-plugin) && !impl(ghc < 8.6)     build-depends:@@ -150,6 +157,6 @@     , directory         >= 1.2.2 && < 1.4     , exceptions        >= 0.8   && < 0.11     , hspec             >= 2.0   && < 3-    , QuickCheck        >= 2.10  && < 2.16+    , QuickCheck        >= 2.10  && < 2.19     -- Uses internal APIs     , streamly-core
test/Streamly/System/Process.hs view
@@ -38,7 +38,7 @@ import qualified Streamly.Data.Stream as Stream  import qualified Streamly.Internal.FileSystem.Handle as FH (putBytes, read)-import qualified Streamly.Internal.System.Command as Cmd (quotedWord)+import qualified Streamly.Internal.System.Command as Cmd (shellWord)  ------------------------------------------------------------------------------- -- Compatibility@@ -486,12 +486,12 @@      checkFailAction = catch action failAction -quotedWordTest :: String -> [String] -> IO ()-quotedWordTest inp expected = do+shellWordTest :: String -> [String] -> IO ()+shellWordTest inp expected = do     res <-         Stream.fold Fold.toList             $ Stream.catRights-            $ Stream.parseMany Cmd.quotedWord $ Stream.fromList inp+            $ Stream.parseMany Cmd.shellWord $ Stream.fromList inp     res `shouldBe` expected  main :: IO ()@@ -551,14 +551,14 @@                 prop "toBytesEither cat = FH.toBytes" toBytes1                 prop "toBytesEither on failing executable" toBytes2 -            describe "quotedWord" $ do+            describe "shellWord" $ do                 it "Single quote test" $-                   quotedWordTest "'hello\\\\\"world'" ["hello\\\\\"world"]+                   shellWordTest "'hello\\\\\"world'" ["hello\\\\\"world"]                 it "Double quote test" $-                   quotedWordTest+                   shellWordTest                        "\"hello\\\"\\\\w\\'orld\""                        ["hello\"\\w\\'orld"]-                -- TODO: We need to let the escape character be at the end-                -- "wordWithQuotes" needs to be fixed!-                -- it "Double quote test" $-                --    quotedWordTest "'hello\'" ["hello\\"]+#if MIN_VERSION_streamly_core(0,3,0)+                it "Double quote test, escape at end" $+                    shellWordTest "'hello\\'" ["hello\\"]+#endif