From cdac4b173f1f8a1199eeb5674b75159400f71b8a Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Tue, 14 Nov 2023 04:57:12 -0600 Subject: [PATCH 1/3] Add note about stdin, pipe, and inherit See https://github.com/purescript/spago/issues/1048 --- src/Node/ChildProcess/Types.purs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Node/ChildProcess/Types.purs b/src/Node/ChildProcess/Types.purs index dd3a74b..073613c 100644 --- a/src/Node/ChildProcess/Types.purs +++ b/src/Node/ChildProcess/Types.purs @@ -26,7 +26,7 @@ module Node.ChildProcess.Types import Prelude import Data.Either (Either(..), either) -import Data.Function.Uncurried (Fn3, runFn3) +import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3) import Data.Nullable (Nullable, null) import Node.FS (FileDescriptor) import Node.Stream (Stream) @@ -44,6 +44,17 @@ foreign import data Handle :: Type -- | See https://nodejs.org/docs/latest-v18.x/api/child_process.html#optionsstdio foreign import data StdIO :: Type +-- | When used for X, then Y will exist on the child process where X and Y are +-- | - `stdio[0]` - `stdin` +-- | - `stdio[1]` - `stdout` +-- | - `stdio[2]` - `stderr` +-- | +-- | Note: when used with `stdin`, piping the parent stdin to this stream +-- | will not cause the child process to terminate when that parent stdin stream +-- | ends via `Ctrl+D` user input. Rather, the child process will hang +-- | until the parent process calls `Stream.end` on the child process' +-- | `stdin` stream. Since it's impossible to know when the user +-- | inputs `Ctrl+D`, `inherit` should be used instead. pipe :: StdIO pipe = unsafeCoerce "pipe" @@ -56,6 +67,15 @@ overlapped = unsafeCoerce "overlapped" ipc :: StdIO ipc = unsafeCoerce "ipc" +-- | Uses the parent's corresponding stream. +-- | +-- | Note: this value must be used for `stdin` if one +-- | wants to pipe the parent's `stdin` into the child process' `stdin` +-- | AND cause the child process to terminate when the user closes +-- | the parent's `stdin` via `Ctrl+D`. Using `pipe` instead +-- | will cause the child process to hang, even when `Ctrl+D` is pressed, +-- | until the parent process calls `Stream.end`, which cannot be reliably +-- | called the moment AFTER `Ctrl+D` is pressed. inherit :: StdIO inherit = unsafeCoerce "inherit" From b37cf7b7fa83e76a1f21c3d4776c62ae52c640b7 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Tue, 14 Nov 2023 05:07:51 -0600 Subject: [PATCH 2/3] Drop unused functions --- src/Node/ChildProcess/Types.purs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/ChildProcess/Types.purs b/src/Node/ChildProcess/Types.purs index 073613c..98f1370 100644 --- a/src/Node/ChildProcess/Types.purs +++ b/src/Node/ChildProcess/Types.purs @@ -26,7 +26,7 @@ module Node.ChildProcess.Types import Prelude import Data.Either (Either(..), either) -import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3) +import Data.Function.Uncurried (Fn3, runFn3) import Data.Nullable (Nullable, null) import Node.FS (FileDescriptor) import Node.Stream (Stream) From 95a34687b225a22fa52f13fd9f92c1c43493b326 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Tue, 14 Nov 2023 05:08:02 -0600 Subject: [PATCH 3/3] Add variant of waitSpawned --- src/Node/ChildProcess/Aff.purs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Node/ChildProcess/Aff.purs b/src/Node/ChildProcess/Aff.purs index 8eac411..8a43525 100644 --- a/src/Node/ChildProcess/Aff.purs +++ b/src/Node/ChildProcess/Aff.purs @@ -8,8 +8,9 @@ import Data.Maybe (fromJust) import Data.Posix (Pid) import Effect.Aff (Aff, effectCanceler, makeAff) import Effect.Ref as Ref -import Node.ChildProcess (ChildProcess, pid) -import Node.ChildProcess as CP +import Node.ChildProcess.Types (UnsafeChildProcess) +import Node.UnsafeChildProcess.Safe as CPSafe +import Node.ChildProcess (ChildProcess, toUnsafeChildProcess) import Node.Errors.SystemError (SystemError) import Node.EventEmitter (once) import Partial.Unsafe (unsafePartial) @@ -19,13 +20,22 @@ import Partial.Unsafe (unsafePartial) -- | and the `pid` of the process can be obtained. -- | If an `error` event fires, child process was not started successfully. waitSpawned :: ChildProcess -> Aff (Either SystemError Pid) -waitSpawned cp = parOneOf [ pidOnSpawn, errored ] +waitSpawned = toUnsafeChildProcess >>> waitSpawned' + +-- | Same as `waitSpawned` but works on `UnsafeChildProcess` +-- | +-- | Blocks until either a `spawn` or `error` event is fired. +-- | If a `spawn` event fired, child process was successfully started +-- | and the `pid` of the process can be obtained. +-- | If an `error` event fires, child process was not started successfully. +waitSpawned' :: UnsafeChildProcess -> Aff (Either SystemError Pid) +waitSpawned' cp = parOneOf [ pidOnSpawn, errored ] where pidOnSpawn = makeAff \done -> do ref <- Ref.new mempty - removeListener <- cp # once CP.spawnH do + removeListener <- cp # once CPSafe.spawnH do join $ Ref.read ref - pid' <- pid cp + pid' <- CPSafe.pid cp done $ Right $ Right $ unsafePartial $ fromJust pid' Ref.write removeListener ref pure $ effectCanceler do @@ -33,7 +43,7 @@ waitSpawned cp = parOneOf [ pidOnSpawn, errored ] errored = makeAff \done -> do ref <- Ref.new mempty - removeListener <- cp # once CP.errorH \sysErr -> do + removeListener <- cp # once CPSafe.errorH \sysErr -> do join $ Ref.read ref done $ Right $ Left sysErr Ref.write removeListener ref