{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
module Streamly.Internal.System.Command
(
toBytes
, toChunks
, toChunksWith
, toChars
, toLines
, toString
, toStdout
, toNull
, pipeBytes
, pipeChars
, pipeChunks
, pipeChunksWith
, standalone
, foreground
, daemon
, quotedWord
, runWith
, streamWith
, pipeWith
)
where
import Control.Monad.Catch (MonadCatch)
import Data.Char (isSpace)
import Data.Word (Word8)
import Streamly.Data.Array (Array)
import Streamly.Data.Fold (Fold)
import Streamly.Data.Parser (Parser)
import Streamly.Data.Stream.Prelude (MonadAsync, Stream)
import Streamly.Internal.System.Process (Config)
import System.Exit (ExitCode(..))
import System.Process (ProcessHandle)
import qualified Streamly.Data.Fold as Fold
import qualified Streamly.Data.Parser as Parser
import qualified Streamly.Data.Stream.Prelude as Stream
import qualified Streamly.Internal.System.Process as Process
#include "DocTestCommand.hs"
{-# INLINE quotedWord #-}
quotedWord :: MonadCatch m => Parser Char m String
quotedWord :: forall (m :: * -> *). MonadCatch m => Parser Char m String
quotedWord =
let toRQuote :: Char -> Maybe Char
toRQuote Char
x =
case Char
x of
Char
'"' -> forall a. a -> Maybe a
Just Char
x
Char
'\'' -> forall a. a -> Maybe a
Just Char
x
Char
_ -> forall a. Maybe a
Nothing
trEsc :: Char -> Char -> Maybe Char
trEsc Char
'"' Char
x =
case Char
x of
Char
'\\' -> forall a. a -> Maybe a
Just Char
'\\'
Char
'"' -> forall a. a -> Maybe a
Just Char
'"'
Char
_ -> forall a. Maybe a
Nothing
trEsc Char
_ Char
_ = forall a. Maybe a
Nothing
in forall (m :: * -> *) a b.
(Monad m, Eq a) =>
Bool
-> (a -> a -> Maybe a)
-> a
-> (a -> Maybe a)
-> (a -> Bool)
-> Fold m a b
-> Parser a m b
Parser.wordWithQuotes Bool
False Char -> Char -> Maybe Char
trEsc Char
'\\' Char -> Maybe Char
toRQuote Char -> Bool
isSpace forall (m :: * -> *) a. Monad m => Fold m a [a]
Fold.toList
{-# INLINE streamWith #-}
streamWith :: MonadCatch m =>
(FilePath -> [String] -> Stream m a) -> String -> Stream m a
streamWith :: forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> Stream m a) -> String -> Stream m a
streamWith String -> [String] -> Stream m a
f String
cmd =
forall (m :: * -> *) a. Monad m => m (Stream m a) -> Stream m a
Stream.concatEffect forall a b. (a -> b) -> a -> b
$ do
[String]
xs <- forall (m :: * -> *) a b.
Monad m =>
Fold m a b -> Stream m a -> m b
Stream.fold forall (m :: * -> *) a. Monad m => Fold m a [a]
Fold.toList
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b.
Monad m =>
Stream m (Either a b) -> Stream m b
Stream.catRights
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b.
Monad m =>
Parser a m b -> Stream m a -> Stream m (Either ParseError b)
Stream.parseMany forall (m :: * -> *). MonadCatch m => Parser Char m String
quotedWord
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Applicative m => [a] -> Stream m a
Stream.fromList String
cmd
case [String]
xs of
String
y:[String]
ys -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String -> [String] -> Stream m a
f String
y [String]
ys
[String]
_ -> forall a. HasCallStack => String -> a
error String
"streamWith: empty command"
{-# INLINE runWith #-}
runWith :: MonadCatch m =>
(FilePath -> [String] -> m a) -> String -> m a
runWith :: forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> m a) -> String -> m a
runWith String -> [String] -> m a
f String
cmd = do
[String]
xs <- forall (m :: * -> *) a b.
Monad m =>
Fold m a b -> Stream m a -> m b
Stream.fold forall (m :: * -> *) a. Monad m => Fold m a [a]
Fold.toList
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b.
Monad m =>
Stream m (Either a b) -> Stream m b
Stream.catRights
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b.
Monad m =>
Parser a m b -> Stream m a -> Stream m (Either ParseError b)
Stream.parseMany forall (m :: * -> *). MonadCatch m => Parser Char m String
quotedWord
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Applicative m => [a] -> Stream m a
Stream.fromList String
cmd
case [String]
xs of
String
y:[String]
ys -> String -> [String] -> m a
f String
y [String]
ys
[String]
_ -> forall a. HasCallStack => String -> a
error String
"streamWith: empty command"
pipeWith :: MonadCatch m =>
(FilePath -> [String] -> Stream m a -> Stream m b)
-> String
-> Stream m a
-> Stream m b
pipeWith :: forall (m :: * -> *) a b.
MonadCatch m =>
(String -> [String] -> Stream m a -> Stream m b)
-> String -> Stream m a -> Stream m b
pipeWith String -> [String] -> Stream m a -> Stream m b
f String
cmd Stream m a
input =
forall (m :: * -> *) a. Monad m => m (Stream m a) -> Stream m a
Stream.concatEffect forall a b. (a -> b) -> a -> b
$ do
[String]
xs <- forall (m :: * -> *) a b.
Monad m =>
Fold m a b -> Stream m a -> m b
Stream.fold forall (m :: * -> *) a. Monad m => Fold m a [a]
Fold.toList
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b.
Monad m =>
Stream m (Either a b) -> Stream m b
Stream.catRights
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b.
Monad m =>
Parser a m b -> Stream m a -> Stream m (Either ParseError b)
Stream.parseMany forall (m :: * -> *). MonadCatch m => Parser Char m String
quotedWord
forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Applicative m => [a] -> Stream m a
Stream.fromList String
cmd
case [String]
xs of
String
y:[String]
ys -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String -> [String] -> Stream m a -> Stream m b
f String
y [String]
ys Stream m a
input
[String]
_ -> forall a. HasCallStack => String -> a
error String
"streamWith: empty command"
{-# INLINE pipeChunksWith #-}
pipeChunksWith ::
(MonadCatch m, MonadAsync m)
=> (Config -> Config)
-> String
-> Stream m (Array Word8)
-> Stream m (Array Word8)
pipeChunksWith :: forall (m :: * -> *).
(MonadCatch m, MonadAsync m) =>
(Config -> Config)
-> String -> Stream m (Array Word8) -> Stream m (Array Word8)
pipeChunksWith Config -> Config
modifier = forall (m :: * -> *) a b.
MonadCatch m =>
(String -> [String] -> Stream m a -> Stream m b)
-> String -> Stream m a -> Stream m b
pipeWith (forall (m :: * -> *).
(MonadCatch m, MonadAsync m) =>
(Config -> Config)
-> String
-> [String]
-> Stream m (Array Word8)
-> Stream m (Array Word8)
Process.pipeChunksWith Config -> Config
modifier)
{-# INLINE pipeChunks #-}
pipeChunks :: (MonadAsync m, MonadCatch m) =>
String -> Stream m (Array Word8) -> Stream m (Array Word8)
pipeChunks :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> Stream m (Array Word8) -> Stream m (Array Word8)
pipeChunks = forall (m :: * -> *) a b.
MonadCatch m =>
(String -> [String] -> Stream m a -> Stream m b)
-> String -> Stream m a -> Stream m b
pipeWith forall (m :: * -> *).
(MonadCatch m, MonadAsync m) =>
String
-> [String] -> Stream m (Array Word8) -> Stream m (Array Word8)
Process.pipeChunks
{-# INLINE pipeBytes #-}
pipeBytes :: (MonadAsync m, MonadCatch m) =>
String -> Stream m Word8 -> Stream m Word8
pipeBytes :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> Stream m Word8 -> Stream m Word8
pipeBytes = forall (m :: * -> *) a b.
MonadCatch m =>
(String -> [String] -> Stream m a -> Stream m b)
-> String -> Stream m a -> Stream m b
pipeWith forall (m :: * -> *).
(MonadCatch m, MonadAsync m) =>
String -> [String] -> Stream m Word8 -> Stream m Word8
Process.pipeBytes
{-# INLINE pipeChars #-}
pipeChars :: (MonadAsync m, MonadCatch m) =>
String -> Stream m Char -> Stream m Char
pipeChars :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> Stream m Char -> Stream m Char
pipeChars = forall (m :: * -> *) a b.
MonadCatch m =>
(String -> [String] -> Stream m a -> Stream m b)
-> String -> Stream m a -> Stream m b
pipeWith forall (m :: * -> *).
(MonadCatch m, MonadAsync m) =>
String -> [String] -> Stream m Char -> Stream m Char
Process.pipeChars
{-# INLINE toBytes #-}
toBytes :: (MonadAsync m, MonadCatch m) => String -> Stream m Word8
toBytes :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> Stream m Word8
toBytes = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> Stream m a) -> String -> Stream m a
streamWith forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> [String] -> Stream m Word8
Process.toBytes
{-# INLINE toChunksWith #-}
toChunksWith ::
(MonadCatch m, MonadAsync m)
=> (Config -> Config)
-> String
-> Stream m (Array Word8)
toChunksWith :: forall (m :: * -> *).
(MonadCatch m, MonadAsync m) =>
(Config -> Config) -> String -> Stream m (Array Word8)
toChunksWith Config -> Config
modifier = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> Stream m a) -> String -> Stream m a
streamWith (forall (m :: * -> *).
(MonadCatch m, MonadAsync m) =>
(Config -> Config) -> String -> [String] -> Stream m (Array Word8)
Process.toChunksWith Config -> Config
modifier)
{-# INLINE toChunks #-}
toChunks :: (MonadAsync m, MonadCatch m) => String -> Stream m (Array Word8)
toChunks :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> Stream m (Array Word8)
toChunks = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> Stream m a) -> String -> Stream m a
streamWith forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> [String] -> Stream m (Array Word8)
Process.toChunks
{-# INLINE toChars #-}
toChars :: (MonadAsync m, MonadCatch m) => String -> Stream m Char
toChars :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> Stream m Char
toChars = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> Stream m a) -> String -> Stream m a
streamWith forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> [String] -> Stream m Char
Process.toChars
{-# INLINE toLines #-}
toLines ::
(MonadAsync m, MonadCatch m)
=> Fold m Char a
-> String
-> Stream m a
toLines :: forall (m :: * -> *) a.
(MonadAsync m, MonadCatch m) =>
Fold m Char a -> String -> Stream m a
toLines Fold m Char a
f = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> Stream m a) -> String -> Stream m a
streamWith (forall (m :: * -> *) a.
(MonadAsync m, MonadCatch m) =>
Fold m Char a -> String -> [String] -> Stream m a
Process.toLines Fold m Char a
f)
{-# INLINE toString #-}
toString ::
(MonadAsync m, MonadCatch m)
=> String
-> m String
toString :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> m String
toString = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> m a) -> String -> m a
runWith forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> [String] -> m String
Process.toString
{-# INLINE toStdout #-}
toStdout ::
(MonadAsync m, MonadCatch m)
=> String
-> m ()
toStdout :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> m ()
toStdout = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> m a) -> String -> m a
runWith forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> [String] -> m ()
Process.toStdout
{-# INLINE toNull #-}
toNull ::
(MonadAsync m, MonadCatch m)
=> String
-> m ()
toNull :: forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> m ()
toNull = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> m a) -> String -> m a
runWith forall (m :: * -> *).
(MonadAsync m, MonadCatch m) =>
String -> [String] -> m ()
Process.toNull
{-# INLINE standalone #-}
standalone ::
Bool
-> (Bool, Bool, Bool)
-> (Config -> Config)
-> String
-> IO (Either ExitCode ProcessHandle)
standalone :: Bool
-> (Bool, Bool, Bool)
-> (Config -> Config)
-> String
-> IO (Either ExitCode ProcessHandle)
standalone Bool
wait (Bool, Bool, Bool)
streams Config -> Config
modCfg =
forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> m a) -> String -> m a
runWith (Bool
-> (Bool, Bool, Bool)
-> (Config -> Config)
-> String
-> [String]
-> IO (Either ExitCode ProcessHandle)
Process.standalone Bool
wait (Bool, Bool, Bool)
streams Config -> Config
modCfg)
{-# INLINE foreground #-}
foreground ::
(Config -> Config)
-> String
-> IO ExitCode
foreground :: (Config -> Config) -> String -> IO ExitCode
foreground Config -> Config
modCfg = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> m a) -> String -> m a
runWith ((Config -> Config) -> String -> [String] -> IO ExitCode
Process.foreground Config -> Config
modCfg)
{-# INLINE daemon #-}
daemon ::
(Config -> Config)
-> String
-> IO ProcessHandle
daemon :: (Config -> Config) -> String -> IO ProcessHandle
daemon Config -> Config
modCfg = forall (m :: * -> *) a.
MonadCatch m =>
(String -> [String] -> m a) -> String -> m a
runWith ((Config -> Config) -> String -> [String] -> IO ProcessHandle
Process.daemon Config -> Config
modCfg)