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 +2/−0
- changelog.md +7/−0
- lib/Polysemy/Process.hs +92/−8
- lib/Polysemy/Process/Data/ProcessError.hs +1/−1
- lib/Polysemy/Process/Data/PtyError.hs +9/−0
- lib/Polysemy/Process/Data/PtyResources.hs +17/−0
- lib/Polysemy/Process/Data/SystemProcessError.hs +12/−0
- lib/Polysemy/Process/Effect/Process.hs +22/−7
- lib/Polysemy/Process/Effect/ProcessOutput.hs +20/−0
- lib/Polysemy/Process/Effect/Pty.hs +38/−0
- lib/Polysemy/Process/Effect/SystemProcess.hs +58/−0
- lib/Polysemy/Process/Executable.hs +48/−0
- lib/Polysemy/Process/Interpreter/Process.hs +215/−29
- lib/Polysemy/Process/Interpreter/ProcessIOE.hs +0/−172
- lib/Polysemy/Process/Interpreter/ProcessOutput.hs +51/−0
- lib/Polysemy/Process/Interpreter/ProcessStdio.hs +80/−0
- lib/Polysemy/Process/Interpreter/Pty.hs +58/−0
- lib/Polysemy/Process/Interpreter/SystemProcess.hs +186/−0
- lib/Polysemy/Process/ProcessOutput.hs +17/−0
- lib/Polysemy/Process/Pty.hs +10/−0
- lib/Polysemy/Process/SystemProcess.hs +24/−0
- polysemy-process.cabal +28/−27
- readme.md +4/−4
- test/Polysemy/Process/Test/ProcessTest.hs +21/−9
+ 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