From cca6a095d2b34b7e8b8f1f078e8e92819c420b90 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 19 Jul 2023 17:26:47 -0700 Subject: [PATCH 1/5] Add dep on event-emitter; update node deps --- bower.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index b6f5ad9..b1069ab 100644 --- a/bower.json +++ b/bower.json @@ -17,11 +17,12 @@ ], "dependencies": { "purescript-exceptions": "^6.0.0", + "purescript-node-event-emitter": "https://github.com/purescript-node/purescript-node-event-emitter.git#^3.0.0", "purescript-foreign": "^7.0.0", "purescript-foreign-object": "^4.0.0", "purescript-functions": "^6.0.0", - "purescript-node-fs": "^8.0.0", - "purescript-node-streams": "^7.0.0", + "purescript-node-fs": "^9.0.0", + "purescript-node-streams": "^8.0.0", "purescript-nullable": "^6.0.0", "purescript-posix-types": "^6.0.0", "purescript-unsafe-coerce": "^6.0.0" From 852a7fed84f277aae4a27823e77b88eafc672e99 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 19 Jul 2023 17:26:55 -0700 Subject: [PATCH 2/5] Migrate event handlers --- src/Node/ChildProcess.js | 44 -------------- src/Node/ChildProcess.purs | 115 ++++++++++++++----------------------- 2 files changed, 44 insertions(+), 115 deletions(-) diff --git a/src/Node/ChildProcess.js b/src/Node/ChildProcess.js index b3ba75a..e5a11ca 100644 --- a/src/Node/ChildProcess.js +++ b/src/Node/ChildProcess.js @@ -46,50 +46,6 @@ export function fork(cmd) { return args => () => cp_fork(cmd, args); } -export function mkOnExit(mkChildExit) { - return function onExit(cp) { - return cb => () => { - cp.on("exit", (code, signal) => { - cb(mkChildExit(code)(signal))(); - }); - }; - }; -} - -export function mkOnClose(mkChildExit) { - return function onClose(cp) { - return cb => () => { - cp.on("close", (code, signal) => { - cb(mkChildExit(code)(signal))(); - }); - }; - }; -} - -export function onDisconnect(cp) { - return cb => () => { - cp.on("disconnect", cb); - }; -} - -export function mkOnMessage(nothing) { - return just => (function onMessage(cp) { - return cb => () => { - cp.on("message", (mess, sendHandle) => { - cb(mess, sendHandle ? just(sendHandle) : nothing)(); - }); - }; - }); -} - -export function onError(cp) { - return cb => () => { - cp.on("error", err => { - cb(err)(); - }); - }; -} - const _undefined = undefined; export { _undefined as undefined }; import process from "process"; diff --git a/src/Node/ChildProcess.purs b/src/Node/ChildProcess.purs index 632e531..a225ce2 100644 --- a/src/Node/ChildProcess.purs +++ b/src/Node/ChildProcess.purs @@ -14,6 +14,13 @@ module Node.ChildProcess ( Handle , ChildProcess + , toEventEmitter + , closeH + , disconnectH + , errorH + , exitH + , messageH + , spawnH , stdin , stdout , stderr @@ -25,11 +32,6 @@ module Node.ChildProcess , Error , toStandardError , Exit(..) - , onExit - , onClose - , onDisconnect - , onMessage - , onError , spawn , SpawnOptions , defaultSpawnOptions @@ -51,22 +53,24 @@ module Node.ChildProcess import Prelude -import Control.Alt ((<|>)) import Data.Function.Uncurried (Fn2, runFn2) import Data.Maybe (Maybe(..), fromMaybe, maybe) -import Data.Nullable (Nullable, toNullable, toMaybe) +import Data.Nullable (Nullable, toMaybe, toNullable) import Data.Posix (Pid, Gid, Uid) import Data.Posix.Signal (Signal) import Data.Posix.Signal as Signal import Effect (Effect) import Effect.Exception as Exception -import Effect.Exception.Unsafe (unsafeThrow) +import Effect.Uncurried (EffectFn2, mkEffectFn1, mkEffectFn2) import Foreign (Foreign) import Foreign.Object (Object) import Node.Buffer (Buffer) import Node.Encoding (Encoding, encodingToNode) +import Node.EventEmitter (EventEmitter, EventHandle(..)) +import Node.EventEmitter.UtilTypes (EventHandle0, EventHandle1) import Node.FS as FS -import Node.Stream (Readable, Writable, Stream) +import Node.Stream (Readable, Stream, Writable) +import Partial.Unsafe (unsafeCrashWith) import Unsafe.Coerce (unsafeCoerce) -- | A handle for inter-process communication (IPC). @@ -74,8 +78,39 @@ foreign import data Handle :: Type -- | Opaque type returned by `spawn`, `fork` and `exec`. -- | Needed as input for most methods in this module. +-- | +-- | `ChildProcess` extends `EventEmitter` newtype ChildProcess = ChildProcess ChildProcessRec +toEventEmitter :: ChildProcess -> EventEmitter +toEventEmitter = unsafeCoerce + +closeH :: EventHandle ChildProcess (Exit -> Effect Unit) (EffectFn2 (Nullable Int) (Nullable String) Unit) +closeH = EventHandle "close" \cb -> mkEffectFn2 \code signal -> + case toMaybe code, toMaybe signal >>= Signal.fromString of + Just c, _ -> cb $ Normally c + _, Just s -> cb $ BySignal s + _, _ -> unsafeCrashWith $ "Impossible. 'close' event did not get an exit code or kill signal: " <> show code <> "; " <> show signal + +disconnectH :: EventHandle0 ChildProcess +disconnectH = EventHandle "disconnect" identity + +errorH :: EventHandle1 ChildProcess Error +errorH = EventHandle "error" mkEffectFn1 + +exitH :: EventHandle ChildProcess (Exit -> Effect Unit) (EffectFn2 (Nullable Int) (Nullable String) Unit) +exitH = EventHandle "exitH" \cb -> mkEffectFn2 \code signal -> + case toMaybe code, toMaybe signal >>= Signal.fromString of + Just c, _ -> cb $ Normally c + _, Just s -> cb $ BySignal s + _, _ -> unsafeCrashWith $ "Impossible. 'exit' event did not get an exit code or kill signal: " <> show code <> "; " <> show signal + +messageH :: EventHandle ChildProcess (Foreign -> Maybe Handle -> Effect Unit) (EffectFn2 Foreign (Nullable Handle) Unit) +messageH = EventHandle "message" \cb -> mkEffectFn2 \a b -> cb a $ toMaybe b + +spawnH :: EventHandle0 ChildProcess +spawnH = EventHandle "spawn" identity + runChildProcess :: ChildProcess -> ChildProcessRec runChildProcess (ChildProcess r) = r @@ -165,68 +200,6 @@ instance showExit :: Show Exit where show (Normally x) = "Normally " <> show x show (BySignal sig) = "BySignal " <> show sig -mkExit :: Nullable Int -> Nullable String -> Exit -mkExit code signal = - case fromCode code <|> fromSignal signal of - Just e -> e - Nothing -> unsafeThrow "Node.ChildProcess.mkExit: Invalid arguments" - where - fromCode = toMaybe >>> map Normally - fromSignal = toMaybe >=> Signal.fromString >>> map BySignal - --- | Handle the `"exit"` signal. -onExit - :: ChildProcess - -> (Exit -> Effect Unit) - -> Effect Unit -onExit = mkOnExit mkExit - -foreign import mkOnExit - :: (Nullable Int -> Nullable String -> Exit) - -> ChildProcess - -> (Exit -> Effect Unit) - -> Effect Unit - --- | Handle the `"close"` signal. -onClose - :: ChildProcess - -> (Exit -> Effect Unit) - -> Effect Unit -onClose = mkOnClose mkExit - -foreign import mkOnClose - :: (Nullable Int -> Nullable String -> Exit) - -> ChildProcess - -> (Exit -> Effect Unit) - -> Effect Unit - --- | Handle the `"message"` signal. -onMessage - :: ChildProcess - -> (Foreign -> Maybe Handle -> Effect Unit) - -> Effect Unit -onMessage = mkOnMessage Nothing Just - -foreign import mkOnMessage - :: forall a - . Maybe a - -> (a -> Maybe a) - -> ChildProcess - -> (Foreign -> Maybe Handle -> Effect Unit) - -> Effect Unit - --- | Handle the `"disconnect"` signal. -foreign import onDisconnect - :: ChildProcess - -> Effect Unit - -> Effect Unit - --- | Handle the `"error"` signal. -foreign import onError - :: ChildProcess - -> (Error -> Effect Unit) - -> Effect Unit - -- | Spawn a child process. Note that, in the event that a child process could -- | not be spawned (for example, if the executable was not found) this will -- | not throw an error. Instead, the `ChildProcess` will be created anyway, From 08559b91611cdd156ff4f11f83b10d45a0e00e2c Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 19 Jul 2023 17:28:31 -0700 Subject: [PATCH 3/5] Update tests --- test/Main.purs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/Main.purs b/test/Main.purs index e8941c5..a07337b 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -7,10 +7,11 @@ import Data.Posix.Signal (Signal(..)) import Effect (Effect) import Effect.Console (log) import Node.Buffer as Buffer -import Node.ChildProcess (Exit(..), defaultExecOptions, exec, defaultExecSyncOptions, execSync, onError, defaultSpawnOptions, spawn, stdout, onExit, kill) +import Node.ChildProcess (Exit(..), defaultExecOptions, defaultExecSyncOptions, defaultSpawnOptions, errorH, exec, execSync, exitH, kill, spawn, stdout) import Node.Encoding (Encoding(UTF8)) import Node.Encoding as NE -import Node.Stream (onData) +import Node.EventEmitter (on_) +import Node.Stream (dataH) main :: Effect Unit main = do @@ -24,7 +25,7 @@ main = do log "doesn't perform effects too early" spawn "ls" [ "-la" ] defaultSpawnOptions >>= \ls -> do let _ = kill SIGTERM ls - onExit ls \exit -> + ls # on_ exitH \exit -> case exit of Normally 0 -> log "All good!" @@ -34,7 +35,7 @@ main = do log "kills processes" spawn "ls" [ "-la" ] defaultSpawnOptions >>= \ls -> do _ <- kill SIGTERM ls - onExit ls \exit -> + ls # on_ exitH \exit -> case exit of BySignal SIGTERM -> log "All good!" @@ -47,14 +48,15 @@ main = do spawnLs :: Effect Unit spawnLs = do ls <- spawn "ls" [ "-la" ] defaultSpawnOptions - onExit ls \exit -> + ls # on_ exitH \exit -> log $ "ls exited: " <> show exit - onData (stdout ls) (Buffer.toString UTF8 >=> log) + (stdout ls) # on_ dataH (Buffer.toString UTF8 >=> log) nonExistentExecutable :: Effect Unit -> Effect Unit nonExistentExecutable done = do ch <- spawn "this-does-not-exist" [] defaultSpawnOptions - onError ch (\err -> log err.code *> done) + ch # on_ errorH \err -> + log err.code *> done execLs :: Effect Unit execLs = do From 2e2b4cd0b01c03ac6de9e386c6060295150b598f Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 19 Jul 2023 17:31:02 -0700 Subject: [PATCH 4/5] Add changelog entry --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86ecef1..234d128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ Notable changes to this project are documented in this file. The format is based ## [Unreleased] Breaking changes: +- Migrate `onEvent`-style event handlers to `eventH`-style (#43 by @JordanMartinez) + + ```purs + -- Before + onExit cp case _ of + Normally exitCode -> ... + BySignal signal -> ... + + -- After + cp # on_ exitH case _ of + Normally exitCode -> ... + BySignal signal -> ... + ``` + See https://pursuit.purescript.org/packages/purescript-node-event-emitter/3.0.0/docs/Node.EventEmitter for more details. + New features: From 22458769ff97eb13ddfd322e84eb18be9fe13ec0 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Wed, 19 Jul 2023 17:31:29 -0700 Subject: [PATCH 5/5] Add entry for 'spawn' event --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 234d128..a8e5bd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Breaking changes: New features: +- Added event handler for `spawn` event (#43 by @JordanMartinez) Bugfixes: