From 7a1c9474af0287f80a568e9b160b2c2f9b234ca2 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 08:10:29 -0700 Subject: [PATCH 01/10] Update tests to Aff --- test/Main.purs | 116 +++++++++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/test/Main.purs b/test/Main.purs index 1215ea7..dba8fc1 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -2,75 +2,95 @@ module Test.Main where import Prelude -import Data.Either (hush) +import Data.Either (Either(..), hush) import Data.Maybe (Maybe(..)) import Data.Posix.Signal (Signal(..)) import Data.Posix.Signal as Signal import Effect (Effect) -import Effect.Console (log) +import Effect.Aff (Aff, effectCanceler, launchAff_, makeAff, nonCanceler) +import Effect.Class (liftEffect) +import Effect.Class.Console (log) import Node.Buffer as Buffer -import Node.ChildProcess (errorH, exec', execSync', exitH, kill, spawn, stdout) +import Node.ChildProcess (exec', execSync', kill, spawn, stdout) +import Node.ChildProcess as CP import Node.ChildProcess.Types (Exit(..), fromKillSignal) import Node.Encoding (Encoding(..)) import Node.Encoding as NE import Node.Errors.SystemError (code) -import Node.EventEmitter (on_) +import Node.EventEmitter (EventHandle, on_, once) import Node.Stream (dataH) main :: Effect Unit -main = do - log "spawns processes ok" +main = launchAff_ do spawnLs + nonExistentExecutable + noEffectsTooEarly + killsProcess + execLs + execSyncEcho "some value" - log "emits an error if executable does not exist" - nonExistentExecutable $ do - log "nonexistent executable: all good." +until + :: forall emitter psCb jsCb a + . emitter + -> EventHandle emitter psCb jsCb + -> ((a -> Effect Unit) -> psCb) + -> Aff a +until ee event cb = makeAff \done -> do + rm <- ee # once event (cb (done <<< Right)) + pure $ effectCanceler rm - log "doesn't perform effects too early" - spawn "ls" [ "-la" ] >>= \ls -> do - let _ = kill ls - ls # on_ exitH \exit -> - case exit of - Normally 0 -> - log "All good!" - _ -> do - log ("Bad exit: expected `Normally 0`, got: " <> show exit) +spawnLs :: Aff Unit +spawnLs = do + log "\nspawns processes ok" + ls <- liftEffect $ spawn "ls" [ "-la" ] + liftEffect $ (stdout ls) # on_ dataH (Buffer.toString UTF8 >=> log) + exit <- until ls CP.exitH \complete -> \exit -> complete exit + log $ "ls exited: " <> show exit - log "kills processes" - spawn "ls" [ "-la" ] >>= \ls -> do - _ <- kill ls - ls # on_ exitH \exit -> - case exit of - BySignal s | Just SIGTERM <- Signal.fromString =<< (hush $ fromKillSignal s) -> - log "All good!" - _ -> do - log ("Bad exit: expected `BySignal SIGTERM`, got: " <> show exit) +nonExistentExecutable :: Aff Unit +nonExistentExecutable = do + log "\nemits an error if executable does not exist" + ch <- liftEffect $ spawn "this-does-not-exist" [] + err <- until ch CP.errorH \complete -> \err -> complete err + log (code err) + log "nonexistent executable: all good." - log "exec" - execLs - -spawnLs :: Effect Unit -spawnLs = do - ls <- spawn "ls" [ "-la" ] - ls # on_ exitH \exit -> - log $ "ls exited: " <> show exit - (stdout ls) # on_ dataH (Buffer.toString UTF8 >=> log) +noEffectsTooEarly :: Aff Unit +noEffectsTooEarly = do + log "\ndoesn't perform effects too early" + ls <- liftEffect $ spawn "ls" [ "-la" ] + let _ = kill ls + exit <- until ls CP.exitH \complete -> \exit -> complete exit + case exit of + Normally 0 -> + log "All good!" + _ -> do + log ("Bad exit: expected `Normally 0`, got: " <> show exit) -nonExistentExecutable :: Effect Unit -> Effect Unit -nonExistentExecutable done = do - ch <- spawn "this-does-not-exist" [] - ch # on_ errorH \err -> - log (code err) *> done +killsProcess :: Aff Unit +killsProcess = do + log "\nkills processes" + ls <- liftEffect $ spawn "ls" [ "-la" ] + _ <- liftEffect $ kill ls + exit <- until ls CP.exitH \complete -> \exit -> complete exit + case exit of + BySignal s | Just SIGTERM <- Signal.fromString =<< (hush $ fromKillSignal s) -> + log "All good!" + _ -> do + log ("Bad exit: expected `BySignal SIGTERM`, got: " <> show exit) -execLs :: Effect Unit +execLs :: Aff Unit execLs = do - -- returned ChildProcess is ignored here - _ <- exec' "ls >&2" identity \r -> - log "redirected to stderr:" *> (Buffer.toString UTF8 r.stderr >>= log) - pure unit + log "\nexec" + r <- makeAff \done -> do + -- returned ChildProcess is ignored here + void $ exec' "ls >&2" identity (done <<< Right) + pure nonCanceler + log "redirected to stderr:" *> (liftEffect $ Buffer.toString UTF8 r.stderr >>= log) -execSyncEcho :: String -> Effect Unit -execSyncEcho str = do +execSyncEcho :: String -> Aff Unit +execSyncEcho str = liftEffect do + log "\nexecSyncEcho" buf <- Buffer.fromString str UTF8 resBuf <- execSync' "cat" (_ { input = Just buf }) res <- Buffer.toString NE.UTF8 resBuf From 962e214101acc12a361eb6992a82d8e003e5ee32 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 08:12:24 -0700 Subject: [PATCH 02/10] Add stdin write test --- test/Main.purs | 21 +++++++++++++++++++-- test/sleep.sh | 6 ++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 test/sleep.sh diff --git a/test/Main.purs b/test/Main.purs index dba8fc1..c3bb467 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -10,18 +10,22 @@ import Effect (Effect) import Effect.Aff (Aff, effectCanceler, launchAff_, makeAff, nonCanceler) import Effect.Class (liftEffect) import Effect.Class.Console (log) +import Effect.Exception (throwException) import Node.Buffer as Buffer -import Node.ChildProcess (exec', execSync', kill, spawn, stdout) +import Node.ChildProcess (exec', execSync', kill, spawn, stdin, stdout) import Node.ChildProcess as CP import Node.ChildProcess.Types (Exit(..), fromKillSignal) import Node.Encoding (Encoding(..)) import Node.Encoding as NE import Node.Errors.SystemError (code) -import Node.EventEmitter (EventHandle, on_, once) +import Node.EventEmitter (EventHandle, on_, once, once_) import Node.Stream (dataH) +import Node.Stream as Stream +import Unsafe.Coerce (unsafeCoerce) main :: Effect Unit main = launchAff_ do + writingToStdinWorks spawnLs nonExistentExecutable noEffectsTooEarly @@ -39,6 +43,19 @@ until ee event cb = makeAff \done -> do rm <- ee # once event (cb (done <<< Right)) pure $ effectCanceler rm +writingToStdinWorks :: Aff Unit +writingToStdinWorks = do + log "\nwriting to stdin works" + sp <- liftEffect $ spawn "sh" [ "./sleep.sh" ] + liftEffect do + buf <- Buffer.fromString "helllo" UTF8 + void $ Stream.write (stdin sp) buf + sp # once_ CP.errorH \err -> + throwException $ unsafeCoerce err + exit <- until sp CP.closeH \completeAff -> \exit -> + completeAff exit + log $ "spawn sleep done " <> show exit + spawnLs :: Aff Unit spawnLs = do log "\nspawns processes ok" diff --git a/test/sleep.sh b/test/sleep.sh new file mode 100644 index 0000000..f0e05a6 --- /dev/null +++ b/test/sleep.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +sleep 2000 +echo "$1" + +echo "Done" From 2eab69c11bd19143b332a9784fedad3795268a4a Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 08:12:33 -0700 Subject: [PATCH 03/10] Fix exit handler's string value --- src/Node/UnsafeChildProcess/Safe.purs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/UnsafeChildProcess/Safe.purs b/src/Node/UnsafeChildProcess/Safe.purs index 9fc9b22..da8d399 100644 --- a/src/Node/UnsafeChildProcess/Safe.purs +++ b/src/Node/UnsafeChildProcess/Safe.purs @@ -61,7 +61,7 @@ errorH :: EventHandle1 UnsafeChildProcess SystemError errorH = EventHandle "error" mkEffectFn1 exitH :: EventHandle UnsafeChildProcess (Exit -> Effect Unit) (EffectFn2 (Nullable Int) (Nullable KillSignal) Unit) -exitH = EventHandle "exitH" \cb -> mkEffectFn2 \code signal -> +exitH = EventHandle "exit" \cb -> mkEffectFn2 \code signal -> case toMaybe code, toMaybe signal of Just c, _ -> cb $ Normally c _, Just s -> cb $ BySignal s From 1908641b38fa7226b676008e6d3c8660f530ae19 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 08:13:48 -0700 Subject: [PATCH 04/10] Update module import to include 'node:' --- src/Node/UnsafeChildProcess/Unsafe.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/UnsafeChildProcess/Unsafe.js b/src/Node/UnsafeChildProcess/Unsafe.js index ba39b8a..3d5bac6 100644 --- a/src/Node/UnsafeChildProcess/Unsafe.js +++ b/src/Node/UnsafeChildProcess/Unsafe.js @@ -16,7 +16,7 @@ export { spawnSync as spawnSyncOptsImpl, fork as forkImpl, fork as forkOptsImpl, -} from "child_process"; +} from "node:child_process"; export const unsafeStdin = (cp) => cp.stdin; export const unsafeStdout = (cp) => cp.stdout; From 087ad9fd9362076923cad1db9519a19e974ef510 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 14:00:36 -0700 Subject: [PATCH 05/10] Fix path of stdin test --- test/Main.purs | 8 ++++++-- test/sleep.sh | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/Main.purs b/test/Main.purs index c3bb467..1da2313 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -46,11 +46,15 @@ until ee event cb = makeAff \done -> do writingToStdinWorks :: Aff Unit writingToStdinWorks = do log "\nwriting to stdin works" - sp <- liftEffect $ spawn "sh" [ "./sleep.sh" ] + sp <- liftEffect $ spawn "sh" [ "./test/sleep.sh" ] liftEffect do + (stdin sp) # once_ Stream.errorH \err -> do + log "Error in stdin" + throwException $ unsafeCoerce err buf <- Buffer.fromString "helllo" UTF8 void $ Stream.write (stdin sp) buf - sp # once_ CP.errorH \err -> + sp # once_ CP.errorH \err -> do + log "Error in child process" throwException $ unsafeCoerce err exit <- until sp CP.closeH \completeAff -> \exit -> completeAff exit diff --git a/test/sleep.sh b/test/sleep.sh index f0e05a6..39d9698 100644 --- a/test/sleep.sh +++ b/test/sleep.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -sleep 2000 +sleep 2 echo "$1" echo "Done" From 268ef0ab61deaf4a5c11a6b36957b42ccd0dafda Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 14:00:44 -0700 Subject: [PATCH 06/10] Add missing FFI --- src/Node/UnsafeChildProcess/Unsafe.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Node/UnsafeChildProcess/Unsafe.js b/src/Node/UnsafeChildProcess/Unsafe.js index 3d5bac6..a08766b 100644 --- a/src/Node/UnsafeChildProcess/Unsafe.js +++ b/src/Node/UnsafeChildProcess/Unsafe.js @@ -10,6 +10,7 @@ export { spawn as spawnImpl, spawn as spawnOptsImpl, execSync as execSyncImpl, + execSync as execSyncOptsImpl, execFileSync as execFileSyncImpl, execFileSync as execFileSyncOptsImpl, spawnSync as spawnSyncImpl, From 3e0222459861471332bac53f2dfd48d201f107f4 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 14:02:14 -0700 Subject: [PATCH 07/10] Drop `ipc` on sync fns (error); inline safeStdio --- src/Node/ChildProcess.purs | 21 ++++++++++----------- src/Node/UnsafeChildProcess/Safe.purs | 10 +--------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/Node/ChildProcess.purs b/src/Node/ChildProcess.purs index 6dc6017..8921441 100644 --- a/src/Node/ChildProcess.purs +++ b/src/Node/ChildProcess.purs @@ -86,7 +86,7 @@ module Node.ChildProcess import Prelude -import Data.Maybe (Maybe(..), fromMaybe, maybe) +import Data.Maybe (Maybe(..), fromMaybe) import Data.Nullable (Nullable, toMaybe, toNullable) import Data.Posix (Pid, Gid, Uid) import Data.Posix.Signal (Signal) @@ -97,12 +97,11 @@ import Effect.Uncurried (EffectFn2) import Foreign (Foreign) import Foreign.Object (Object) import Node.Buffer (Buffer) -import Node.ChildProcess.Types (Exit(..), Handle, KillSignal, Shell, StdIO, UnsafeChildProcess) +import Node.ChildProcess.Types (Exit(..), Handle, KillSignal, Shell, StdIO, UnsafeChildProcess, ipc, pipe) import Node.Errors.SystemError (SystemError) import Node.EventEmitter (EventEmitter, EventHandle) import Node.EventEmitter.UtilTypes (EventHandle0, EventHandle1) import Node.Stream (Readable, Writable) -import Node.UnsafeChildProcess.Safe (safeStdio) import Node.UnsafeChildProcess.Safe as SafeCP import Node.UnsafeChildProcess.Unsafe (unsafeSOBToBuffer) import Node.UnsafeChildProcess.Unsafe as UnsafeCP @@ -288,7 +287,7 @@ spawnSync' command args buildOpts = (UnsafeCP.spawnSync' command args opts) <#> } where opts = - { stdio: maybe safeStdio (\rest -> safeStdio <> rest) o.appendStdio + { stdio: [ pipe, pipe, pipe ] <> fromMaybe [] o.appendStdio , encoding: "buffer" , cwd: fromMaybe undefined o.cwd , input: fromMaybe undefined o.input @@ -328,7 +327,7 @@ spawn :: String -> Array String -> Effect ChildProcess -spawn cmd args = coerce $ UnsafeCP.spawn' cmd args { stdio: safeStdio } +spawn cmd args = coerce $ UnsafeCP.spawn cmd args -- | - `cwd` | Current working directory of the child process. -- | - `env` Environment key-value pairs. Default: process.env. @@ -367,7 +366,7 @@ spawn' spawn' cmd args buildOpts = coerce $ UnsafeCP.spawn' cmd args opts where opts = - { stdio: maybe safeStdio (\rest -> safeStdio <> rest) o.appendStdio + { stdio: [ pipe, pipe, pipe, ipc ] <> fromMaybe [] o.appendStdio , cwd: fromMaybe undefined o.cwd , env: fromMaybe undefined o.env , argv0: fromMaybe undefined o.argv0 @@ -452,7 +451,7 @@ execSync' cmd buildOpts = do , windowsHide: Nothing } opts = - { stdio: maybe safeStdio (\rest -> safeStdio <> rest) o.appendStdio + { stdio: [ pipe, pipe, pipe ] <> fromMaybe [] o.appendStdio , encoding: "buffer" , cwd: fromMaybe undefined o.cwd , input: fromMaybe undefined o.input @@ -550,7 +549,7 @@ execFileSync -> Array String -> Effect Buffer execFileSync file args = - map unsafeSOBToBuffer $ UnsafeCP.execFileSync' file args { stdio: safeStdio, encoding: "buffer" } + map unsafeSOBToBuffer $ UnsafeCP.execFileSync' file args { encoding: "buffer" } -- | - `cwd` | Current working directory of the child process. -- | - `input` | | | The value which will be passed as stdin to the spawned process. Supplying this value will override stdio[0]. @@ -585,7 +584,7 @@ execFileSync' file args buildOpts = map unsafeSOBToBuffer $ UnsafeCP.execFileSync' file args opts where opts = - { stdio: maybe safeStdio (\rest -> safeStdio <> rest) o.appendStdio + { stdio: [ pipe, pipe, pipe ] <> fromMaybe [] o.appendStdio , encoding: "buffer" , cwd: fromMaybe undefined o.cwd , input: fromMaybe undefined o.input @@ -685,7 +684,7 @@ fork :: String -> Array String -> Effect ChildProcess -fork modulePath args = coerce $ UnsafeCP.fork' modulePath args { stdio: safeStdio } +fork modulePath args = coerce $ UnsafeCP.fork' modulePath args { stdio: [ pipe, pipe, pipe, ipc ] } -- | - `cwd` | Current working directory of the child process. -- | - `detached` Prepare child to run independently of its parent process. Specific behavior depends on the platform, see options.detached). @@ -724,7 +723,7 @@ fork' fork' modulePath args buildOpts = coerce $ UnsafeCP.fork' modulePath args opts where opts = - { stdio: maybe safeStdio (\rest -> safeStdio <> rest) o.appendStdio + { stdio: [ pipe, pipe, pipe, ipc ] <> fromMaybe [] o.appendStdio , cwd: fromMaybe undefined o.cwd , detached: fromMaybe undefined o.detached , env: fromMaybe undefined o.env diff --git a/src/Node/UnsafeChildProcess/Safe.purs b/src/Node/UnsafeChildProcess/Safe.purs index da8d399..10d42a4 100644 --- a/src/Node/UnsafeChildProcess/Safe.purs +++ b/src/Node/UnsafeChildProcess/Safe.purs @@ -24,7 +24,6 @@ module Node.UnsafeChildProcess.Safe , spawnFile , spawnArgs , stdio - , safeStdio ) where import Prelude @@ -37,7 +36,7 @@ import Data.Posix.Signal as Signal import Effect (Effect) import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, mkEffectFn2, runEffectFn1, runEffectFn2) import Foreign (Foreign) -import Node.ChildProcess.Types (Exit(..), Handle, KillSignal, StdIO, UnsafeChildProcess, intSignal, ipc, pipe, stringSignal) +import Node.ChildProcess.Types (Exit(..), Handle, KillSignal, StdIO, UnsafeChildProcess, intSignal, stringSignal) import Node.Errors.SystemError (SystemError) import Node.EventEmitter (EventEmitter, EventHandle(..)) import Node.EventEmitter.UtilTypes (EventHandle0, EventHandle1) @@ -149,10 +148,3 @@ foreign import spawnArgs :: UnsafeChildProcess -> Array String foreign import spawnFile :: UnsafeChildProcess -> String foreign import stdio :: UnsafeChildProcess -> Array StdIO - --- | Safe default configuration for an UnsafeChildProcess. --- | `[ pipe, pipe, pipe, ipc ]`. --- | Creates a new stream for `stdin`, `stdout`, and `stderr` --- | Also adds an IPC channel, even if it's not used. -safeStdio :: Array StdIO -safeStdio = [ pipe, pipe, pipe, ipc ] From 3cac254646fef06b9d9624c10f1e152f49cb03b9 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 14:07:06 -0700 Subject: [PATCH 08/10] Fix `fromKillSignalImpl` FFI arg order --- src/Node/ChildProcess/Types.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Node/ChildProcess/Types.js b/src/Node/ChildProcess/Types.js index 9a38154..995dc88 100644 --- a/src/Node/ChildProcess/Types.js +++ b/src/Node/ChildProcess/Types.js @@ -1,8 +1,8 @@ export const showKillSignal = (ks) => ks + ""; export const showShell = (shell) => shell + ""; -export const fromKillSignalImpl = (left, right, sig) => { +export const fromKillSignalImpl = (fromInt, fromStr, sig) => { const ty = typeof sig; - if (ty === "number") return right(sig | 0); - if (ty === "string") return left(sig); + if (ty === "number") return fromInt(sig | 0); + if (ty === "string") return fromStr(sig); throw new Error("Impossible. Got kill signal that was neither int nor string: " + sig); }; From d17188032fdef69345cb73547e7559b8044c5a84 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 14:13:27 -0700 Subject: [PATCH 09/10] Update tests --- test/Main.purs | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/test/Main.purs b/test/Main.purs index 1da2313..2b973f3 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -10,16 +10,15 @@ import Effect (Effect) import Effect.Aff (Aff, effectCanceler, launchAff_, makeAff, nonCanceler) import Effect.Class (liftEffect) import Effect.Class.Console (log) -import Effect.Exception (throwException) +import Effect.Exception (throw, throwException) import Node.Buffer as Buffer -import Node.ChildProcess (exec', execSync', kill, spawn, stdin, stdout) +import Node.ChildProcess (exec', execSync', kill, spawn, stdin) import Node.ChildProcess as CP +import Node.ChildProcess.Aff (waitSpawned) import Node.ChildProcess.Types (Exit(..), fromKillSignal) import Node.Encoding (Encoding(..)) import Node.Encoding as NE -import Node.Errors.SystemError (code) -import Node.EventEmitter (EventHandle, on_, once, once_) -import Node.Stream (dataH) +import Node.EventEmitter (EventHandle, once, once_) import Node.Stream as Stream import Unsafe.Coerce (unsafeCoerce) @@ -64,17 +63,24 @@ spawnLs :: Aff Unit spawnLs = do log "\nspawns processes ok" ls <- liftEffect $ spawn "ls" [ "-la" ] - liftEffect $ (stdout ls) # on_ dataH (Buffer.toString UTF8 >=> log) - exit <- until ls CP.exitH \complete -> \exit -> complete exit - log $ "ls exited: " <> show exit + res <- waitSpawned ls + case res of + Right pid -> log $ "ls successfully spawned with PID: " <> show pid + Left err -> liftEffect $ throwException $ unsafeCoerce err + exit <- until ls CP.closeH \complete -> \exit -> complete exit + case exit of + Normally 0 -> log $ "ls exited with 0" + Normally i -> liftEffect $ throw $ "ls had non-zero exit: " <> show i + BySignal sig -> liftEffect $ throw $ "ls exited with sig: " <> show sig nonExistentExecutable :: Aff Unit nonExistentExecutable = do log "\nemits an error if executable does not exist" ch <- liftEffect $ spawn "this-does-not-exist" [] - err <- until ch CP.errorH \complete -> \err -> complete err - log (code err) - log "nonexistent executable: all good." + res <- waitSpawned ch + case res of + Left _ -> log "nonexistent executable: all good." + Right pid -> liftEffect $ throw $ "nonexistent executable started with PID: " <> show pid noEffectsTooEarly :: Aff Unit noEffectsTooEarly = do @@ -85,8 +91,8 @@ noEffectsTooEarly = do case exit of Normally 0 -> log "All good!" - _ -> do - log ("Bad exit: expected `Normally 0`, got: " <> show exit) + _ -> + liftEffect $ throw $ "Bad exit: expected `Normally 0`, got: " <> show exit killsProcess :: Aff Unit killsProcess = do @@ -98,7 +104,7 @@ killsProcess = do BySignal s | Just SIGTERM <- Signal.fromString =<< (hush $ fromKillSignal s) -> log "All good!" _ -> do - log ("Bad exit: expected `BySignal SIGTERM`, got: " <> show exit) + liftEffect $ throw $ "Bad exit: expected `BySignal SIGTERM`, got: " <> show exit execLs :: Aff Unit execLs = do @@ -107,7 +113,13 @@ execLs = do -- returned ChildProcess is ignored here void $ exec' "ls >&2" identity (done <<< Right) pure nonCanceler - log "redirected to stderr:" *> (liftEffect $ Buffer.toString UTF8 r.stderr >>= log) + stdout' <- liftEffect $ Buffer.toString UTF8 r.stdout + stderr' <- liftEffect $ Buffer.toString UTF8 r.stderr + when (stdout' /= "") do + liftEffect $ throw $ "stdout should be redirected to stderr but had content: " <> show stdout' + when (stderr' == "") do + liftEffect $ throw $ "stderr should have content but was empty" + log "stdout was successfully redirected to stderr" execSyncEcho :: String -> Aff Unit execSyncEcho str = liftEffect do @@ -115,4 +127,6 @@ execSyncEcho str = liftEffect do buf <- Buffer.fromString str UTF8 resBuf <- execSync' "cat" (_ { input = Just buf }) res <- Buffer.toString NE.UTF8 resBuf - log res + when (str /= res) do + throw $ "cat did not output its input. \nGot: " <> show res <> "\nExpected: " <> show str + log "cat successfully re-outputted its input" From 52cadff9e1079d8adc8bedd667825e7467b24502 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 26 Jul 2023 14:23:14 -0700 Subject: [PATCH 10/10] Add changelog entry --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f57ef2b..4aaf070 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,22 @@ Bugfixes: Other improvements: +## [v12.0.0](https://github.com/purescript-node/purescript-node-child-process/releases/tag/v12.0.0) - 2023-07-26 + +Breaking changes: +- Removed `safeStdio` (#60 by @JordanMartinez) + + Turns out this isn't safe for `*Sync` functions. AFAIK, this isn't documented + in Node docs. + +Bugfixes: +- Fixed `exitH`'s String value for listener (#60 by @JordanMartinez) +- Added missing FFI for `execSync'` (#60 by @JordanMartinez) +- Fixed `fromKillSignal`'s FFI's arg order (#60 by @JordanMartinez) + +Other improvements: +- Update tests to actually throw if invalid state occurs (#60 by @JordanMartinez) + ## [v11.0.0](https://github.com/purescript-node/purescript-node-child-process/releases/tag/v11.0.0) - 2023-07-25 Breaking changes: