{-# LANGUAGE CPP #-}
-- |
-- Module      : Streamly.System.Command
-- Copyright   : (c) 2023 Composewell Technologies
-- License     : Apache-2.0
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC
--
-- This module provides a way to invoke external executables and use them
-- seamlessly in a Haskell program, in a streaming fashion. This enables you to
-- write high-level Haskell scripts to perform tasks similar to shell scripts
-- without requiring the shell. Moreover, Haskell scripts provide C-like
-- performance.
--
-- Please see the "Streamly.System.Process" for basics. This module is a
-- wrapper over that module. "Streamly.System.Process" requires
-- specifying a command executable name and its arguments separately (e.g.
-- "ls" "-al") whereas using this module we can specify the executable and its
-- arguments more conveniently as a single command string e.g.  we can execute
-- "ls -al".
--
-- A command string is parsed in the same way as a posix shell would parse it.
-- A command string consists of whitespace separated tokens with the first
-- token treated as the executable name and the rest as arguments. Whitespace
-- can be escaped using @\\@. Alternatively, double quotes or single quotes can
-- be used to enclose tokens with whitespaces. Quotes can be escaped using @\\@.
-- Single quotes inside double quotes or vice-versa are treated as normal
-- characters.
--
-- You can use the string quasiquoter 'Streamly.Unicode.String.str' to write
-- commands conveniently, it allows Haskell variable expansion as well e.g.:
--
-- >>> f = "file name"
-- >>> [str|ls -al "#{f} with spaces"|]
-- "ls -al \"file name with spaces\""
--
-- With the "Streamly.System.Command" module you can write the examples in the
-- "Streamly.System.Process" module more conveniently.
--
-- = Executables as functions
--
-- The shell command @echo "hello world" | tr [a-z] [A-Z]@ can be written as
-- follows using this module:
--
-- >>> :{
--    Command.toBytes [str|echo "hello world"|]
--  & Command.pipeBytes [str|tr [a-z] [A-Z]|]
--  & Stream.fold Stdio.write
--  :}
--  HELLO WORLD
--
-- = Shell commands as functions
--
-- 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:
--
-- >>> :{
--    Command.toBytes [str|sh "-c" "echo 'hello world' | tr [a-z] [A-Z]"|]
--  & Stream.fold Stdio.write
--  :}
--  HELLO WORLD
--
-- = Running Commands Concurrently
--
-- This example shows the power of composing in Haskell rather than using the
-- shell. Running @grep@ concurrently on many files:
--
-- >>> :{
-- grep file =
--    Command.toBytes [str|grep -H "pattern" #{file}|]
--  & Stream.handle (\(_ :: Command.ProcessFailure) -> Stream.nil)
--  & Stream.foldMany (Fold.takeEndBy (== 10) Array.write)
--  :}
--
-- >>> :{
-- pgrep =
--    Dir.readFiles "."
--  & Stream.parConcatMap id grep
--  & Stream.fold Stdio.writeChunks
-- :}
--
-- = Experimental APIs
--
-- See "Streamly.Internal.System.Command" for unreleased APIs.
--

module Streamly.System.Command
    (
    -- * Setup
    -- | To execute the code examples provided in this module in ghci, please
    -- run the following commands first.
    --
    -- $setup

    -- * Exceptions
      Process.ProcessFailure (..)

    -- * Process Configuration
    -- | Use the config modifiers to modify the default config.
    , Process.Config

    -- ** Common Modifiers
    -- | These options apply to both POSIX and Windows.
    , Process.setCwd
    , Process.setEnv
    , Process.closeFiles
    , Process.newProcessGroup
    , Process.Session (..)
    , Process.setSession

    -- ** Posix Only Modifiers
    -- | These options have no effect on Windows.
    , Process.interruptChildOnly
    , Process.setUserId
    , Process.setGroupId

    -- ** Windows Only Modifiers
    -- | These options have no effect on Posix.
    , Process.waitForDescendants

    -- * Generation
    , toBytes
    , toChunks
    , toChunksWith
    , toChars
    , toLines

    -- * Effects
    , toString
    , toStdout
    , toNull

    -- * Transformation
    , pipeChunks
    , pipeChunksWith
    , pipeBytes
    , pipeChars

    -- -- * Including Stderr Stream
    -- | Like other "Generation" routines but along with stdout, stderr is also
    -- included in the output stream. stdout is converted to 'Right' values in
    -- the output stream and stderr is converted to 'Left' values.
    -- , toBytesEither
    -- , toChunksEither
    -- , toChunksEitherWith
    -- , pipeBytesEither
    -- , pipeChunksEither
    -- , pipeChunksEitherWith

    -- * Non-streaming Processes
    -- | These processes do not attach the IO streams with other processes.
    , foreground
    , daemon
    , standalone

    -- -- * Helpers
    -- , runWith
    -- , streamWith
    -- , pipeWith
    )
where

import Streamly.Internal.System.Command
import qualified Streamly.Internal.System.Process as Process -- (ProcessFailure (..))

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