diff --git a/README.md b/README.md index c96afc1a..71a3b1f6 100644 --- a/README.md +++ b/README.md @@ -169,8 +169,7 @@ enumerated explicitly. - `clojure.set` aliased as `set` - `clojure.edn` aliased as `edn`: - `read-string` -- `clojure.java.shell` aliases as `shell`: - - `sh` +- `clojure.java.shell` aliases as `shell` - `clojure.java.io` aliased as `io`: - `as-relative-path`, `as-url`, `copy`, `delete-file`, `file`, `input-stream`, `make-parents`, `output-stream`, `reader`, `resource`, `writer` diff --git a/src/babashka/impl/clojure/java/io.clj b/src/babashka/impl/clojure/java/io.clj index 88e7ec0c..5c26164b 100644 --- a/src/babashka/impl/clojure/java/io.clj +++ b/src/babashka/impl/clojure/java/io.clj @@ -1,4 +1,5 @@ (ns babashka.impl.clojure.java.io + {:no-doc true} (:require [clojure.java.io :as io])) (def io-namespace diff --git a/src/babashka/impl/clojure/java/shell.clj b/src/babashka/impl/clojure/java/shell.clj new file mode 100644 index 00000000..1d3aa429 --- /dev/null +++ b/src/babashka/impl/clojure/java/shell.clj @@ -0,0 +1,42 @@ +(ns babashka.impl.clojure.java.shell + {:no-doc true} + (:require [clojure.java.shell :as shell] + [sci.core :as sci])) + +(def sh-dir (sci/new-dynamic-var '*sh-dir* nil)) +(def sh-env (sci/new-dynamic-var '*sh-env* nil)) + +(defn with-sh-dir* + [_ _ dir & forms] + `(binding [clojure.java.shell/*sh-dir* ~dir] + ~@forms)) + +(defn with-sh-env* + [_ _ env & forms] + `(binding [clojure.java.shell/*sh-env* ~env] + ~@forms)) + +(defn parse-args + [args] + (let [default-encoding "UTF-8" ;; see sh doc string + default-opts {:out-enc default-encoding + :in-enc default-encoding + :dir @sh-dir + :env @sh-env} + [cmd opts] (split-with string? args) + opts (merge default-opts (apply hash-map opts)) + opts-seq (apply concat opts)] + (concat cmd opts-seq))) + +(defn sh [& args] + (let [args (parse-args args)] + (apply shell/sh args))) + +(def shell-namespace + {'*sh-dir* sh-dir + '*sh-env* sh-env + 'with-sh-dir (with-meta with-sh-dir* + {:sci/macro true}) + 'with-sh-env (with-meta with-sh-env* + {:sci/macro true}) + 'sh sh}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 8bdf6cc4..e6230073 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -7,6 +7,7 @@ [babashka.impl.classpath :as cp] [babashka.impl.clojure.core :refer [core-extras]] [babashka.impl.clojure.java.io :refer [io-namespace]] + [babashka.impl.clojure.java.shell :refer [shell-namespace]] [babashka.impl.clojure.stacktrace :refer [print-stack-trace]] [babashka.impl.csv :as csv] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] @@ -16,7 +17,6 @@ [babashka.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] - [clojure.java.shell :as shell] [clojure.string :as str] [sci.addons :as addons] [sci.core :as sci] @@ -218,7 +218,7 @@ Everything after that is bound to *command-line-args*.")) {'clojure.tools.cli tools-cli-namespace 'clojure.edn {'read edn/read 'read-string edn/read-string} - 'clojure.java.shell {'sh shell/sh} + 'clojure.java.shell shell-namespace 'babashka.wait {'wait-for-port wait/wait-for-port 'wait-for-path wait/wait-for-path} 'babashka.signal {'pipe-signal-received? pipe-signal-received?} diff --git a/test/babashka/impl/clojure/java/shell_test.clj b/test/babashka/impl/clojure/java/shell_test.clj new file mode 100644 index 00000000..0f1cd8db --- /dev/null +++ b/test/babashka/impl/clojure/java/shell_test.clj @@ -0,0 +1,17 @@ +(ns babashka.impl.clojure.java.shell-test + (:require [clojure.test :as t :refer [deftest is testing]] + [babashka.test-utils :as test-utils] + [clojure.string :as str])) + +(deftest with-sh-env-test + (is (= "\"BAR\"" + (str/trim (test-utils/bb nil " +(-> (shell/with-sh-env {:FOO \"BAR\"} + (shell/sh \"bash\" \"-c\" \"echo $FOO\")) + :out + str/trim)")))) + (is (str/includes? (str/trim (test-utils/bb nil " +(-> (shell/with-sh-dir \"logo\" + (shell/sh \"ls\")) + :out)")) + "icon.svg")))