diff --git a/README.md b/README.md index 9793ec4c..0916e3a1 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ You may also download a binary from [Github](https://github.com/borkdude/babashk ## Usage ``` shellsession -Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] ( expression | -f | --socket-repl [host:]port ) +Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] ( -e | -f | --socket-repl [:] ) Options: @@ -108,9 +108,13 @@ Options: -o: write lines to stdout. -O: write EDN values to stdout. --stream: stream over lines or EDN values from stdin. Combined with -i or -I *in* becomes a single value per iteration. - --file or -f: read expressions from file instead of argument wrapped in an implicit do. + -e, --eval : evaluate an expression + -f, --file : evaluate a file --socket-repl: start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666). --time: print execution time before exiting. + +If neither -e, -f, or --socket-repl are specified, then the first argument that is not parsed as a option is treated as a file if it exists, or as an expression otherwise. +Everything after that is bound to *command-line-args*. ``` The `clojure.core` functions are accessible without a namespace alias. diff --git a/src/babashka/main.clj b/src/babashka/main.clj index a8209e44..6067dedc 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -101,7 +101,7 @@ (defn print-version [] (println (str "babashka v"(str/trim (slurp (io/resource "BABASHKA_VERSION")))))) -(def usage-string "Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] ( -e | -f | --socket-repl [host:]port )") +(def usage-string "Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] ( -e | -f | --socket-repl [:] )") (defn print-usage [] (println usage-string)) @@ -121,13 +121,13 @@ -o: write lines to stdout. -O: write EDN values to stdout. --stream: stream over lines or EDN values from stdin. Combined with -i or -I *in* becomes a single value per iteration. - -e, --eval expression: evaluate an expression - -f, --file path: evaluate a file + -e, --eval : evaluate an expression + -f, --file : evaluate a file --socket-repl: start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666). --time: print execution time before exiting. - If neither -e, -f, or --socket-repl are specified, then the first argument is treated as a file if it exists, or as an expression otherwise. -")) +If neither -e, -f, or --socket-repl are specified, then the first argument that is not parsed as a option is treated as a file if it exists, or as an expression otherwise. +Everything after that is bound to *command-line-args*.")) (defn read-file [file] (let [f (io/file file)] @@ -211,27 +211,27 @@ :else (try (let [expr (if file (read-file file) expression)] - (loop [in (read-next *in*)] - (let [ctx (update ctx :bindings assoc (with-meta '*in* - (when-not stream? - {:sci/deref! true})) in)] - (if (identical? ::EOF in) - [nil 0] ;; done streaming - (let [res [(do (when-not (or expression file) - (throw (Exception. (str args "Babashka expected an expression. Type --help to print help.")))) - (let [res (sci/eval-string expr ctx)] - (if (some? res) - (if-let [pr-f (cond shell-out println - edn-out prn)] - (if (coll? res) - (doseq [l res - :while (not (pipe-signal-received?))] - (pr-f l)) - (pr-f res)) - (prn res))))) 0]] - (if stream? - (recur (read-next *in*)) - res)))))) + (if expr + (loop [in (read-next *in*)] + (let [ctx (update ctx :bindings assoc (with-meta '*in* + (when-not stream? + {:sci/deref! true})) in)] + (if (identical? ::EOF in) + [nil 0] ;; done streaming + (let [res [(let [res (sci/eval-string expr ctx)] + (when (some? res) + (if-let [pr-f (cond shell-out println + edn-out prn)] + (if (coll? res) + (doseq [l res + :while (not (pipe-signal-received?))] + (pr-f l)) + (pr-f res)) + (prn res)))) 0]] + (if stream? + (recur (read-next *in*)) + res))))) + [(print-help) 1])) (catch Throwable e (binding [*out* *err*] (let [d (ex-data e) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index f6f52bbe..a4398840 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -101,8 +101,12 @@ (deftest malformed-command-line-args-test (is (thrown-with-msg? Exception #"File does not exist: non-existing\n" (bb nil "-f" "non-existing"))) - (is (thrown-with-msg? Exception #"expression" - (bb nil)))) + (testing "no arguments prints help" + (is (str/includes? + (try (test-utils/bb nil) + (catch clojure.lang.ExceptionInfo e + (:stdout (ex-data e)))) + "Usage:")))) (deftest ssl-test (let [graalvm-home (System/getenv "GRAALVM_HOME") diff --git a/test/babashka/test_utils.clj b/test/babashka/test_utils.clj index cff7da61..b5996386 100644 --- a/test/babashka/test_utils.clj +++ b/test/babashka/test_utils.clj @@ -6,15 +6,19 @@ (set! *warn-on-reflection* true) (defn bb-jvm [input & args] - (let [sw (java.io.StringWriter.) - res (binding [*err* sw] - (with-out-str - (if input + (let [es (java.io.StringWriter.) + os (java.io.StringWriter.)] + (binding [*err* es + *out* os] + (let [res (if input (with-in-str input (apply main/main args)) - (apply main/main args))))] - (if-let [err ^String (not-empty (str sw))] - (throw (Exception. err)) res))) + (apply main/main args))] + (if (zero? res) + (str os) + (throw (ex-info (str es) + {:stdout (str os) + :stderr (str es)}))))))) (defn bb-native [input & args] (let-programs [bb "./bb"]