diff options
| author | 2026-02-19 20:54:19 -0600 | |
|---|---|---|
| committer | 2026-02-19 21:39:32 -0600 | |
| commit | a17483cd5ab58347d067fdc011d57f451a3b8038 (patch) | |
| tree | 265527e332aaf4f0bc7ea22b27f6b6d87c06ea9f | |
| parent | Update version tag (diff) | |
Add *pipefile* and *errexit* to sh-dsl.pipefail-errexit
These dynamic bindings are analogs to set -o pipefile and set -o errexit
| -rw-r--r-- | spork/declare-cc.janet | 1 | ||||
| -rw-r--r-- | spork/sh-dsl.janet | 29 | ||||
| -rw-r--r-- | test/suite-sh-dsl.janet | 25 |
3 files changed, 52 insertions, 3 deletions
diff --git a/spork/declare-cc.janet b/spork/declare-cc.janet index 288e0c7..7791b76 100644 --- a/spork/declare-cc.janet +++ b/spork/declare-cc.janet @@ -201,6 +201,7 @@ be run in the environment dictated by (dyn :modpath)." [&opt root-directory] (var errors-found 0) + # TODO - flycheck all tests before running them - fail quickly (defn dodir [dir] (each sub (sort (os/dir dir)) diff --git a/spork/sh-dsl.janet b/spork/sh-dsl.janet index f1cba4c..3f9b877 100644 --- a/spork/sh-dsl.janet +++ b/spork/sh-dsl.janet @@ -5,6 +5,9 @@ ### sh-dsl.janet ### +(defdyn *pipefail* "When set, the return value of a pipeline is the last non-zero exit code instead of the default right-most exit code") +(defdyn *errexit* "When set, error immediately if pipelines run with `$`, `$<`, or `$<_` return with a non-zero exit code.") + (def- parse-env-set-peg (peg/compile '(* '(to "=") "=" ':S*))) # Re-implements ev/go-gather @@ -40,6 +43,25 @@ # End ev/go-gather +(defn- last-nonzero + [xs] + (var ret 0) + (each x xs (when (not= 0 x) (set ret x))) + ret) + +(defn- pipeline-results + [xs] + (def status-codes (filter number? xs)) + (assert (next status-codes)) # we must have at least 1 status code + (let [rc (if (dyn *pipefail*) + (last-nonzero status-codes) + (last status-codes))] + (if (not= 0 rc) + (if (dyn *errexit*) + (error (string/format "non-zero exit code %v" rc)) + rc) + (last xs)))) + (defn- string-token [x] (if (bytes? x) (string x) @@ -73,6 +95,7 @@ (def procs @[]) (def fds @[]) (var pipein nil) + (var out nil) (defn getfd [f] (array/push fds f) f) (defer @@ -140,8 +163,10 @@ (ev/read final-pipe :all capture-buf) capture-buf))) - (def out (wait-thunks thunks)) - (if return-all out (last out)))) + (set out (wait-thunks thunks))) + + # Outside defer for better stack trace on error + (if return-all out (pipeline-results out))) ### ### DSL Parsing diff --git a/test/suite-sh-dsl.janet b/test/suite-sh-dsl.janet index fd5adbf..ec92ad1 100644 --- a/test/suite-sh-dsl.janet +++ b/test/suite-sh-dsl.janet @@ -31,6 +31,29 @@ # More pipes using just janet (def version (buffer janet/version "-" janet/build)) - (assert (deep= version ($<_ ,janet --version | ,janet -e '(prin (:read stdin :all)))) "janet pipe example")) + (assert (deep= version ($<_ ,janet --version | ,janet -e '(prin (:read stdin :all)))) "janet pipe example") + + # Pipefail + (setdyn *pipefail* true) + (assert ($< echo) "echo pipefail 1") + (assert (deep= @"hi\n" ($< echo hi)) "echo pipefail 2") + (assert (deep= @"hi" ($<_ echo hi)) "echo pipefail 3") + (assert (= 1 ($< ,janet -e "(os/exit 0)" | ,janet -e "(os/exit 1)" | ,janet -e "(os/exit 0)")) "pipefail 1") + + # Errexit + (setdyn *pipefail* false) + (setdyn *errexit* true) + (assert ($< echo) "echo errexit 1") + (assert (deep= @"hi\n" ($< echo hi)) "echo errexit 2") + (assert (deep= @"hi" ($<_ echo hi)) "echo errexit 3") + (assert-error "errexit grep" ($ echo hi | grep nope)) + + # Pipefail and Errexit + (setdyn *pipefail* true) + (assert ($< echo) "echo pipefail + errexit 1") + (assert (deep= @"hi\n" ($< echo hi)) "echo pipefail + errexit 2") + (assert (deep= @"hi" ($<_ echo hi)) "echo pipefail + errexit 3") + (assert-error "pipefail + errexit grep" ($ echo hi | grep nope)) + (assert-error "pipefail + errexit grep" ($ echo hi | grep nope | ,janet -e "(os/exit 0)"))) (end-suite) |
