From 2598c5e6b45f99226ecf61d655889ff18c340ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Ren=C3=A9=20Rideau?= Date: Mon, 23 Oct 2023 22:26:04 -0700 Subject: [PATCH] Test, tweak and document std/misc/process (#1022) --- doc/reference/std/misc/process.md | 54 +++++++++++++++++++++++++-- src/std/misc/ports-test.ss | 2 +- src/std/misc/process-test.ss | 62 +++++++++++++++++++++++++++++++ src/std/misc/process.ss | 23 ++++++++---- 4 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 src/std/misc/process-test.ss diff --git a/doc/reference/std/misc/process.md b/doc/reference/std/misc/process.md index ab4db65f7..d33b5e657 100644 --- a/doc/reference/std/misc/process.md +++ b/doc/reference/std/misc/process.md @@ -8,7 +8,7 @@ ## run-process ``` scheme (run-process cmd - [coprocess: read-all-as-string] + [coprocess: ...] [check-status: #t] [environment: #f] [directory: #f] @@ -16,7 +16,7 @@ [stdout-redirection: #t] [stderr-redirection: #f] [pseudo-terminal: #f] - [show-console: #f]) -> any | error + [show-console: ...]) -> any | error cmd := list of strings, [path . arguments] coprocess := procedure interacting with process @@ -38,7 +38,8 @@ The following keyword settings are available: - *coprocess*: A procedure that specifies how to interact with the process, which it receives as an argument, and what should be returned from `run-process`. Defaults to reading the whole output as a string via - `std/misc/ports#read-all-as-string`. + `std/misc/ports#read-all-as-string` if either `stdout-redirection` or + `stderr-redirection` is true, otherwise to `void`. - *check-status*: Declares how to handle the exit status of the process upon termination. If a procedure is provided, then it will be called with the process' exit status and a list of process creation arguments. If @@ -75,7 +76,7 @@ The following keyword settings are available: behave differently when they are used interactively, for example shells. - *show-console*: Applies to *Microsoft Windows*. It controls whether the process’ console window will be hidden or visible. The default value of this - setting is `#f` (i.e. hide the console window). + setting is true if any of the port redirection option is false. More information can be found in section `17.7.2 Process devices` of the Gambit manual. @@ -133,3 +134,48 @@ adding: file2.txt (stored 0%) adding: file3.txt (stored 0%) ``` ::: + +## invoke +``` scheme +(invoke program args + [stdout-redirection: #f] + [stderr-redirection: #f] + [stdin-redirection: #f] + [coprocess: ...] + [check-status: #t] + [environment: #f] + [directory: #f] + [show-console: ...] +``` + +Invoke a `program` with arguments `args`, in a way very similar to `run-process` above, +except that the program is specified separately from the arguments, +and the defaults for standard port redirections are different. + +::: tip Examples: +``` scheme +> (invoke "date" ["--utc"] stdout-redirection: #t coprocess: read-line) +``` +::: + +## filter-process +``` scheme +(filter-with-process command writer reader + [directory: #f] + [environment: #f]) +``` + +Invoke a Unix `command` to filter some data, wherein +the `writer` procedure takes an output port as argument and writes pre-filtered data to the port, +the `command` then filters the data, reading it from its standard input, +processing it and writing the filtered result to its standard output, +and the `reader` procedure takes an input port as argument and reads the filtered data from it. +The optional keyword arguments `directory:` and `environment:` are passed to `run-process`. + +::: tip Examples: +``` scheme +> (check (filter-with-process ["sh" "-c" "echo BEGIN ; cat ; echo END"] + (lambda (proc) (display "ab\ncd\nef\n" proc)) + read-all-as-lines) +("BEGIN" "ab" "cd" "ef" "END") +``` diff --git a/src/std/misc/ports-test.ss b/src/std/misc/ports-test.ss index 9b2b282cb..fad95cfc4 100644 --- a/src/std/misc/ports-test.ss +++ b/src/std/misc/ports-test.ss @@ -1,4 +1,4 @@ -(export ports-test) +(export #t) (import :std/error diff --git a/src/std/misc/process-test.ss b/src/std/misc/process-test.ss new file mode 100644 index 000000000..741575b5d --- /dev/null +++ b/src/std/misc/process-test.ss @@ -0,0 +1,62 @@ +(export process-test) + +(import + :gerbil/gambit + :std/error + :std/format + :std/misc/ports + :std/misc/process + :std/os/temporaries + :std/source + :std/sugar + :std/test + "./ports-test.ss") + +(def process-test + (test-suite "test :std/misc/process" + (test-case "run-process, run-process/batch, invoke" + (def dir (this-source-directory)) + (def (rp/i c . a) (apply invoke (car c) (cdr c) a)) + (defrule (checks/redir-coproc run ...) + (begin + (begin + (check (run ["echo" "ok" "1"] + stdin-redirection: #f stdout-redirection: #t stderr-redirection: #t) + => "ok 1\n") + (check (run ["echo" "ok" "1"] + stdin-redirection: #t stdout-redirection: #t stderr-redirection: #t) + => "ok 1\n") + (check (run ["sh" "-c" "echo foo bar; echo baz >&2"] + stdout-redirection: #t stderr-redirection: #f) + => "foo bar\n") + (check (run ["sh" "-c" "echo foo bar; echo baz >&2"] + stdout-redirection: #t stderr-redirection: #t) + => "foo bar\nbaz\n") + (check (run ["sh" "-c" "echo foo >&2 ; echo bar; echo baz >&2"] + coprocess: read-all-as-lines + stdout-redirection: #t stderr-redirection: #t) + => ["foo" "bar" "baz"]) + (check (run ["sh" "-c" "exit 0"] + coprocess: process-status) => 0) + (check (run ["sh" "-c" "exit 42"] + coprocess: process-status + check-status: true) => (* 42 256)) + (check (run ["true"] coprocess: process-status) => 0) + (check (run ["false"] coprocess: process-status check-status: true) => 256) + (check (run ["sh" "-c" "cat < ports-test.data ; echo bar baz >&2 ; exit 42"] + stdout-redirection: #t stderr-redirection: #f + directory: dir + check-status: (lambda (s _) (= s (* 42 256)))) + => test-data))...)) + (checks/redir-coproc run-process rp/i) + (defrule (checks/pass-fail run ...) + (begin + (begin + (check (begin (run ["true"]) 69) => 69) + (check-exception (run ["sh" "-c" "exit 42"]) process-error?) + (check-exception (run ["false"]) process-error?))...)) + (checks/pass-fail run-process run-process/batch rp/i)) + (test-case "filter-with-process" + (check (filter-with-process ["sh" "-c" "echo BEGIN ; cat ; echo END"] + (lambda (proc) (display "ab\ncd\nef\n" proc)) + read-all-as-lines) => ["BEGIN" "ab" "cd" "ef" "END"])))) diff --git a/src/std/misc/process.ss b/src/std/misc/process.ss index f878cfa3e..5088b9388 100644 --- a/src/std/misc/process.ss +++ b/src/std/misc/process.ss @@ -47,15 +47,16 @@ ;; That is also coherent with the above pseudo-terminal: default to #f, BTW. (def (run-process command - coprocess: (coprocess read-all-as-string) - check-status: (check-status #t) - environment: (environment #f) - directory: (directory #f) stdin-redirection: (stdin-redirection #t) stdout-redirection: (stdout-redirection #t) stderr-redirection: (stderr-redirection #f) + coprocess: (coprocess (if (or stdout-redirection stderr-redirection) read-all-as-string void)) + check-status: (check-status #t) + environment: (environment #f) + directory: (directory #f) pseudo-terminal: (pseudo-terminal #f) - show-console: (show-console #f)) ;; NB: default differs from Gambit. See above. + ;; NB: defaults for show-console differ from Gambit. See above. + show-console: (show-console #f)) (let* ((settings [path: (car command) arguments: (cdr command) @@ -94,7 +95,7 @@ stdout-redirection: (stdout-r #f) stderr-redirection: (stderr-r #f) stdin-redirection: (stdin-r #f) - coprocess: (coprocess (if stdout-r read-all-as-string void)) + coprocess: (coprocess (if (or stdout-r stderr-r) read-all-as-string void)) check-status: (check-status #t) environment: (environment #f) directory: (directory #f) @@ -103,6 +104,7 @@ stdout-redirection: stdout-r stderr-redirection: stderr-r stdin-redirection: stdin-r + coprocess: coprocess check-status: check-status environment: environment directory: directory @@ -111,9 +113,16 @@ ;; write data into a filter process and read some data back. ;; process-options as per open-process, except you should only use ;; path: arguments: directory: environment: -(def (filter-with-process command writer reader) +(def (filter-with-process command writer reader + directory: (directory #f) + environment: (environment #f)) (run-process command + stdin-redirection: #t + stdout-redirection: #t + stderr-redirection: #f + directory: directory + environment: environment coprocess: (lambda (process) (spawn/name