diff --git a/doc/guide/README.md b/doc/guide/README.md index 854b25364..6e9d5107d 100644 --- a/doc/guide/README.md +++ b/doc/guide/README.md @@ -109,7 +109,7 @@ docker pull gerbil/gerbil:$(uname -m) To get to the REPL: ```bash -docker run -it gerbil/gebil:$(uname -m) +docker run -it gerbil/gerbil:$(uname -m) ``` To get a bash shell where you can compile programs: @@ -125,6 +125,6 @@ See the [Docker Gulde](docker.md) for additional information. You can install Gerbil using Nix. See [nix.md](nix.md) for more details. There are also Docker containers based on Nix, with some gerbil libraries also installed, -at `mukn/gerbil` (with the compiler) and `mukn/glow` (with many libraries installed) -(user `user` working in `/home`). +at `mukn/glow:devel` or `ghcr.io/glow-lang/glow:devel` with many libraries installed. + See the `scripts` directory of [Gerbil Clan](https://github.com/fare/gerbil-utils) for details. 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 diff --git a/src/std/text/char-set.ss b/src/std/text/char-set.ss index b2cc73b70..6e9ec25b3 100644 --- a/src/std/text/char-set.ss +++ b/src/std/text/char-set.ss @@ -65,11 +65,11 @@ (= c #x0D))) ;; #\return ;; Whitespace as defined by C, C++ and Python. +;; To the strict-whitespace above, add two characters: +;; #\vtab (vertical tab) C'\v' and #\page (page break, form feed) C'\f' ;; : Codepoint -> Bool (def-codepoint (ascii-whitespace? c) - (or (codepoint-strict-whitespace? c) - (= c #x0B) ;; #\vtab (vertical tab) C'\v' - (= c #x0C))) ;; #\page (page break, form feed) C'\f' + (or (= c #x20) (<= #x09 c #x0D))) ;; Whitespace as defined by the underlying Scheme implementation ;; For Gambit and thus Gerbil (so far), it is the union of ASCII whitespace diff --git a/src/tools/gxpkg.ss b/src/tools/gxpkg.ss index ab6d37479..01ac2c6a2 100644 --- a/src/tools/gxpkg.ss +++ b/src/tools/gxpkg.ss @@ -23,6 +23,7 @@ ;;; TODO: add private repos support (import :gerbil/gambit + :std/format :std/getopt :std/sugar :std/iter @@ -85,11 +86,9 @@ (def new-cmd (command 'new help: "create a new package template in the current directory" (option 'package "-p" "--package" - help: "the package prefix for your project; defaults to the current username" - default: (getenv "USER")) + help: "the package prefix for your project; defaults to the current username") (option 'name "-n" "--name" - help: "the package name; defaults to the current directory name" - default: (path-strip-directory (path-normalize* (current-directory)))) + help: "the package name; defaults to the current directory name") (option 'link "-l" "--link" help: "link this package with a public package name; for example: github.com/your-user/your-package"))) (def deps-cmd @@ -340,7 +339,12 @@ (force once) (force +pkg-root-dir+)))) -(def (pkg-new prefix name maybe-link) +(def (pkg-new package-prefix package-name maybe-link) + (def prefix (or package-prefix + (getenv "USER" #f) + (error "Package prefix not specified with -p or --package, and USER not defined"))) + (def name (or package-name + (path-strip-directory (path-normalize* (current-directory))))) (def (create-template file template . args) (call-with-output-file file (lambda (output)