packages feed

polysemy-process 0.5.1.1 → 0.6.0.0

raw patch · 24 files changed

+1020/−257 lines, 24 filesdep +incipit-coredep +pathdep +path-iodep −asyncdep −bytestringdep −containersdep ~polysemy-resumedep ~typed-processsetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: incipit-core, path, path-io, posix-pty, process, unix

Dependencies removed: async, bytestring, containers, polysemy-time, relude, stm, template-haskell, text, time

Dependency ranges changed: polysemy-resume, typed-process

API changes (from Hackage documentation)

- Polysemy.Process: interpretProcessIOE :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped ProcessQueues (Process ByteString ByteString ByteString !! ProcessError)) r
- Polysemy.Process: interpretProcessNative :: forall resource i o e err stdin stdout stderr r. Members [Resource, Race, Async, Embed IO] r => ProcessConfig stdin stdout stderr -> (forall x. Process stdin stdout stderr -> (resource -> Sem r x) -> Sem r x) -> (resource -> InterpreterFor (Process i o e !! err) r) -> InterpreterFor (Scoped resource (Process i o e !! err)) r
- Polysemy.Process.Interpreter.Process: interpretProcessNative :: forall resource i o e err stdin stdout stderr r. Members [Resource, Race, Async, Embed IO] r => ProcessConfig stdin stdout stderr -> (forall x. Process stdin stdout stderr -> (resource -> Sem r x) -> Sem r x) -> (resource -> InterpreterFor (Process i o e !! err) r) -> InterpreterFor (Scoped resource (Process i o e !! err)) r
- Polysemy.Process.Interpreter.ProcessIOE: instance GHC.Classes.Eq a => GHC.Classes.Eq (Polysemy.Process.Interpreter.ProcessIOE.Err a)
- Polysemy.Process.Interpreter.ProcessIOE: instance GHC.Classes.Eq a => GHC.Classes.Eq (Polysemy.Process.Interpreter.ProcessIOE.In a)
- Polysemy.Process.Interpreter.ProcessIOE: instance GHC.Classes.Eq a => GHC.Classes.Eq (Polysemy.Process.Interpreter.ProcessIOE.Out a)
- Polysemy.Process.Interpreter.ProcessIOE: instance GHC.Show.Show a => GHC.Show.Show (Polysemy.Process.Interpreter.ProcessIOE.Err a)
- Polysemy.Process.Interpreter.ProcessIOE: instance GHC.Show.Show a => GHC.Show.Show (Polysemy.Process.Interpreter.ProcessIOE.In a)
- Polysemy.Process.Interpreter.ProcessIOE: instance GHC.Show.Show a => GHC.Show.Show (Polysemy.Process.Interpreter.ProcessIOE.Out a)
- Polysemy.Process.Interpreter.ProcessIOE: interpretProcessIOE :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped ProcessQueues (Process ByteString ByteString ByteString !! ProcessError)) r
+ Polysemy.Process: [RecvError] :: Process i o e m e
+ Polysemy.Process: [Recv] :: Process i o e m o
+ Polysemy.Process: [Send] :: i -> Process i o e m ()
+ Polysemy.Process: data ProcessOutput a :: Effect
+ Polysemy.Process: data Pty :: Effect
+ Polysemy.Process: data SystemProcess :: Effect
+ Polysemy.Process: interpretProcess :: forall resource err o e r. Member (Scoped resource (SystemProcess !! err)) r => Members [ProcessOutput o, ProcessOutput e, Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString o e) !! ProcessError) r
+ Polysemy.Process: interpretProcessByteString :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process: interpretProcessByteStringLines :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process: interpretProcessByteStringLinesNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process: interpretProcessByteStringNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process: interpretProcessOutputId :: InterpreterFor (ProcessOutput ByteString) r
+ Polysemy.Process: interpretProcessOutputLines :: InterpreterFor (ProcessOutput ByteString) r
+ Polysemy.Process: interpretProcessOutputText :: InterpreterFor (ProcessOutput Text) r
+ Polysemy.Process: interpretProcessOutputTextLines :: InterpreterFor (ProcessOutput Text) r
+ Polysemy.Process: interpretProcessText :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process: interpretProcessTextLines :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process: interpretProcessTextLinesNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process: interpretProcessTextNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process: interpretPty :: Members [Resource, Embed IO] r => InterpreterFor (Scoped PtyResources Pty !! PtyError) r
+ Polysemy.Process: interpretSystemProcessNative :: forall r. Members [Resource, Embed IO] r => ProcessConfig () () () -> InterpreterFor (Scoped PipesProcess (SystemProcess !! SystemProcessError)) r
+ Polysemy.Process: interpretSystemProcessNativeOpaque :: forall i o e r. Members [Resource, Embed IO] r => ProcessConfig i o e -> InterpreterFor (Scoped (Process i o e) (SystemProcess !! SystemProcessError)) r
+ Polysemy.Process: interpretSystemProcessNativeOpaqueSingle :: forall i o e r. Members [Resource, Embed IO] r => ProcessConfig i o e -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process: interpretSystemProcessNativeSingle :: forall r. Members [Resource, Embed IO] r => ProcessConfig () () () -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process: interpretSystemProcessWithProcess :: forall r. Member (Embed IO) r => Process Handle Handle Handle -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process: interpretSystemProcessWithProcessOpaque :: forall i o e r. Member (Embed IO) r => Process i o e -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process: resolveExecutable :: Member (Embed IO) r => Path Rel File -> Maybe (Path Abs File) -> Sem r (Either Text (Path Abs File))
+ Polysemy.Process: withPty :: forall resource r. Member (Scoped resource Pty) r => InterpreterFor Pty r
+ Polysemy.Process: withSystemProcess :: forall resource err r. Member (Scoped resource (SystemProcess !! err)) r => InterpreterFor (SystemProcess !! err) r
+ Polysemy.Process.Data.PtyError: PtyError :: Text -> PtyError
+ Polysemy.Process.Data.PtyError: data PtyError
+ Polysemy.Process.Data.PtyError: instance GHC.Classes.Eq Polysemy.Process.Data.PtyError.PtyError
+ Polysemy.Process.Data.PtyError: instance GHC.Show.Show Polysemy.Process.Data.PtyError.PtyError
+ Polysemy.Process.Data.PtyResources: PtyResources :: Fd -> Fd -> Handle -> Pty -> PtyResources
+ Polysemy.Process.Data.PtyResources: [$sel:handle:PtyResources] :: PtyResources -> Handle
+ Polysemy.Process.Data.PtyResources: [$sel:primary:PtyResources] :: PtyResources -> Fd
+ Polysemy.Process.Data.PtyResources: [$sel:pty:PtyResources] :: PtyResources -> Pty
+ Polysemy.Process.Data.PtyResources: [$sel:secondary:PtyResources] :: PtyResources -> Fd
+ Polysemy.Process.Data.PtyResources: data PtyResources
+ Polysemy.Process.Data.SystemProcessError: NoPipes :: SystemProcessError
+ Polysemy.Process.Data.SystemProcessError: Terminated :: Text -> SystemProcessError
+ Polysemy.Process.Data.SystemProcessError: data SystemProcessError
+ Polysemy.Process.Data.SystemProcessError: instance GHC.Classes.Eq Polysemy.Process.Data.SystemProcessError.SystemProcessError
+ Polysemy.Process.Data.SystemProcessError: instance GHC.Show.Show Polysemy.Process.Data.SystemProcessError.SystemProcessError
+ Polysemy.Process.Effect.Process: runProcessIO :: forall i o e err r. Member (Process i o e !! err) r => InterpretersFor [Output i !! err, Input o !! err] r
+ Polysemy.Process.Effect.ProcessOutput: [Chunk] :: ByteString -> ByteString -> ProcessOutput a m ([a], ByteString)
+ Polysemy.Process.Effect.ProcessOutput: data ProcessOutput a :: Effect
+ Polysemy.Process.Effect.Pty: Cols :: Int -> Cols
+ Polysemy.Process.Effect.Pty: Rows :: Int -> Rows
+ Polysemy.Process.Effect.Pty: [$sel:unCols:Cols] :: Cols -> Int
+ Polysemy.Process.Effect.Pty: [$sel:unRows:Rows] :: Rows -> Int
+ Polysemy.Process.Effect.Pty: [Handle] :: Pty m Handle
+ Polysemy.Process.Effect.Pty: [Resize] :: Rows -> Cols -> Pty m ()
+ Polysemy.Process.Effect.Pty: [Size] :: Pty m (Rows, Cols)
+ Polysemy.Process.Effect.Pty: data Pty :: Effect
+ Polysemy.Process.Effect.Pty: instance GHC.Classes.Eq Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Classes.Eq Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: instance GHC.Classes.Ord Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Classes.Ord Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: instance GHC.Enum.Enum Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Enum.Enum Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: instance GHC.Generics.Generic Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Generics.Generic Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: instance GHC.Num.Num Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Num.Num Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: instance GHC.Real.Integral Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Real.Integral Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: instance GHC.Real.Real Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Real.Real Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: instance GHC.Show.Show Polysemy.Process.Effect.Pty.Cols
+ Polysemy.Process.Effect.Pty: instance GHC.Show.Show Polysemy.Process.Effect.Pty.Rows
+ Polysemy.Process.Effect.Pty: newtype Cols
+ Polysemy.Process.Effect.Pty: newtype Rows
+ Polysemy.Process.Effect.Pty: withPty :: forall resource r. Member (Scoped resource Pty) r => InterpreterFor Pty r
+ Polysemy.Process.Effect.SystemProcess: [Pid] :: SystemProcess m Pid
+ Polysemy.Process.Effect.SystemProcess: [ReadStderr] :: SystemProcess m ByteString
+ Polysemy.Process.Effect.SystemProcess: [ReadStdout] :: SystemProcess m ByteString
+ Polysemy.Process.Effect.SystemProcess: [Signal] :: Signal -> SystemProcess m ()
+ Polysemy.Process.Effect.SystemProcess: [Wait] :: SystemProcess m ExitCode
+ Polysemy.Process.Effect.SystemProcess: [WriteStdin] :: ByteString -> SystemProcess m ()
+ Polysemy.Process.Effect.SystemProcess: data SystemProcess :: Effect
+ Polysemy.Process.Effect.SystemProcess: interrupt :: Member SystemProcess r => Sem r ()
+ Polysemy.Process.Effect.SystemProcess: kill :: Member SystemProcess r => Sem r ()
+ Polysemy.Process.Effect.SystemProcess: term :: Member SystemProcess r => Sem r ()
+ Polysemy.Process.Effect.SystemProcess: withSystemProcess :: forall resource err r. Member (Scoped resource (SystemProcess !! err)) r => InterpreterFor (SystemProcess !! err) r
+ Polysemy.Process.Executable: resolveExecutable :: Member (Embed IO) r => Path Rel File -> Maybe (Path Abs File) -> Sem r (Either Text (Path Abs File))
+ Polysemy.Process.Interpreter.Process: instance GHC.Classes.Eq a => GHC.Classes.Eq (Polysemy.Process.Interpreter.Process.Err a)
+ Polysemy.Process.Interpreter.Process: instance GHC.Classes.Eq a => GHC.Classes.Eq (Polysemy.Process.Interpreter.Process.In a)
+ Polysemy.Process.Interpreter.Process: instance GHC.Classes.Eq a => GHC.Classes.Eq (Polysemy.Process.Interpreter.Process.Out a)
+ Polysemy.Process.Interpreter.Process: instance GHC.Show.Show a => GHC.Show.Show (Polysemy.Process.Interpreter.Process.Err a)
+ Polysemy.Process.Interpreter.Process: instance GHC.Show.Show a => GHC.Show.Show (Polysemy.Process.Interpreter.Process.In a)
+ Polysemy.Process.Interpreter.Process: instance GHC.Show.Show a => GHC.Show.Show (Polysemy.Process.Interpreter.Process.Out a)
+ Polysemy.Process.Interpreter.Process: interpretProcess :: forall resource err o e r. Member (Scoped resource (SystemProcess !! err)) r => Members [ProcessOutput o, ProcessOutput e, Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString o e) !! ProcessError) r
+ Polysemy.Process.Interpreter.Process: interpretProcessByteString :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process.Interpreter.Process: interpretProcessByteStringLines :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process.Interpreter.Process: interpretProcessText :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process.Interpreter.Process: interpretProcessTextLines :: forall resource err r. Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r => Bool -> Int -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process.Interpreter.ProcessOutput: interpretProcessOutputId :: InterpreterFor (ProcessOutput ByteString) r
+ Polysemy.Process.Interpreter.ProcessOutput: interpretProcessOutputLines :: InterpreterFor (ProcessOutput ByteString) r
+ Polysemy.Process.Interpreter.ProcessOutput: interpretProcessOutputText :: InterpreterFor (ProcessOutput Text) r
+ Polysemy.Process.Interpreter.ProcessOutput: interpretProcessOutputTextLines :: InterpreterFor (ProcessOutput Text) r
+ Polysemy.Process.Interpreter.ProcessStdio: interpretProcessByteStringLinesNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process.Interpreter.ProcessStdio: interpretProcessByteStringNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
+ Polysemy.Process.Interpreter.ProcessStdio: interpretProcessTextLinesNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process.Interpreter.ProcessStdio: interpretProcessTextNative :: Members [Resource, Race, Async, Embed IO] r => Bool -> Int -> ProcessConfig () () () -> InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
+ Polysemy.Process.Interpreter.Pty: interpretPty :: Members [Resource, Embed IO] r => InterpreterFor (Scoped PtyResources Pty !! PtyError) r
+ Polysemy.Process.Interpreter.SystemProcess: interpretSystemProcessNative :: forall r. Members [Resource, Embed IO] r => ProcessConfig () () () -> InterpreterFor (Scoped PipesProcess (SystemProcess !! SystemProcessError)) r
+ Polysemy.Process.Interpreter.SystemProcess: interpretSystemProcessNativeOpaque :: forall i o e r. Members [Resource, Embed IO] r => ProcessConfig i o e -> InterpreterFor (Scoped (Process i o e) (SystemProcess !! SystemProcessError)) r
+ Polysemy.Process.Interpreter.SystemProcess: interpretSystemProcessNativeOpaqueSingle :: forall i o e r. Members [Resource, Embed IO] r => ProcessConfig i o e -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process.Interpreter.SystemProcess: interpretSystemProcessNativeSingle :: forall r. Members [Resource, Embed IO] r => ProcessConfig () () () -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process.Interpreter.SystemProcess: interpretSystemProcessWithProcess :: forall r. Member (Embed IO) r => Process Handle Handle Handle -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process.Interpreter.SystemProcess: interpretSystemProcessWithProcessOpaque :: forall i o e r. Member (Embed IO) r => Process i o e -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process.ProcessOutput: [Chunk] :: ByteString -> ByteString -> ProcessOutput a m ([a], ByteString)
+ Polysemy.Process.ProcessOutput: data ProcessOutput a :: Effect
+ Polysemy.Process.ProcessOutput: interpretProcessOutputId :: InterpreterFor (ProcessOutput ByteString) r
+ Polysemy.Process.ProcessOutput: interpretProcessOutputLines :: InterpreterFor (ProcessOutput ByteString) r
+ Polysemy.Process.ProcessOutput: interpretProcessOutputText :: InterpreterFor (ProcessOutput Text) r
+ Polysemy.Process.ProcessOutput: interpretProcessOutputTextLines :: InterpreterFor (ProcessOutput Text) r
+ Polysemy.Process.Pty: [Handle] :: Pty m Handle
+ Polysemy.Process.Pty: [Resize] :: Rows -> Cols -> Pty m ()
+ Polysemy.Process.Pty: [Size] :: Pty m (Rows, Cols)
+ Polysemy.Process.Pty: data Pty :: Effect
+ Polysemy.Process.Pty: interpretPty :: Members [Resource, Embed IO] r => InterpreterFor (Scoped PtyResources Pty !! PtyError) r
+ Polysemy.Process.Pty: withPty :: forall resource r. Member (Scoped resource Pty) r => InterpreterFor Pty r
+ Polysemy.Process.SystemProcess: [Pid] :: SystemProcess m Pid
+ Polysemy.Process.SystemProcess: [ReadStderr] :: SystemProcess m ByteString
+ Polysemy.Process.SystemProcess: [ReadStdout] :: SystemProcess m ByteString
+ Polysemy.Process.SystemProcess: [Signal] :: Signal -> SystemProcess m ()
+ Polysemy.Process.SystemProcess: [Wait] :: SystemProcess m ExitCode
+ Polysemy.Process.SystemProcess: [WriteStdin] :: ByteString -> SystemProcess m ()
+ Polysemy.Process.SystemProcess: data SystemProcess :: Effect
+ Polysemy.Process.SystemProcess: interpretSystemProcessNative :: forall r. Members [Resource, Embed IO] r => ProcessConfig () () () -> InterpreterFor (Scoped PipesProcess (SystemProcess !! SystemProcessError)) r
+ Polysemy.Process.SystemProcess: interpretSystemProcessNativeSingle :: forall r. Members [Resource, Embed IO] r => ProcessConfig () () () -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process.SystemProcess: interpretSystemProcessWithProcess :: forall r. Member (Embed IO) r => Process Handle Handle Handle -> InterpreterFor (SystemProcess !! SystemProcessError) r
+ Polysemy.Process.SystemProcess: interrupt :: Member SystemProcess r => Sem r ()
+ Polysemy.Process.SystemProcess: withSystemProcess :: forall resource err r. Member (Scoped resource (SystemProcess !! err)) r => InterpreterFor (SystemProcess !! err) r
- Polysemy.Process: withProcess :: forall resource i o e err r. Member (Scoped resource (Process i o e !! err)) r => InterpreterFor (Process i o e !! err) r
+ Polysemy.Process: withProcess :: forall resource i o e r. Member (Scoped resource (Process i o e)) r => InterpreterFor (Process i o e) r
- Polysemy.Process.Effect.Process: withProcess :: forall resource i o e err r. Member (Scoped resource (Process i o e !! err)) r => InterpreterFor (Process i o e !! err) r
+ Polysemy.Process.Effect.Process: withProcess :: forall resource i o e r. Member (Scoped resource (Process i o e)) r => InterpreterFor (Process i o e) r

Files

+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
changelog.md view
@@ -1,5 +1,12 @@ # Unreleased +* Allow `Process` to emit custom chunks constructed by an interpreter of `ProcessOutput` instead of `ByteString`s+  containing whatever the `Handle` produced.+* Rename stdio interpreters.+* Add helper `resolveExecutable` that looks up names in `$PATH` and ensures the files are executable.+* Add effect `Pty` for interacting with pseudo terminals.+* Add low-level process abstraction effect, `SystemProcess`.+ # 0.5.0.0  * Add the effect `Process`, wrapping `System.Process.Typed` using `Scoped`.
lib/Polysemy/Process.hs view
@@ -3,24 +3,108 @@   -- * Introduction   -- $intro -  -- * Effect-  Process,+  -- * Effects+  -- ** Process+  Process (..),   recv,   recvError,   send,   withProcess, +  -- ** ProcessOutput+  ProcessOutput,++  -- ** SystemProcess+  SystemProcess,+  withSystemProcess,++  -- ** Pty+  Pty,+  withPty,+   -- * Interpreters-  interpretProcessNative,-  interpretProcessIOE,+  -- ** Process+  interpretProcessByteStringNative,+  interpretProcessByteStringLinesNative,+  interpretProcessTextNative,+  interpretProcessTextLinesNative,+  interpretProcess,+  interpretProcessByteString,+  interpretProcessByteStringLines,+  interpretProcessText,+  interpretProcessTextLines,++  -- ** ProcessOutput+  interpretProcessOutputId,+  interpretProcessOutputLines,+  interpretProcessOutputText,+  interpretProcessOutputTextLines,++  -- ** SystemProcess+  interpretSystemProcessWithProcess,+  interpretSystemProcessNativeSingle,+  interpretSystemProcessNative,+  interpretSystemProcessWithProcessOpaque,+  interpretSystemProcessNativeOpaqueSingle,+  interpretSystemProcessNativeOpaque,++  -- ** Pty+  interpretPty,++  -- * Tools+  resolveExecutable, ) where -import Polysemy.Process.Effect.Process (Process, recv, recvError, send, withProcess)-import Polysemy.Process.Interpreter.Process (interpretProcessNative)-import Polysemy.Process.Interpreter.ProcessIOE (interpretProcessIOE)+import Prelude hiding (send) +import Polysemy.Process.Effect.Process (Process (..), recv, recvError, send, withProcess)+import Polysemy.Process.Effect.ProcessOutput (ProcessOutput)+import Polysemy.Process.Effect.Pty (Pty, withPty)+import Polysemy.Process.Effect.SystemProcess (+  SystemProcess,+  withSystemProcess,+  )+import Polysemy.Process.Executable (resolveExecutable)+import Polysemy.Process.Interpreter.Process (+  interpretProcess,+  interpretProcessByteString,+  interpretProcessByteStringLines,+  interpretProcessText,+  interpretProcessTextLines,+  )+import Polysemy.Process.Interpreter.ProcessOutput (+  interpretProcessOutputId,+  interpretProcessOutputLines,+  interpretProcessOutputText,+  interpretProcessOutputTextLines,+  )+import Polysemy.Process.Interpreter.ProcessStdio (+  interpretProcessByteStringLinesNative,+  interpretProcessByteStringNative,+  interpretProcessTextLinesNative,+  interpretProcessTextNative,+  )+import Polysemy.Process.Interpreter.Pty (interpretPty)+import Polysemy.Process.Interpreter.SystemProcess (+  interpretSystemProcessNative,+  interpretSystemProcessNativeOpaque,+  interpretSystemProcessNativeOpaqueSingle,+  interpretSystemProcessNativeSingle,+  interpretSystemProcessWithProcess,+  interpretSystemProcessWithProcessOpaque,+  )+ -- $intro -- This library provides an abstraction of a system process in the effect 'Process', whose constructors represent the -- three standard file descriptors. ----- The values produced by the constructors are chunks of the process' output when using the default interpreter.+-- An intermediate effect, 'SystemProcess', is more concretely tied to the functionality of the "System.Process"+-- library.+-- See "Polysemy.Process.SystemProcess" for its constructors.+--+-- The utility effect 'ProcessOutput' takes care of decoding the process output, getting called by the 'Process'+-- interpreters whenever a chunk was read, while accumulating chunks until they were decoded successfully.+-- See "Polysemy.Process.ProcessOutput" for its constructors.+--+-- The effect 'Pty' abstracts pseudo terminals.+-- See "Polysemy.Process.Pty" for its constructors.
lib/Polysemy/Process/Data/ProcessError.hs view
@@ -6,4 +6,4 @@ data ProcessError =   -- |The process terminated.   Terminated Text-  deriving (Eq, Show)+  deriving stock (Eq, Show)
+ lib/Polysemy/Process/Data/PtyError.hs view
@@ -0,0 +1,9 @@+{-# options_haddock prune #-}++-- |PtyError ADT, Internal+module Polysemy.Process.Data.PtyError where++-- |Internal error used by an interpreter for 'Polysemy.Process.Pty'.+data PtyError =+  PtyError Text+  deriving stock (Eq, Show)
+ lib/Polysemy/Process/Data/PtyResources.hs view
@@ -0,0 +1,17 @@+{-# options_haddock prune #-}++-- |Description: PtyResources ADT, Internal+module Polysemy.Process.Data.PtyResources where++import System.IO (Handle)+import System.Posix (Fd)+import System.Posix.Pty (Pty)++-- |The resources used by the default interpreter for 'Polysemy.Process.Pty'.+data PtyResources =+  PtyResources {+    primary :: Fd,+    secondary :: Fd,+    handle :: Handle,+    pty :: Pty+  }
+ lib/Polysemy/Process/Data/SystemProcessError.hs view
@@ -0,0 +1,12 @@+{-# options_haddock prune #-}++-- |Description: SystemProcessError, Internal+module Polysemy.Process.Data.SystemProcessError where++-- |Signal error for 'Polysemy.Process.SystemProcess'.+data SystemProcessError =+  -- |The process terminated.+  Terminated Text+  |+  NoPipes+  deriving stock (Eq, Show)
lib/Polysemy/Process/Effect/Process.hs view
@@ -1,10 +1,11 @@ {-# options_haddock prune #-}+ -- |Description: Process Effect, Internal module Polysemy.Process.Effect.Process where -import Polysemy (makeSem_) import Polysemy.Conc.Effect.Scoped (Scoped, scoped)-import Polysemy.Resume (type (!!))+import Polysemy.Resume (interpretResumable, restop, type (!!))+import Prelude hiding (send)  -- |Abstraction of a process with stdin/stdout/stderr. --@@ -18,8 +19,8 @@ -- -- prog :: Member (Scoped resource (Process Text Text e !! err)) r => Sem r Text -- prog =---  withProcess do---    resumeAs "failed" do+--  resumeAs "failed" do+--    withProcess do --      send "input" --      recv --@@ -56,8 +57,22 @@  -- |Create a scoped resource for 'Process'. withProcess ::-  ∀ resource i o e err r .-  Member (Scoped resource (Process i o e !! err)) r =>-  InterpreterFor (Process i o e !! err) r+  ∀ resource i o e r .+  Member (Scoped resource (Process i o e)) r =>+  InterpreterFor (Process i o e) r withProcess =   scoped @resource++-- |Convert 'Output' and 'Input' to 'Process'.+runProcessIO ::+  ∀ i o e err r .+  Member (Process i o e !! err) r =>+  InterpretersFor [Output i !! err, Input o !! err] r+runProcessIO =+  interpretResumable \case+    Input ->+      restop @err @(Process i o e) (recv @i @o @e)+  .+  interpretResumable \case+    Output o ->+      restop @err @(Process i o e) (send @i @o @e o)
+ lib/Polysemy/Process/Effect/ProcessOutput.hs view
@@ -0,0 +1,20 @@+{-# options_haddock prune #-}++-- |Description: ProcessOutput effect, Internal.+module Polysemy.Process.Effect.ProcessOutput where++-- |This effect is used by the effect 'Polysemy.Process.Process' to accumulate and decode chunks of 'ByteString's, for+-- example using a parser.+-- The interpreter may be stateful or stateless, since the constructor 'Chunk' is expected to be called with both the+-- accumulated unprocessed output as well as the new chunk.+data ProcessOutput a :: Effect where+  -- |Add a chunk of output to the accumulator, returning any number of successfully parsed values and the leftover+  -- output.+  Chunk ::+    -- |The accumulation of the previous leftovers.+    ByteString ->+    -- |The new chunk read from the process.+    ByteString ->+    ProcessOutput a m ([a], ByteString)++makeSem ''ProcessOutput
+ lib/Polysemy/Process/Effect/Pty.hs view
@@ -0,0 +1,38 @@+{-# options_haddock prune #-}++-- |Description: Pty Effect, Internal+module Polysemy.Process.Effect.Pty where++import Polysemy.Conc.Effect.Scoped (Scoped, scoped)+import System.IO (Handle)++-- |Horizontal size of a pseudo terminal in characters.+newtype Rows =+  Rows { unRows :: Int }+  deriving stock (Eq, Show, Generic)+  deriving newtype (Num, Real, Enum, Integral, Ord)++-- |Vertical size of a pseudo terminal in characters.+newtype Cols =+  Cols { unCols :: Int }+  deriving stock (Eq, Show, Generic)+  deriving newtype (Num, Real, Enum, Integral, Ord)++-- |A pseudo terminal, to be scoped with 'withPty'.+data Pty :: Effect where+  -- |The file descriptor that can be connected to stdio of a process.+  Handle :: Pty m Handle+  -- |Set the size of the terminal.+  Resize :: Rows -> Cols -> Pty m ()+  -- |Get the size of the terminal.+  Size :: Pty m (Rows, Cols)++makeSem ''Pty++-- |Bracket an action with the creation and destruction of a pseudo terminal.+withPty ::+  ∀ resource r .+  Member (Scoped resource Pty) r =>+  InterpreterFor Pty r+withPty =+  scoped @resource
+ lib/Polysemy/Process/Effect/SystemProcess.hs view
@@ -0,0 +1,58 @@+{-# options_haddock prune #-}++-- |Description: SystemProcess Effect, Internal+module Polysemy.Process.Effect.SystemProcess where++import Polysemy.Conc.Effect.Scoped (Scoped, scoped)+import Polysemy.Resume (type (!!))+import System.Exit (ExitCode)+import qualified System.Posix as Signal+import System.Posix (Signal)+import System.Process (Pid)++-- |Low-level interface for a process, operating on raw chunks of bytes.+-- Interface is modeled after "System.Process".+data SystemProcess :: Effect where+  -- |Read a chunk from stdout.+  ReadStdout :: SystemProcess m ByteString+  -- |Read a chunk from stderr.+  ReadStderr :: SystemProcess m ByteString+  -- |Write a 'ByteString' to stdin.+  WriteStdin :: ByteString -> SystemProcess m ()+  -- |Obtain the process ID.+  Pid :: SystemProcess m Pid+  -- |Send a 'System.Posix.Signal' to the process.+  Signal :: Signal -> SystemProcess m ()+  -- |Wait for the process to terminate, returning its exit code.+  Wait :: SystemProcess m ExitCode++makeSem ''SystemProcess++-- |Create a scoped resource for 'SystemProcess'.+withSystemProcess ::+  ∀ resource err r .+  Member (Scoped resource (SystemProcess !! err)) r =>+  InterpreterFor (SystemProcess !! err) r+withSystemProcess =+  scoped @resource++-- |Send signal INT(2) to the process.+interrupt ::+  Member SystemProcess r =>+  Sem r ()+interrupt =+  signal Signal.sigINT++-- |Send signal INT(15) to the process.+term ::+  Member SystemProcess r =>+  Sem r ()+term =+  signal Signal.sigTERM++-- |Send signal INT(9) to the process.+kill ::+  Member SystemProcess r =>+  Sem r ()+kill =+  signal Signal.sigKILL
+ lib/Polysemy/Process/Executable.hs view
@@ -0,0 +1,48 @@+{-# options_haddock prune #-}++-- |Description: Executable helpers, Internal+module Polysemy.Process.Executable where++import Path (Abs, File, Path, Rel, toFilePath)+import qualified Path.IO as Path+import Path.IO (executable, getPermissions)++checkExecutable ::+  Member (Embed IO) r =>+  Text ->+  Path Abs File ->+  Sem r (Either Text (Path Abs File))+checkExecutable name path =+  tryAny (getPermissions path) <&> \case+    Right (executable -> True) ->+      Right path+    Right _ ->+      Left (message "executable")+    Left _ ->+      Left (message "a readable file")+  where+    message what =+      "specified path for `" <> name <> "` is not " <> what <> ": " <> pathText+    pathText =+      toText (toFilePath path)++-- |Find a file in @$PATH@, verifying that it is executable by this process.+resolveExecutable ::+  Member (Embed IO) r =>+  -- |Executable name, for @$PATH@ lookup and error messages+  Path Rel File ->+  -- |Explicit override to be checked for adequate permissions+  Maybe (Path Abs File) ->+  Sem r (Either Text (Path Abs File))+resolveExecutable exe = \case+  Just path ->+    checkExecutable name path+  Nothing ->+    tryAny (Path.findExecutable exe) <&> \case+      Right (Just path) ->+        Right path+      _ ->+        Left ("could not find executable `" <> name <> "` in `$PATH`.")+  where+    name =+      toText (toFilePath exe)
lib/Polysemy/Process/Interpreter/Process.hs view
@@ -1,41 +1,227 @@ {-# options_haddock prune #-}+ -- |Description: Process Interpreters, Internal module Polysemy.Process.Interpreter.Process where -import Polysemy.Async (Async)-import Polysemy.Conc (Race)+import Control.Concurrent.STM.TBMQueue (TBMQueue)+import Polysemy.Conc.Async (withAsync_)+import qualified Polysemy.Conc.Data.QueueResult as QueueResult+import qualified Polysemy.Conc.Effect.Queue as Queue+import Polysemy.Conc.Effect.Queue (Queue)+import Polysemy.Conc.Effect.Race (Race) import Polysemy.Conc.Effect.Scoped (Scoped)-import Polysemy.Conc.Interpreter.Scoped (runScoped)-import Polysemy.Error (fromException, runError)-import Polysemy.Resource (Resource, bracket)-import Polysemy.Resume (type (!!))+import Polysemy.Conc.Interpreter.Queue.TBM (interpretQueueTBMWith, withTBMQueue)+import Polysemy.Conc.Interpreter.Scoped (interpretScopedResumableWith_)+import Polysemy.Resume (Stop, resumeOr, stop, type (!!)) import Prelude hiding (fromException)-import qualified System.Process.Typed as System-import System.Process.Typed (-  ProcessConfig,-  startProcess,-  stopProcess,-  ) +import Polysemy.Process.Data.ProcessError (ProcessError (Terminated))+import qualified Polysemy.Process.Effect.Process as Process import Polysemy.Process.Effect.Process (Process)+import qualified Polysemy.Process.Effect.ProcessOutput as ProcessOutput+import Polysemy.Process.Effect.ProcessOutput (ProcessOutput)+import qualified Polysemy.Process.Effect.SystemProcess as SystemProcess+import Polysemy.Process.Effect.SystemProcess (SystemProcess, withSystemProcess)+import Polysemy.Process.Interpreter.ProcessOutput (+  interpretProcessOutputId,+  interpretProcessOutputLines,+  interpretProcessOutputText,+  interpretProcessOutputTextLines,+  ) -withProcess ::+newtype In a =+  In { unIn :: a }+  deriving stock (Eq, Show)++newtype Out a =+  Out { unOut :: a }+  deriving stock (Eq, Show)++newtype Err a =+  Err { unErr :: a }+  deriving stock (Eq, Show)++data ProcessQueues o e =+  ProcessQueues {+    pqIn :: TBMQueue (In ByteString),+    pqOut :: TBMQueue (Out o),+    pqErr :: TBMQueue (Err e)+  }++interpretQueues ::+  Members [Resource, Race, Embed IO] r =>+  ProcessQueues o e ->+  InterpretersFor [Queue (In ByteString), Queue (Out o), Queue (Err e)] r+interpretQueues (ProcessQueues inQ outQ errQ) =+  interpretQueueTBMWith errQ .+  interpretQueueTBMWith outQ .+  interpretQueueTBMWith inQ++handleProcessWithQueues ::+  ∀ o e m r a .+  Members [Queue (In ByteString), Queue (Out o), Queue (Err e), Stop ProcessError] r =>+  Process ByteString o e m a ->+  Sem r a+handleProcessWithQueues = \case+  Process.Recv ->+    Queue.read >>= \case+      QueueResult.Closed ->+        stop (Terminated "closed")+      QueueResult.NotAvailable ->+        stop (Terminated "impossible: empty")+      QueueResult.Success (Out msg) ->+        pure msg+  Process.RecvError ->+    Queue.read >>= \case+      QueueResult.Closed ->+        stop (Terminated "closed")+      QueueResult.NotAvailable ->+        stop (Terminated "impossible: empty")+      QueueResult.Success (Err msg) ->+        pure msg+  Process.Send msg -> do+    whenM (Queue.closed @(In ByteString)) (stop (Terminated "closed"))+    Queue.write (In msg)++withSTMResources ::+  ∀ o e r a .   Members [Resource, Embed IO] r =>-  ProcessConfig stdin stdout stderr ->-  (System.Process stdin stdout stderr -> Sem r a) ->+  Int ->+  (ProcessQueues o e -> Sem r a) ->   Sem r a-withProcess config =-  bracket (embed @IO (startProcess config)) (runError @SomeException . fromException @SomeException . stopProcess)+withSTMResources qSize action = do+  withTBMQueue qSize \ inQ ->+    withTBMQueue qSize \ outQ ->+      withTBMQueue qSize \ errQ ->+        action (ProcessQueues inQ outQ errQ) --- |Interpret 'Process' with a system process resource.-interpretProcessNative ::-  ∀ resource i o e err stdin stdout stderr r .-  Members [Resource, Race, Async, Embed IO] r =>-  ProcessConfig stdin stdout stderr ->-  (∀ x. System.Process stdin stdout stderr -> (resource -> Sem r x) -> Sem r x) ->-  (resource -> InterpreterFor (Process i o e !! err) r) ->-  InterpreterFor (Scoped resource (Process i o e !! err)) r-interpretProcessNative config fromProcess =-  runScoped \ f ->-    withProcess config \ prc ->-      fromProcess prc f+withQueues ::+  Members [Race, Resource, Embed IO] r =>+  Int ->+  InterpretersFor [Queue (In ByteString), Queue (Out o), Queue (Err e)] r+withQueues qSize action =+  withSTMResources qSize \ qs -> interpretQueues qs action++outputQueue ::+  ∀ pipe chunk err r .+  Coercible (pipe chunk) chunk =>+  Members [SystemProcess !! err, ProcessOutput chunk, Queue (pipe chunk), Embed IO] r =>+  Bool ->+  Sem (SystemProcess : r) ByteString ->+  Sem r ()+outputQueue discardWhenFull readChunk = do+  spin ""+  where+    spin buffer =+      resumeOr @err readChunk (write buffer) (const (Queue.close @(pipe chunk)))+    write buffer msg = do+      (chunks, newBuffer) <- ProcessOutput.chunk buffer msg+      for_ chunks \ (coerce @chunk @(pipe chunk) -> c) ->+        if discardWhenFull then void (Queue.tryWrite c) else Queue.write c+      spin newBuffer++inputQueue ::+  ∀ err r .+  Members [SystemProcess !! err, Queue (In ByteString), Embed IO] r =>+  (ByteString -> Sem (SystemProcess : r) ()) ->+  Sem r ()+inputQueue writeChunk =+  spin+  where+    spin =+      Queue.read >>= \case+        QueueResult.Success (In msg) ->+          resumeOr @err (writeChunk msg) (const spin) (const (Queue.close @(In ByteString)))+        _ ->+          unit++type ScopeEffects o e err =+  [Queue (In ByteString), Queue (Out o), Queue (Err e), SystemProcess !! err]++scope ::+  ∀ o e resource err r .+  Member (Scoped resource (SystemProcess !! err)) r =>+  Members [ProcessOutput e, ProcessOutput o, Resource, Race, Async, Embed IO] r =>+  Bool ->+  Int ->+  InterpretersFor (ScopeEffects o e err) r+scope discard qSize =+  withSystemProcess @resource .+  withQueues qSize .+  withAsync_ (outputQueue @Err @e @err discard SystemProcess.readStderr) .+  withAsync_ (outputQueue @Out @o @err discard SystemProcess.readStdout) .+  withAsync_ (inputQueue @err SystemProcess.writeStdin)++-- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,+-- deferring decoding of stdout and stderr to the interpreters of two 'ProcessOutput' effects.+interpretProcess ::+  ∀ resource err o e r .+  Member (Scoped resource (SystemProcess !! err)) r =>+  Members [ProcessOutput o, ProcessOutput e, Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full or block.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  InterpreterFor (Scoped () (Process ByteString o e) !! ProcessError) r+interpretProcess discard qSize =+  interpretScopedResumableWith_ @(ScopeEffects o e err) (scope @o @e @resource discard qSize) handleProcessWithQueues++-- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,+-- producing 'ByteString's.+interpretProcessByteString ::+  ∀ resource err r .+  Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r+interpretProcessByteString discard qSize =+  interpretProcessOutputId .+  interpretProcess @resource @err discard qSize .+  raiseUnder++-- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,+-- producing chunks of lines of 'ByteString's.+interpretProcessByteStringLines ::+  ∀ resource err r .+  Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r+interpretProcessByteStringLines discard qSize =+  interpretProcessOutputLines .+  interpretProcess @resource @err discard qSize .+  raiseUnder++-- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,+-- producing 'Text's.+interpretProcessText ::+  ∀ resource err r .+  Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r+interpretProcessText discard qSize =+  interpretProcessOutputText .+  interpretProcess @resource @err discard qSize .+  raiseUnder++-- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,+-- producing chunks of lines of 'Text's.+interpretProcessTextLines ::+  ∀ resource err r .+  Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r+interpretProcessTextLines discard qSize =+  interpretProcessOutputTextLines .+  interpretProcess @resource @err discard qSize .+  raiseUnder
− lib/Polysemy/Process/Interpreter/ProcessIOE.hs
@@ -1,172 +0,0 @@-{-# options_haddock prune #-}-{-# language CPP #-}---- |Description: Process Interpreters for stdpipes, Internal-module Polysemy.Process.Interpreter.ProcessIOE where--import Control.Concurrent.STM.TBMQueue (TBMQueue)-import Data.ByteString (hGetSome, hPut)-import Polysemy (InterpretersFor, insertAt)-import Polysemy.Async (Async)-import Polysemy.Conc.Async (withAsync_)-import qualified Polysemy.Conc.Data.QueueResult as QueueResult-import qualified Polysemy.Conc.Effect.Queue as Queue-import Polysemy.Conc.Effect.Queue (Queue)-import Polysemy.Conc.Effect.Race (Race)-import Polysemy.Conc.Effect.Scoped (Scoped)-import Polysemy.Conc.Interpreter.Queue.TBM (interpretQueueTBMWith, withTBMQueue)-import Polysemy.Resource (Resource)-import Polysemy.Resume (interpretResumable, stop, type (!!))-import Prelude hiding (fromException)-import qualified System.Process.Typed as System-import System.Process.Typed (-  ProcessConfig,-  createPipe,-  getStderr,-  getStdin,-  getStdout,-  setStderr,-  setStdin,-  setStdout,-  )--import Polysemy.Process.Data.ProcessError (ProcessError (Terminated))-import qualified Polysemy.Process.Effect.Process as Process-import Polysemy.Process.Effect.Process (Process)-import Polysemy.Process.Interpreter.Process (interpretProcessNative)--#if !MIN_VERSION_relude(1,0,0)-import System.IO (BufferMode (NoBuffering), hSetBuffering)-#endif--newtype In a =-  In { unIn :: a }-  deriving (Eq, Show)--newtype Out a =-  Out { unOut :: a }-  deriving (Eq, Show)--newtype Err a =-  Err { unErr :: a }-  deriving (Eq, Show)--data ProcessQueues =-  ProcessQueues {-    pqIn :: TBMQueue (In ByteString),-    pqOut :: TBMQueue (Out ByteString),-    pqErr :: TBMQueue (Err ByteString)-  }--processWithQueues :: ProcessConfig () () () -> ProcessConfig Handle Handle Handle-processWithQueues =-  setStdin createPipe . setStdout createPipe . setStderr createPipe--readQueue ::-  ∀ r .-  Members [Queue (In ByteString), Embed IO] r =>-  Bool ->-  Handle ->-  Sem r ()-readQueue discardWhenFull handle = do-  void $ tryAny (hSetBuffering handle NoBuffering)-  tryAny (hGetSome handle 4096) >>= traverse_ \ msg -> do-    if discardWhenFull then void (Queue.tryWrite (In msg)) else Queue.write (In msg)-    readQueue discardWhenFull handle--writeQueue ::-  ∀ r .-  Members [Queue (Out ByteString), Embed IO] r =>-  Handle ->-  Sem r ()-writeQueue handle = do-  void $ tryAny (hSetBuffering handle NoBuffering)-  spin-  where-    spin =-      Queue.read >>= \case-        QueueResult.Success (Out msg) ->-          traverse_ (const spin) =<< tryAny (hPut handle msg)-        _ ->-          pass--interpretQueues ::-  Members [Resource, Race, Embed IO] r =>-  ProcessQueues ->-  InterpretersFor [Queue (In ByteString), Queue (Out ByteString), Queue (Err ByteString)] r-interpretQueues (ProcessQueues inQ outQ errQ) =-  interpretQueueTBMWith errQ .-  interpretQueueTBMWith outQ .-  interpretQueueTBMWith inQ--interpretProcessWithQueues ::-  Members [Queue (In ByteString), Queue (Out ByteString), Queue (Err ByteString)] r =>-  InterpreterFor (Process ByteString ByteString ByteString !! ProcessError) r-interpretProcessWithQueues =-  interpretResumable \case-    Process.Recv ->-      Queue.read >>= \case-        QueueResult.Closed ->-          stop (Terminated "closed")-        QueueResult.NotAvailable ->-          stop (Terminated "impossible: empty")-        QueueResult.Success (In msg) ->-          pure msg-    Process.RecvError ->-      Queue.read >>= \case-        QueueResult.Closed ->-          stop (Terminated "closed")-        QueueResult.NotAvailable ->-          stop (Terminated "impossible: empty")-        QueueResult.Success (Err msg) ->-          pure msg-    Process.Send msg -> do-      whenM (Queue.closed @(Out ByteString)) (stop (Terminated "closed"))-      Queue.write (Out msg)--withSTMResources ::-  ∀ r a .-  Members [Resource, Embed IO] r =>-  Int ->-  (ProcessQueues -> Sem r a) ->-  Sem r a-withSTMResources qSize action = do-  withTBMQueue qSize \ inQ ->-    withTBMQueue qSize \ outQ ->-      withTBMQueue qSize \ errQ ->-        action (ProcessQueues inQ outQ errQ)--withProcessResources ::-  Members [Resource, Race, Async, Embed IO] r =>-  Bool ->-  Int ->-  System.Process Handle Handle Handle ->-  (ProcessQueues -> Sem r a) ->-  Sem r a-withProcessResources discardWhenFull qSize prc f =-  withSTMResources qSize \ qs ->-    interpretQueues qs $-    withAsync_ (readQueue discardWhenFull (getStderr prc)) $-    withAsync_ (readQueue discardWhenFull (getStdout prc)) $-    withAsync_ (writeQueue (getStdin prc)) $-    insertAt @0 (f qs)--interpretProcessQueues ::-  Members [Resource, Race, Async, Embed IO] r =>-  ProcessQueues ->-  InterpreterFor (Process ByteString ByteString ByteString !! ProcessError) r-interpretProcessQueues qs =-  interpretQueues qs .-  interpretProcessWithQueues .-  raiseUnder3---- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,--- producing 'ByteString's.-interpretProcessIOE ::-  Members [Resource, Race, Async, Embed IO] r =>-  Bool ->-  Int ->-  ProcessConfig () () () ->-  InterpreterFor (Scoped ProcessQueues (Process ByteString ByteString ByteString !! ProcessError)) r-interpretProcessIOE discardWhenFull qSize config =-  interpretProcessNative (processWithQueues config) (withProcessResources discardWhenFull qSize) interpretProcessQueues
+ lib/Polysemy/Process/Interpreter/ProcessOutput.hs view
@@ -0,0 +1,51 @@+{-# options_haddock prune #-}++-- |Description: ProcessOutput Interpreters, Internal+module Polysemy.Process.Interpreter.ProcessOutput where++import qualified Data.ByteString as ByteString++import Polysemy.Process.Effect.ProcessOutput (ProcessOutput (Chunk))++-- |Interpret 'ProcessOutput' by immediately emitting raw 'ByteString's without accumulation.+interpretProcessOutputId :: InterpreterFor (ProcessOutput ByteString) r+interpretProcessOutputId =+  interpret \case+    Chunk buffer new ->+      pure ([buffer <> new], "")+{-# inline interpretProcessOutputId #-}++splitLines :: ByteString -> ByteString -> ([ByteString], ByteString)+splitLines buffer new =+  second fold (foldr' folder ([], Nothing) parts)+  where+    parts =+      ByteString.split 10 (buffer <> new)+    folder a (z, Nothing) =+      (z, Just a)+    folder a (z, Just r) =+      (a : z, Just r)++-- |Interpret 'ProcessOutput' by emitting individual 'ByteString' lines of output.+interpretProcessOutputLines :: InterpreterFor (ProcessOutput ByteString) r+interpretProcessOutputLines =+  interpret \case+    Chunk buffer new ->+      pure (splitLines buffer new)+{-# inline interpretProcessOutputLines #-}++-- |Interpret 'ProcessOutput' by immediately emitting 'Text' without accumulation.+interpretProcessOutputText :: InterpreterFor (ProcessOutput Text) r+interpretProcessOutputText =+  interpret \case+    Chunk buffer new ->+      pure ([decodeUtf8 (buffer <> new)], "")+{-# inline interpretProcessOutputText #-}++-- |Interpret 'ProcessOutput' by emitting individual 'Text' lines of output.+interpretProcessOutputTextLines :: InterpreterFor (ProcessOutput Text) r+interpretProcessOutputTextLines =+  interpret \case+    Chunk buffer new ->+      pure (first (fmap decodeUtf8) (splitLines buffer new))+{-# inline interpretProcessOutputTextLines #-}
+ lib/Polysemy/Process/Interpreter/ProcessStdio.hs view
@@ -0,0 +1,80 @@+{-# options_haddock prune #-}++-- |Description: Process Interpreters for stdio, Internal+module Polysemy.Process.Interpreter.ProcessStdio where++import Polysemy.Conc.Effect.Race (Race)+import Polysemy.Conc.Effect.Scoped (Scoped)+import Polysemy.Resume (type (!!))+import System.Process.Typed (ProcessConfig)++import Polysemy.Process.Data.ProcessError (ProcessError)+import Polysemy.Process.Data.SystemProcessError (SystemProcessError)+import Polysemy.Process.Effect.Process (Process)+import Polysemy.Process.Interpreter.Process (+  interpretProcessByteString,+  interpretProcessByteStringLines,+  interpretProcessText,+  interpretProcessTextLines,+  )+import Polysemy.Process.Interpreter.SystemProcess (PipesProcess, interpretSystemProcessNative)++-- |Interpret 'Process' as a native 'Polysemy.Process.SystemProcess', producing unaccumulated chunks of 'ByteString'.+interpretProcessByteStringNative ::+  Members [Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.+  ProcessConfig () () () ->+  InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r+interpretProcessByteStringNative discard qSize conf =+  interpretSystemProcessNative conf .+  interpretProcessByteString @PipesProcess @SystemProcessError discard qSize .+  raiseUnder++-- |Interpret 'Process' as a native 'Polysemy.Process.SystemProcess', producing lines of 'ByteString'.+interpretProcessByteStringLinesNative ::+  Members [Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.+  ProcessConfig () () () ->+  InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r+interpretProcessByteStringLinesNative discard qSize conf =+  interpretSystemProcessNative conf .+  interpretProcessByteStringLines @PipesProcess @SystemProcessError discard qSize .+  raiseUnder++-- |Interpret 'Process' as a native 'Polysemy.Process.SystemProcess', producing unaccumulated chunks of 'Text'.+interpretProcessTextNative ::+  Members [Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.+  ProcessConfig () () () ->+  InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r+interpretProcessTextNative discard qSize conf =+  interpretSystemProcessNative conf .+  interpretProcessText @PipesProcess @SystemProcessError discard qSize .+  raiseUnder++-- |Interpret 'Process' as a native 'Polysemy.Process.SystemProcess', producing lines of 'Text'.+interpretProcessTextLinesNative ::+  Members [Resource, Race, Async, Embed IO] r =>+  -- |Whether to discard output chunks if the queue is full.+  Bool ->+  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.+  Int ->+  -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.+  ProcessConfig () () () ->+  InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r+interpretProcessTextLinesNative discard qSize conf =+  interpretSystemProcessNative conf .+  interpretProcessTextLines @PipesProcess @SystemProcessError discard qSize .+  raiseUnder
+ lib/Polysemy/Process/Interpreter/Pty.hs view
@@ -0,0 +1,58 @@+{-# options_haddock prune #-}++-- |Description: Pty Interpreters, Internal+module Polysemy.Process.Interpreter.Pty where++import Polysemy.Conc.Effect.Scoped (Scoped)+import Polysemy.Conc.Interpreter.Scoped (interpretScopedResumable)+import Polysemy.Resume (Stop, stopEitherWith, stopNote, type (!!))+import System.Posix (closeFd, fdToHandle, openPseudoTerminal)+import System.Posix.Pty (closePty, createPty, ptyDimensions, resizePty)++import Polysemy.Process.Data.PtyError (PtyError (PtyError))+import Polysemy.Process.Data.PtyResources (PtyResources (PtyResources, handle, primary, pty, secondary))+import Polysemy.Process.Effect.Pty (Cols (Cols), Pty (Handle, Resize, Size), Rows (Rows))++tryStop ::+  Members [Stop PtyError, Embed IO] r =>+  IO a ->+  Sem r a+tryStop =+  stopEitherWith PtyError <=< tryAny++acquirePty ::+  Member (Embed IO) r =>+  Sem (Stop PtyError : r) PtyResources+acquirePty = do+  (primary, secondary) <- tryStop openPseudoTerminal+  pty <- stopNote (PtyError "no pty returned") =<< tryStop (createPty secondary)+  handle <- tryStop (fdToHandle secondary)+  pure PtyResources {..}++releasePty ::+  Member (Embed IO) r =>+  PtyResources ->+  Sem r ()+releasePty PtyResources {primary, pty} = do+  ignoreException (closePty pty)+  ignoreException (closeFd primary)++withPty ::+  Members [Resource, Embed IO] r =>+  (PtyResources -> Sem (Stop PtyError : r) a) ->+  Sem (Stop PtyError : r) a+withPty =+  bracket acquirePty releasePty++-- |Interpret Pty as a 'System.Posix.Pty'.+interpretPty ::+  Members [Resource, Embed IO] r =>+  InterpreterFor (Scoped PtyResources Pty !! PtyError) r+interpretPty =+  interpretScopedResumable withPty \ PtyResources {..} -> \case+    Handle ->+      pure handle+    Resize rows cols -> do+      tryStop (resizePty pty (fromIntegral rows, fromIntegral cols))+    Size ->+      bimap Rows Cols <$> tryStop (ptyDimensions pty)
+ lib/Polysemy/Process/Interpreter/SystemProcess.hs view
@@ -0,0 +1,186 @@+{-# options_haddock prune #-}++-- |Description: SystemProcess Interpreters, Internal+module Polysemy.Process.Interpreter.SystemProcess where++import Data.ByteString (hGetSome, hPut)+import Polysemy.Conc.Effect.Scoped (Scoped)+import Polysemy.Conc.Interpreter.Scoped (runScoped)+import Polysemy.Resume (Stop, interpretResumable, stop, stopNote, type (!!))+import Prelude hiding (fromException)+import System.IO (BufferMode (NoBuffering), Handle, hSetBuffering)+import qualified System.Posix as Signal+import System.Process (Pid, getPid)+import System.Process.Typed (+  Process,+  ProcessConfig,+  createPipe,+  getStderr,+  getStdin,+  getStdout,+  setStderr,+  setStdin,+  setStdout,+  startProcess,+  stopProcess,+  unsafeProcessHandle,+  waitExitCode,+  )++import qualified Polysemy.Process.Data.SystemProcessError as SystemProcessError+import Polysemy.Process.Data.SystemProcessError (SystemProcessError)+import qualified Polysemy.Process.Effect.SystemProcess as SystemProcess+import Polysemy.Process.Effect.SystemProcess (SystemProcess)++type PipesProcess =+  Process Handle Handle Handle++processWithPipes :: ProcessConfig () () () -> ProcessConfig Handle Handle Handle+processWithPipes =+  setStdin createPipe .+  setStdout createPipe .+  setStderr createPipe++start ::+  Member (Embed IO) r =>+  ProcessConfig () () () ->+  Sem r PipesProcess+start =+  startProcess . processWithPipes++withProcess ::+  Members [Resource, Embed IO] r =>+  ProcessConfig () () () ->+  (PipesProcess -> Sem r a) ->+  Sem r a+withProcess config use =+  bracket (start config) (tryAny . stopProcess) \ p -> do+    unbuffer (getStdin p)+    unbuffer (getStdout p)+    unbuffer (getStderr p)+    use p+  where+    unbuffer h =+      void $ tryMaybe (hSetBuffering h NoBuffering)++startOpaque ::+  Member (Embed IO) r =>+  ProcessConfig i o e ->+  Sem r (Process i o e)+startOpaque =+  startProcess++withProcessOpaque ::+  Members [Resource, Embed IO] r =>+  ProcessConfig i o e ->+  (Process i o e -> Sem r a) ->+  Sem r a+withProcessOpaque config =+  bracket (startOpaque config) (tryAny . stopProcess)++terminate ::+  Member (Stop SystemProcessError) r =>+  Text ->+  Maybe a ->+  Sem r a+terminate msg =+  stopNote (SystemProcessError.Terminated msg)++tryStop ::+  Members [Stop SystemProcessError, Embed IO] r =>+  Text ->+  IO a ->+  Sem r a+tryStop msg =+  terminate msg <=< tryMaybe++processId ::+  Members [Stop SystemProcessError, Embed IO] r =>+  Process i o e ->+  Sem r Pid+processId process =+  terminate "getPid returned Nothing" =<< embed (getPid (unsafeProcessHandle process))++-- |Interpret 'SystemProcess' with a concrete 'System.Process' with connected pipes.+interpretSystemProcessWithProcess ::+  ∀ r .+  Member (Embed IO) r =>+  Process Handle Handle Handle ->+  InterpreterFor (SystemProcess !! SystemProcessError) r+interpretSystemProcessWithProcess process =+  interpretResumable \case+    SystemProcess.Pid ->+      processId process+    SystemProcess.Signal sig -> do+      pid <- processId process+      tryStop "signal failed" (Signal.signalProcess sig pid)+    SystemProcess.ReadStdout ->+      tryStop "stdout failed" (hGetSome (getStdout process) 4096)+    SystemProcess.ReadStderr ->+      tryStop "stderr failed" (hGetSome (getStderr process) 4096)+    SystemProcess.WriteStdin msg ->+      tryStop "stdin failed" (hPut (getStdin process) msg)+    SystemProcess.Wait ->+      tryStop "wait failed" (waitExitCode process)++-- |Interpret 'SystemProcess' as a single global 'System.Process' that's started immediately.+interpretSystemProcessNativeSingle ::+  ∀ r .+  Members [Resource, Embed IO] r =>+  ProcessConfig () () () ->+  InterpreterFor (SystemProcess !! SystemProcessError) r+interpretSystemProcessNativeSingle config sem =+  withProcess config \ process ->+    interpretSystemProcessWithProcess process sem++-- |Interpret 'SystemProcess' as a scoped 'System.Process' that's started wherever 'Polysemy.Process.withSystemProcess'+-- is called and terminated when the wrapped action finishes.+interpretSystemProcessNative ::+  ∀ r .+  Members [Resource, Embed IO] r =>+  ProcessConfig () () () ->+  InterpreterFor (Scoped PipesProcess (SystemProcess !! SystemProcessError)) r+interpretSystemProcessNative config =+  runScoped (withProcess config) interpretSystemProcessWithProcess++-- |Interpret 'SystemProcess' with a concrete 'System.Process' with connected pipes.+interpretSystemProcessWithProcessOpaque ::+  ∀ i o e r .+  Member (Embed IO) r =>+  Process i o e ->+  InterpreterFor (SystemProcess !! SystemProcessError) r+interpretSystemProcessWithProcessOpaque process =+  interpretResumable \case+    SystemProcess.Pid ->+      processId process+    SystemProcess.Signal sig -> do+      pid <- processId process+      tryStop "signal failed" (Signal.signalProcess sig pid)+    SystemProcess.ReadStdout ->+      stop SystemProcessError.NoPipes+    SystemProcess.ReadStderr ->+      stop SystemProcessError.NoPipes+    SystemProcess.WriteStdin _ ->+      stop SystemProcessError.NoPipes+    SystemProcess.Wait ->+      tryStop "wait failed" (waitExitCode process)++-- |Interpret 'SystemProcess' as a single global 'System.Process' that's started immediately.+interpretSystemProcessNativeOpaqueSingle ::+  ∀ i o e r .+  Members [Resource, Embed IO] r =>+  ProcessConfig i o e ->+  InterpreterFor (SystemProcess !! SystemProcessError) r+interpretSystemProcessNativeOpaqueSingle config sem =+  withProcessOpaque config \ process ->+    interpretSystemProcessWithProcessOpaque process sem++-- |Interpret 'SystemProcess' as a scoped 'System.Process' that's started wherever 'Polysemy.Process.withSystemProcess'+-- is called and terminated when the wrapped action finishes.+interpretSystemProcessNativeOpaque ::+  ∀ i o e r .+  Members [Resource, Embed IO] r =>+  ProcessConfig i o e ->+  InterpreterFor (Scoped (Process i o e) (SystemProcess !! SystemProcessError)) r+interpretSystemProcessNativeOpaque config =+  runScoped (withProcessOpaque config) interpretSystemProcessWithProcessOpaque
+ lib/Polysemy/Process/ProcessOutput.hs view
@@ -0,0 +1,17 @@+{-# options_haddock prune #-}++-- |The utility effect 'ProcessOutput' takes care of decoding process output, getting called by the+-- 'Polysemy.Process.Process' interpreters whenever a chunk was read, while accumulating chunks until they were decoded+-- successfully.+module Polysemy.Process.ProcessOutput (+  module Polysemy.Process.Effect.ProcessOutput,+  module Polysemy.Process.Interpreter.ProcessOutput,+) where++import Polysemy.Process.Effect.ProcessOutput (ProcessOutput (Chunk), chunk)+import Polysemy.Process.Interpreter.ProcessOutput (+  interpretProcessOutputId,+  interpretProcessOutputLines,+  interpretProcessOutputText,+  interpretProcessOutputTextLines,+  )
+ lib/Polysemy/Process/Pty.hs view
@@ -0,0 +1,10 @@+{-# options_haddock prune #-}++-- |The effect 'Pty' abstracts pseudo terminals.+module Polysemy.Process.Pty (+  module Polysemy.Process.Effect.Pty,+  module Polysemy.Process.Interpreter.Pty,+) where++import Polysemy.Process.Effect.Pty (Pty (..), handle, resize, size, withPty)+import Polysemy.Process.Interpreter.Pty (interpretPty)
+ lib/Polysemy/Process/SystemProcess.hs view
@@ -0,0 +1,24 @@+{-# options_haddock prune #-}++-- |The effect 'SystemProcess' is a low-level abstraction of a native system process.+module Polysemy.Process.SystemProcess (+  module Polysemy.Process.Effect.SystemProcess,+  module Polysemy.Process.Interpreter.SystemProcess,+) where++import Polysemy.Process.Effect.SystemProcess (+  SystemProcess (..),+  interrupt,+  pid,+  readStderr,+  readStdout,+  signal,+  wait,+  withSystemProcess,+  writeStdin,+  )+import Polysemy.Process.Interpreter.SystemProcess (+  interpretSystemProcessNative,+  interpretSystemProcessNativeSingle,+  interpretSystemProcessWithProcess,+  )
polysemy-process.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.2 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.34.6. -- -- see: https://github.com/sol/hpack  name:           polysemy-process-version:        0.5.1.1+version:        0.6.0.0 synopsis:       Polysemy Effects for System Processes description:    See <https://hackage.haskell.org/package/polysemy-process/docs/Polysemy-Process.html> category:       Concurrency@@ -29,13 +29,22 @@   exposed-modules:       Polysemy.Process       Polysemy.Process.Data.ProcessError+      Polysemy.Process.Data.PtyError+      Polysemy.Process.Data.PtyResources+      Polysemy.Process.Data.SystemProcessError       Polysemy.Process.Effect.Process+      Polysemy.Process.Effect.ProcessOutput+      Polysemy.Process.Effect.Pty+      Polysemy.Process.Effect.SystemProcess+      Polysemy.Process.Executable       Polysemy.Process.Interpreter.Process-      Polysemy.Process.Interpreter.ProcessIOE-  other-modules:-      Paths_polysemy_process-  autogen-modules:-      Paths_polysemy_process+      Polysemy.Process.Interpreter.ProcessOutput+      Polysemy.Process.Interpreter.ProcessStdio+      Polysemy.Process.Interpreter.Pty+      Polysemy.Process.Interpreter.SystemProcess+      Polysemy.Process.ProcessOutput+      Polysemy.Process.Pty+      Polysemy.Process.SystemProcess   hs-source-dirs:       lib   default-extensions:@@ -96,27 +105,22 @@       UndecidableInstances       UnicodeSyntax       ViewPatterns-  ghc-options: -flate-specialise -fspecialise-aggressively -Wall -Wredundant-constraints+  ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wmissing-deriving-strategies -Widentities   build-depends:-      async-    , base ==4.*-    , bytestring-    , containers+      base ==4.*+    , incipit-core >=0.1.0.1+    , path >=0.7+    , path-io >=1.6.2     , polysemy >=1.6     , polysemy-conc-    , polysemy-resume >=0.2-    , polysemy-time >=0.1.4-    , relude >=0.7-    , stm+    , polysemy-resume >=0.3+    , posix-pty >=0.2+    , process     , stm-chans >=2-    , template-haskell-    , text-    , time-    , typed-process+    , typed-process >=0.2.6+    , unix   mixins:       base hiding (Prelude)-    , polysemy-conc hiding (Prelude)-    , polysemy-conc (Polysemy.Conc.Prelude as Prelude)   if impl(ghc >= 8.10)     ghc-options: -Wunused-packages   default-language: Haskell2010@@ -126,7 +130,6 @@   main-is: Main.hs   other-modules:       Polysemy.Process.Test.ProcessTest-      Paths_polysemy_process   hs-source-dirs:       test   default-extensions:@@ -187,10 +190,10 @@       UndecidableInstances       UnicodeSyntax       ViewPatterns-  ghc-options: -flate-specialise -fspecialise-aggressively -Wall -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wmissing-deriving-strategies -Widentities -threaded -rtsopts -with-rtsopts=-N   build-depends:       base ==4.*-    , bytestring+    , incipit-core     , polysemy     , polysemy-conc     , polysemy-plugin@@ -201,8 +204,6 @@     , typed-process   mixins:       base hiding (Prelude)-    , polysemy-conc hiding (Prelude)-    , polysemy-conc (Polysemy.Conc.Prelude as Prelude)   if impl(ghc >= 8.10)     ghc-options: -Wunused-packages   default-language: Haskell2010
readme.md view
@@ -1,8 +1,8 @@ # About -This library provides a few convenience [polysemy] effects for using STM queues, MVars, signal handling and racing.+This library provides [Polysemy] effects for system processes and pseudo terminals. -Please visit [hackage] for documentation.+Please visit [Hackage] for documentation. -[polysemy]: https://hackage.haskell.org/package/polysemy-[hackage]: https://hackage.haskell.org/package/polysemy-conc+[Polysemy]: https://hackage.haskell.org/package/polysemy+[Hackage]: https://hackage.haskell.org/package/polysemy-process/docs/Polysemy-Process.html
test/Polysemy/Process/Test/ProcessTest.hs view
@@ -2,31 +2,43 @@  module Polysemy.Process.Test.ProcessTest where -import qualified Data.ByteString as ByteString-import Polysemy.Async (asyncToIOFinal) import Polysemy.Conc.Interpreter.Race (interpretRace)-import Polysemy.Resume (resuming)+import Polysemy.Resume (resumeHoistError) import Polysemy.Test (UnitTest, runTestAuto, (===)) import qualified System.Process.Typed as Process import System.Process.Typed (ProcessConfig) +import Polysemy.Process.Data.ProcessError (ProcessError) import qualified Polysemy.Process.Effect.Process as Process import Polysemy.Process.Effect.Process (withProcess)-import Polysemy.Process.Interpreter.ProcessIOE (interpretProcessIOE)+import Polysemy.Process.Interpreter.ProcessStdio (interpretProcessByteStringNative, interpretProcessTextLinesNative)  config :: ProcessConfig () () () config =   Process.proc "cat" [] +messageLines :: [Text]+messageLines =+  replicate 4 "line"+ message :: ByteString message =-  ByteString.replicate 10 120+  encodeUtf8 (unlines messageLines)  test_process :: UnitTest test_process =-  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessIOE True 10 config do-    withProcess do-      response <- resuming (pure . show) do+  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessByteStringNative True 10 config do+    response <- resumeHoistError @ProcessError show do+      withProcess do         Process.send message         Process.recv-      message === response+    message === response++test_processLines :: UnitTest+test_processLines =+  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessTextLinesNative True 10 config do+    response <- resumeHoistError @ProcessError show do+      withProcess do+        Process.send message+        replicateM 4 Process.recv+    messageLines === response