Compare commits
86 commits
master
...
task-runne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1bf6692d0 | ||
|
|
ed40991c56 | ||
|
|
5444ce43a6 | ||
|
|
0ff97a17f3 | ||
|
|
ce63407f1e | ||
|
|
ab3b4fa53a | ||
|
|
d8cd25a84d | ||
|
|
c4d8e4de4c | ||
|
|
f02bf19e80 | ||
|
|
235adfcfe5 | ||
|
|
344ce2dca7 | ||
|
|
6ecc70710e | ||
|
|
1eedff98b6 | ||
|
|
806c9109e1 | ||
|
|
1b0688a02d | ||
|
|
d4287f353e | ||
|
|
283d6db591 | ||
|
|
518e430930 | ||
|
|
3b39ccfe1d | ||
|
|
5c6bbb4b0f | ||
|
|
c53a0b079b | ||
|
|
55be656d82 | ||
|
|
a3f7cebd15 | ||
|
|
c2829fe34d | ||
|
|
035167ab11 | ||
|
|
e4d82b87be | ||
|
|
6e58278f9d | ||
|
|
f7457e64d2 | ||
|
|
29f4452fef | ||
|
|
4617076104 | ||
|
|
6abe9a6851 | ||
|
|
b69ec8fc17 | ||
|
|
5a1b69953b | ||
|
|
3c0900563c | ||
|
|
be47d673f5 | ||
|
|
289c589215 | ||
|
|
3e860722f0 | ||
|
|
f554a32dff | ||
|
|
a8319d42c1 | ||
|
|
423789a8a9 | ||
|
|
4a58ad8c9f | ||
|
|
9b9c6f0d36 | ||
|
|
7cc4867212 | ||
|
|
3750ea0459 | ||
|
|
5b9e3c3267 | ||
|
|
200caef226 | ||
|
|
ff3d1e56ba | ||
|
|
f9f6fa8621 | ||
|
|
612edd6fc9 | ||
|
|
343c363319 | ||
|
|
6e4313700f | ||
|
|
a44f07a665 | ||
|
|
91106b5401 | ||
|
|
e6b211a030 | ||
|
|
e6905173b6 | ||
|
|
6a1d48460e | ||
|
|
07f5e811e6 | ||
|
|
70eb717d21 | ||
|
|
8f93826072 | ||
|
|
ca22e8fd04 | ||
|
|
5317020a24 | ||
|
|
aae8464fb9 | ||
|
|
c5ebffa7bf | ||
|
|
f0bdc28888 | ||
|
|
240c90a179 | ||
|
|
6515ef771a | ||
|
|
1160f44d22 | ||
|
|
644634be1d | ||
|
|
60e25043d4 | ||
|
|
40e7b739e9 | ||
|
|
9051d3aac7 | ||
|
|
afed99ad1b | ||
|
|
44f80f2a28 | ||
|
|
90443eed80 | ||
|
|
ef4969e54c | ||
|
|
e0dd41d631 | ||
|
|
55f38db119 | ||
|
|
4d77ee6446 | ||
|
|
d99f813fe8 | ||
|
|
adc5987162 | ||
|
|
ce62b47085 | ||
|
|
ae397e20e7 | ||
|
|
23834a5302 | ||
|
|
18219526e2 | ||
|
|
57aaed524d | ||
|
|
1f1b6cfde1 |
13 changed files with 716 additions and 225 deletions
4
bb.edn.bak
Normal file
4
bb.edn.bak
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{:paths ["test-resources/task_scripts"]
|
||||||
|
:tasks {:main-task {:task/type :main
|
||||||
|
:main tasks ;; this calls tasks/-main
|
||||||
|
:args [1 2 3]}}}
|
||||||
|
|
@ -67,8 +67,7 @@
|
||||||
:feature/hiccup
|
:feature/hiccup
|
||||||
:feature/test-check
|
:feature/test-check
|
||||||
:feature/spec-alpha
|
:feature/spec-alpha
|
||||||
{:dependencies [[clj-commons/conch "0.9.2"]
|
{:dependencies [[com.clojure-goes-fast/clj-async-profiler "0.4.1"]
|
||||||
[com.clojure-goes-fast/clj-async-profiler "0.4.1"]
|
|
||||||
[com.opentable.components/otj-pg-embedded "0.13.3"]]}]
|
[com.opentable.components/otj-pg-embedded "0.13.3"]]}]
|
||||||
:uberjar {:global-vars {*assert* false}
|
:uberjar {:global-vars {*assert* false}
|
||||||
:jvm-opts ["-Dclojure.compiler.direct-linking=true"
|
:jvm-opts ["-Dclojure.compiler.direct-linking=true"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@
|
||||||
resource-paths)))
|
resource-paths)))
|
||||||
|
|
||||||
(defn path-from-jar
|
(defn path-from-jar
|
||||||
[^java.io.File jar-file resource-paths {:keys [:url?]}]
|
[^java.io.File jar-file resource-paths opts]
|
||||||
|
(let [url? (:url? opts)]
|
||||||
(with-open [jar (JarFile. jar-file)]
|
(with-open [jar (JarFile. jar-file)]
|
||||||
(some (fn [path]
|
(some (fn [path]
|
||||||
(when-let [entry (.getEntry jar path)]
|
(when-let [entry (.getEntry jar path)]
|
||||||
|
|
@ -38,7 +39,7 @@
|
||||||
(str "file:" (.getAbsolutePath jar-file) "!/" path))
|
(str "file:" (.getAbsolutePath jar-file) "!/" path))
|
||||||
{:file path
|
{:file path
|
||||||
:source (slurp (.getInputStream jar entry))})))
|
:source (slurp (.getInputStream jar entry))})))
|
||||||
resource-paths)))
|
resource-paths))))
|
||||||
|
|
||||||
(deftype JarFileResolver [jar-file]
|
(deftype JarFileResolver [jar-file]
|
||||||
IResourceResolver
|
IResourceResolver
|
||||||
|
|
@ -57,8 +58,10 @@
|
||||||
(getResources [_ resource-paths opts]
|
(getResources [_ resource-paths opts]
|
||||||
(keep #(getResource % resource-paths opts) entries)))
|
(keep #(getResource % resource-paths opts) entries)))
|
||||||
|
|
||||||
|
(def path-sep (System/getProperty "path.separator"))
|
||||||
|
|
||||||
(defn loader [^String classpath]
|
(defn loader [^String classpath]
|
||||||
(let [parts (.split classpath (System/getProperty "path.separator"))
|
(let [parts (.split classpath path-sep)
|
||||||
entries (map part->entry parts)]
|
entries (map part->entry parts)]
|
||||||
(Loader. entries)))
|
(Loader. entries)))
|
||||||
|
|
||||||
|
|
@ -88,7 +91,7 @@
|
||||||
(fn [{:keys [:cp]}]
|
(fn [{:keys [:cp]}]
|
||||||
(let [new-cp
|
(let [new-cp
|
||||||
(if-not cp extra-classpath
|
(if-not cp extra-classpath
|
||||||
(str cp (System/getProperty "path.separator") extra-classpath))]
|
(str cp path-sep extra-classpath))]
|
||||||
{:loader (loader new-cp)
|
{:loader (loader new-cp)
|
||||||
:cp new-cp})))
|
:cp new-cp})))
|
||||||
nil)
|
nil)
|
||||||
|
|
@ -96,7 +99,7 @@
|
||||||
(defn split-classpath
|
(defn split-classpath
|
||||||
"Returns the classpath as a seq of strings, split by the platform
|
"Returns the classpath as a seq of strings, split by the platform
|
||||||
specific path separator."
|
specific path separator."
|
||||||
([^String cp] (vec (.split cp (System/getProperty "path.separator")))))
|
([^String cp] (vec (.split cp path-sep))))
|
||||||
|
|
||||||
(defn get-classpath
|
(defn get-classpath
|
||||||
"Returns the current classpath as set by --classpath, BABASHKA_CLASSPATH and add-classpath."
|
"Returns the current classpath as set by --classpath, BABASHKA_CLASSPATH and add-classpath."
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
ret#))
|
ret#))
|
||||||
|
|
||||||
(def data-readers (sci/new-dynamic-var '*data-readers* nil))
|
(def data-readers (sci/new-dynamic-var '*data-readers* nil))
|
||||||
|
(def command-line-args (sci/new-dynamic-var '*command-line-args* nil))
|
||||||
|
(def warn-on-reflection (sci/new-dynamic-var '*warn-on-reflection* false))
|
||||||
|
|
||||||
(defn read+string
|
(defn read+string
|
||||||
"Added for compatibility. Must be used with
|
"Added for compatibility. Must be used with
|
||||||
|
|
@ -59,4 +61,6 @@
|
||||||
'default-data-readers default-data-readers
|
'default-data-readers default-data-readers
|
||||||
'xml-seq (copy-core-var xml-seq)
|
'xml-seq (copy-core-var xml-seq)
|
||||||
'read+string (fn [& args]
|
'read+string (fn [& args]
|
||||||
(apply read+string @common/ctx args))})
|
(apply read+string @common/ctx args))
|
||||||
|
'*command-line-args* command-line-args
|
||||||
|
'*warn-on-reflection* warn-on-reflection})
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,20 @@
|
||||||
then used to resolve dependencies in babashka."
|
then used to resolve dependencies in babashka."
|
||||||
([deps-map] (add-deps deps-map nil))
|
([deps-map] (add-deps deps-map nil))
|
||||||
([deps-map {:keys [:aliases]}]
|
([deps-map {:keys [:aliases]}]
|
||||||
(let [args ["-Spath" "-Sdeps" (str deps-map)]
|
(when-let [paths (:paths deps-map)]
|
||||||
args (cond-> args
|
(cp/add-classpath (str/join cp/path-sep paths)))
|
||||||
aliases (conj (str "-A:" (str/join ":" aliases))))
|
(when-let [deps-map (not-empty (dissoc deps-map :paths :tasks))]
|
||||||
cp (with-out-str (apply deps/-main args))]
|
(let [deps-map (assoc-in deps-map [:aliases :org.babashka/defaults]
|
||||||
(cp/add-classpath cp))))
|
'{:replace-paths [] ;; babashka sets paths manually
|
||||||
|
:classpath-overrides {org.clojure/clojure ""
|
||||||
|
org.clojure/spec.alpha ""
|
||||||
|
org.clojure/core.specs.alpha ""}})
|
||||||
|
args ["-Spath" "-Sdeps" (str deps-map)]
|
||||||
|
args (conj args (str "-A:" (str/join ":" (cons ":org.babashka/defaults" aliases))))
|
||||||
|
cp (with-out-str (apply deps/-main args))
|
||||||
|
cp (str/trim cp)
|
||||||
|
cp (str/replace cp (re-pattern (str cp/path-sep "+$")) "")]
|
||||||
|
(cp/add-classpath cp)))))
|
||||||
|
|
||||||
(defn clojure
|
(defn clojure
|
||||||
"Starts clojure similar to CLI. Use `rlwrap bb` for `clj`-like invocation.
|
"Starts clojure similar to CLI. Use `rlwrap bb` for `clj`-like invocation.
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
{:no-doc true}
|
{:no-doc true}
|
||||||
(:refer-clojure :exclude [error-handler])
|
(:refer-clojure :exclude [error-handler])
|
||||||
(:require
|
(:require
|
||||||
|
[babashka.fs :as fs]
|
||||||
[babashka.impl.bencode :refer [bencode-namespace]]
|
[babashka.impl.bencode :refer [bencode-namespace]]
|
||||||
[babashka.impl.cheshire :refer [cheshire-core-namespace]]
|
[babashka.impl.cheshire :refer [cheshire-core-namespace]]
|
||||||
[babashka.impl.classes :as classes]
|
[babashka.impl.classes :as classes]
|
||||||
|
|
@ -33,6 +34,7 @@
|
||||||
[babashka.impl.test :as t]
|
[babashka.impl.test :as t]
|
||||||
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
|
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
|
||||||
[babashka.nrepl.server :as nrepl-server]
|
[babashka.nrepl.server :as nrepl-server]
|
||||||
|
[babashka.process :as p]
|
||||||
[babashka.wait :as wait]
|
[babashka.wait :as wait]
|
||||||
[clojure.edn :as edn]
|
[clojure.edn :as edn]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
|
|
@ -74,135 +76,33 @@
|
||||||
;; echo '1' | java -agentlib:native-image-agent=config-output-dir=/tmp -jar target/babashka-xxx-standalone.jar '...'
|
;; echo '1' | java -agentlib:native-image-agent=config-output-dir=/tmp -jar target/babashka-xxx-standalone.jar '...'
|
||||||
;; with the java provided by GraalVM.
|
;; with the java provided by GraalVM.
|
||||||
|
|
||||||
(defn parse-opts [options]
|
|
||||||
(let [opts (loop [options options
|
|
||||||
opts-map {}]
|
|
||||||
(if options
|
|
||||||
(let [opt (first options)]
|
|
||||||
(case opt
|
|
||||||
("--") (assoc opts-map :command-line-args (next options))
|
|
||||||
("--clojure") (assoc opts-map :clojure true
|
|
||||||
:opts (rest options))
|
|
||||||
("--version") {:version true}
|
|
||||||
("--help" "-h" "-?") {:help? true}
|
|
||||||
("--verbose")(recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:verbose? true))
|
|
||||||
("--describe") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:describe? true))
|
|
||||||
("--stream") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:stream? true))
|
|
||||||
("-i") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:shell-in true))
|
|
||||||
("-I") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:edn-in true))
|
|
||||||
("-o") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:shell-out true))
|
|
||||||
("-O") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:edn-out true))
|
|
||||||
("-io") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:shell-in true
|
|
||||||
:shell-out true))
|
|
||||||
("-iO") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:shell-in true
|
|
||||||
:edn-out true))
|
|
||||||
("-Io") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:edn-in true
|
|
||||||
:shell-out true))
|
|
||||||
("-IO") (recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:edn-in true
|
|
||||||
:edn-out true))
|
|
||||||
("--classpath", "-cp")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(assoc opts-map :classpath (first options))))
|
|
||||||
("--uberscript")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:uberscript (first options))))
|
|
||||||
("--uberjar")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:uberjar (first options))))
|
|
||||||
("-f" "--file")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:file (first options))))
|
|
||||||
("--jar" "-jar")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:jar (first options))))
|
|
||||||
("--repl")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(assoc opts-map
|
|
||||||
:repl true)))
|
|
||||||
("--socket-repl")
|
|
||||||
(let [options (next options)
|
|
||||||
opt (first options)
|
|
||||||
opt (when (and opt (not (str/starts-with? opt "-")))
|
|
||||||
opt)
|
|
||||||
options (if opt (next options)
|
|
||||||
options)]
|
|
||||||
(recur options
|
|
||||||
(assoc opts-map
|
|
||||||
:socket-repl (or opt "1666"))))
|
|
||||||
("--nrepl-server")
|
|
||||||
(let [options (next options)
|
|
||||||
opt (first options)
|
|
||||||
opt (when (and opt (not (str/starts-with? opt "-")))
|
|
||||||
opt)
|
|
||||||
options (if opt (next options)
|
|
||||||
options)]
|
|
||||||
(recur options
|
|
||||||
(assoc opts-map
|
|
||||||
:nrepl (or opt "1667"))))
|
|
||||||
("--eval", "-e")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(update opts-map :expressions (fnil conj []) (first options))))
|
|
||||||
("--main", "-m")
|
|
||||||
(let [options (next options)]
|
|
||||||
(recur (next options)
|
|
||||||
(assoc opts-map :main (first options))))
|
|
||||||
(if (some opts-map [:file :jar :socket-repl :expressions :main])
|
|
||||||
(assoc opts-map
|
|
||||||
:command-line-args options)
|
|
||||||
(let [trimmed-opt (str/triml opt)
|
|
||||||
c (.charAt trimmed-opt 0)]
|
|
||||||
(case c
|
|
||||||
(\( \{ \[ \* \@ \#)
|
|
||||||
(-> opts-map
|
|
||||||
(update :expressions (fnil conj []) (first options))
|
|
||||||
(assoc :command-line-args (next options)))
|
|
||||||
(assoc opts-map
|
|
||||||
(if (str/ends-with? opt ".jar")
|
|
||||||
:jar :file) opt
|
|
||||||
:command-line-args (next options)))))))
|
|
||||||
opts-map))]
|
|
||||||
opts))
|
|
||||||
|
|
||||||
(def version (str/trim (slurp (io/resource "BABASHKA_VERSION"))))
|
(def version (str/trim (slurp (io/resource "BABASHKA_VERSION"))))
|
||||||
|
|
||||||
(defn print-version []
|
(defn print-version []
|
||||||
(println (str "babashka v" version)))
|
(println (str "babashka v" version)))
|
||||||
|
|
||||||
|
(def bb-edn
|
||||||
|
(atom nil))
|
||||||
|
|
||||||
(defn print-help []
|
(defn decode-task [task]
|
||||||
|
(let [task (if (map? task)
|
||||||
|
(:task task)
|
||||||
|
task)
|
||||||
|
task-key (first task)
|
||||||
|
args (rest task)
|
||||||
|
maybe-opts (first args)]
|
||||||
|
(if (map? maybe-opts)
|
||||||
|
{:task task-key
|
||||||
|
:opts maybe-opts
|
||||||
|
:args (rest args)}
|
||||||
|
{:task task-key
|
||||||
|
:args args})))
|
||||||
|
|
||||||
|
(defn print-error [& msgs]
|
||||||
|
(binding [*out* *err*]
|
||||||
|
(apply println msgs)))
|
||||||
|
|
||||||
|
(defn print-help [_ctx _command-line-args]
|
||||||
(println (str "Babashka v" version))
|
(println (str "Babashka v" version))
|
||||||
;; (println (str "sci v" (str/trim (slurp (io/resource "SCI_VERSION")))))
|
;; (println (str "sci v" (str/trim (slurp (io/resource "SCI_VERSION")))))
|
||||||
(println)
|
(println)
|
||||||
|
|
@ -210,9 +110,11 @@
|
||||||
(println "
|
(println "
|
||||||
Help:
|
Help:
|
||||||
|
|
||||||
--help, -h or -? Print this help text.
|
help, -h or -? Print this help text.
|
||||||
--version Print the current version of babashka.
|
version Print the current version of babashka.
|
||||||
--describe Print an EDN map with information about this version of babashka.
|
describe Print an EDN map with information about this version of babashka.
|
||||||
|
tasks List tasks.
|
||||||
|
doc <var> Print docstring of var or task. Resolves using requiring-resolve.
|
||||||
|
|
||||||
Evaluation:
|
Evaluation:
|
||||||
|
|
||||||
|
|
@ -224,9 +126,9 @@ Evaluation:
|
||||||
|
|
||||||
REPL:
|
REPL:
|
||||||
|
|
||||||
--repl Start REPL. Use rlwrap for history.
|
repl Start REPL. Use rlwrap for history.
|
||||||
--socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666).
|
socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666).
|
||||||
--nrepl-server Start nREPL server. Specify port (e.g. 1667) or host and port separated by colon (e.g. 127.0.0.1:1667).
|
nrepl-server Start nREPL server. Specify port (e.g. 1667) or host and port separated by colon (e.g. 127.0.0.1:1667).
|
||||||
|
|
||||||
In- and output flags:
|
In- and output flags:
|
||||||
|
|
||||||
|
|
@ -238,21 +140,69 @@ In- and output flags:
|
||||||
|
|
||||||
Uberscript:
|
Uberscript:
|
||||||
|
|
||||||
--uberscript <file> Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single file.
|
uberscript <file> Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single file.
|
||||||
|
|
||||||
Uberjar:
|
Uberjar:
|
||||||
|
|
||||||
--uberjar <jar> Similar to --uberscript but creates jar file.
|
uberjar <jar> Similar to --uberscript but creates jar file.
|
||||||
|
|
||||||
Clojure:
|
Clojure:
|
||||||
|
|
||||||
--clojure [args...] Invokes clojure. Takes same args as the official clojure CLI.
|
clojure [args...] Invokes clojure. Takes same args as the official clojure CLI.
|
||||||
|
|
||||||
If the first argument is not any of the above options, then it treated as a file if it exists, or as an expression otherwise.
|
If the first argument is not any of the above options, then it treated as a file if it exists, or as an expression otherwise.
|
||||||
Everything after that is bound to *command-line-args*.
|
Everything after that is bound to *command-line-args*.
|
||||||
|
|
||||||
Use -- to separate script command line args from bb command line args.
|
Use -- to separate script command line args from bb command line args.
|
||||||
"))
|
")
|
||||||
|
[nil 0])
|
||||||
|
|
||||||
|
(defn print-doc [ctx command-line-args]
|
||||||
|
(let [arg (first command-line-args)]
|
||||||
|
(if (str/starts-with? arg ":")
|
||||||
|
(let [k (keyword (subs arg 1))]
|
||||||
|
(if-let [task (get-in @bb-edn [:tasks k])]
|
||||||
|
(let [{:keys [:args]
|
||||||
|
task-key :task} (decode-task task)]
|
||||||
|
(if-let [help-text (:doc task)]
|
||||||
|
[(println help-text) 0]
|
||||||
|
(if-let [main (when (= 'main task-key)
|
||||||
|
(first args))]
|
||||||
|
(let [main (if (simple-symbol? main)
|
||||||
|
(symbol (str main) "-main")
|
||||||
|
main)]
|
||||||
|
(if (sci/eval-string* ctx (format "(when (requiring-resolve '%1$s)
|
||||||
|
(clojure.repl/doc %1$s) true)" main))
|
||||||
|
[nil 0]
|
||||||
|
[(print-error "No docstring found for task:" k) 1]))
|
||||||
|
[(print-error "No docstring found for task:" k) 1])))
|
||||||
|
[(print-error "Task does not exist:" k) 1]))
|
||||||
|
(let [arg (if (str/includes? arg "/") arg (str "clojure.core/" arg))]
|
||||||
|
(if (sci/eval-string* ctx (format "(when (requiring-resolve '%1$s)
|
||||||
|
(clojure.repl/doc %1$s) true)" arg))
|
||||||
|
[nil 0]
|
||||||
|
[(print-error "No docstring found for var:" arg) 1]))))
|
||||||
|
,)
|
||||||
|
|
||||||
|
(defn print-tasks [tasks]
|
||||||
|
(if (seq tasks)
|
||||||
|
(let [tasks (into (sorted-map) tasks)
|
||||||
|
ks (keys tasks)
|
||||||
|
longest (apply max
|
||||||
|
(map (comp count str)
|
||||||
|
ks))
|
||||||
|
fmt (str "%1$-" longest "s")]
|
||||||
|
(println "The following tasks are available:")
|
||||||
|
(println)
|
||||||
|
(doseq [[k v] tasks]
|
||||||
|
(println (str (format fmt k)
|
||||||
|
(when-let [d (:description v)]
|
||||||
|
(str " " d)))))
|
||||||
|
(println)
|
||||||
|
(println "Run bb :help <task> to view help of a specific task.")
|
||||||
|
[nil 0])
|
||||||
|
(do (println "No tasks found.")
|
||||||
|
[nil 0])))
|
||||||
|
|
||||||
(defn print-describe []
|
(defn print-describe []
|
||||||
(println
|
(println
|
||||||
|
|
@ -301,8 +251,6 @@ Use -- to separate script command line args from bb command line args.
|
||||||
(str/replace x #"^#!.*" ""))
|
(str/replace x #"^#!.*" ""))
|
||||||
(throw (Exception. (str "File does not exist: " file))))))
|
(throw (Exception. (str "File does not exist: " file))))))
|
||||||
|
|
||||||
(def reflection-var (sci/new-dynamic-var '*warn-on-reflection* false))
|
|
||||||
|
|
||||||
(defn load-file* [f]
|
(defn load-file* [f]
|
||||||
(let [f (io/file f)
|
(let [f (io/file f)
|
||||||
s (slurp f)]
|
s (slurp f)]
|
||||||
|
|
@ -319,7 +267,7 @@ Use -- to separate script command line args from bb command line args.
|
||||||
nrepl-opts (assoc nrepl-opts
|
nrepl-opts (assoc nrepl-opts
|
||||||
:debug dev?
|
:debug dev?
|
||||||
:describe {"versions" {"babashka" version}}
|
:describe {"versions" {"babashka" version}}
|
||||||
:thread-bind [reflection-var])]
|
:thread-bind [core/warn-on-reflection])]
|
||||||
(nrepl-server/start-server! ctx nrepl-opts)
|
(nrepl-server/start-server! ctx nrepl-opts)
|
||||||
(binding [*out* *err*]
|
(binding [*out* *err*]
|
||||||
(println "For more info visit: https://book.babashka.org/#_nrepl")))
|
(println "For more info visit: https://book.babashka.org/#_nrepl")))
|
||||||
|
|
@ -477,27 +425,234 @@ Use -- to separate script command line args from bb command line args.
|
||||||
(defn shell-seq [in]
|
(defn shell-seq [in]
|
||||||
(line-seq (java.io.BufferedReader. in)))
|
(line-seq (java.io.BufferedReader. in)))
|
||||||
|
|
||||||
(defn main
|
(declare resolve-task)
|
||||||
[& args]
|
|
||||||
(handle-pipe!)
|
(defn error [msg exit]
|
||||||
(handle-sigint!)
|
(binding [*out* *err*]
|
||||||
|
(println msg)
|
||||||
|
{:exec (fn [] [nil exit])}))
|
||||||
|
|
||||||
|
(defn command? [x]
|
||||||
|
(case x
|
||||||
|
("clojure"
|
||||||
|
"version"
|
||||||
|
"help"
|
||||||
|
"doc"
|
||||||
|
"tasks"
|
||||||
|
"uberjar"
|
||||||
|
"uberscript"
|
||||||
|
"repl"
|
||||||
|
"socket-repl"
|
||||||
|
"nrepl-server"
|
||||||
|
"describe") true
|
||||||
|
false))
|
||||||
|
|
||||||
|
(defn parse-opts [options]
|
||||||
|
(let [fst (when options (first options))
|
||||||
|
key? (when fst (str/starts-with? fst ":"))
|
||||||
|
keys (when key? (rest (str/split fst #":")))
|
||||||
|
expanded (when (and key? (> (count keys) 1))
|
||||||
|
(into ['do] (map (comp vector keyword) keys)))
|
||||||
|
k (when (and key? (not expanded))
|
||||||
|
(keyword (first keys)))
|
||||||
|
bb-edn @bb-edn
|
||||||
|
tasks (when bb-edn
|
||||||
|
(:tasks bb-edn))
|
||||||
|
user-task (when (and tasks k)
|
||||||
|
(get tasks k))
|
||||||
|
opt (first options)]
|
||||||
|
(cond user-task
|
||||||
|
(resolve-task tasks user-task {:command-line-args (next options)})
|
||||||
|
expanded (resolve-task tasks expanded nil)
|
||||||
|
(and (command? opt)
|
||||||
|
(not (fs/regular-file? opt)))
|
||||||
|
(recur (cons (str "--" opt) (next options)))
|
||||||
|
:else
|
||||||
|
(let [opts (loop [options options
|
||||||
|
opts-map {}]
|
||||||
|
(if options
|
||||||
|
(let [opt (first options)]
|
||||||
|
(case opt
|
||||||
|
("--") (assoc opts-map :command-line-args (next options))
|
||||||
|
("--clojure") (assoc opts-map :clojure true
|
||||||
|
:command-line-args (rest options))
|
||||||
|
("--version") {:version true}
|
||||||
|
("--help" "-h" "-?" "help")
|
||||||
|
{:help true
|
||||||
|
:command-line-args (rest options)}
|
||||||
|
("--doc")
|
||||||
|
{:doc true
|
||||||
|
:command-line-args (rest options)}
|
||||||
|
("--tasks") {:tasks (or tasks {})
|
||||||
|
:command-line-args (rest options)}
|
||||||
|
("--verbose") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:verbose? true))
|
||||||
|
("--describe") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:describe? true))
|
||||||
|
("--stream") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:stream? true))
|
||||||
|
("-i") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:shell-in true))
|
||||||
|
("-I") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:edn-in true))
|
||||||
|
("-o") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:shell-out true))
|
||||||
|
("-O") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:edn-out true))
|
||||||
|
("-io") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:shell-in true
|
||||||
|
:shell-out true))
|
||||||
|
("-iO") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:shell-in true
|
||||||
|
:edn-out true))
|
||||||
|
("-Io") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:edn-in true
|
||||||
|
:shell-out true))
|
||||||
|
("-IO") (recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:edn-in true
|
||||||
|
:edn-out true))
|
||||||
|
("--classpath", "-cp")
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(assoc opts-map :classpath (first options))))
|
||||||
|
("--uberscript")
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:uberscript (first options))))
|
||||||
|
("--uberjar")
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:uberjar (first options))))
|
||||||
|
("-f" "--file")
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:file (first options))))
|
||||||
|
("--jar" "-jar")
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:jar (first options))))
|
||||||
|
("--repl")
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(assoc opts-map
|
||||||
|
:repl true)))
|
||||||
|
("--socket-repl")
|
||||||
|
(let [options (next options)
|
||||||
|
opt (first options)
|
||||||
|
opt (when (and opt (not (str/starts-with? opt "-")))
|
||||||
|
opt)
|
||||||
|
options (if opt (next options)
|
||||||
|
options)]
|
||||||
|
(recur options
|
||||||
|
(assoc opts-map
|
||||||
|
:socket-repl (or opt "1666"))))
|
||||||
|
("--nrepl-server")
|
||||||
|
(let [options (next options)
|
||||||
|
opt (first options)
|
||||||
|
opt (when (and opt (not (str/starts-with? opt "-")))
|
||||||
|
opt)
|
||||||
|
options (if opt (next options)
|
||||||
|
options)]
|
||||||
|
(recur options
|
||||||
|
(assoc opts-map
|
||||||
|
:nrepl (or opt "1667"))))
|
||||||
|
("--eval", "-e")
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(update opts-map :expressions (fnil conj []) (first options))))
|
||||||
|
("--main", "-m",)
|
||||||
|
(let [options (next options)]
|
||||||
|
(recur (next options)
|
||||||
|
(assoc opts-map :main (first options))))
|
||||||
|
;; fallback
|
||||||
|
(if (some opts-map [:file :jar :socket-repl :expressions :main])
|
||||||
|
(assoc opts-map
|
||||||
|
:command-line-args options)
|
||||||
|
(let [trimmed-opt (str/triml opt)
|
||||||
|
c (.charAt trimmed-opt 0)]
|
||||||
|
(case c
|
||||||
|
(\( \{ \[ \* \@ \#)
|
||||||
|
(-> opts-map
|
||||||
|
(update :expressions (fnil conj []) (first options))
|
||||||
|
(assoc :command-line-args (next options)))
|
||||||
|
(if (fs/exists? opt)
|
||||||
|
(assoc opts-map
|
||||||
|
(if (str/ends-with? opt ".jar")
|
||||||
|
:jar :file) opt
|
||||||
|
:command-line-args (next options))
|
||||||
|
(error (str (if (str/starts-with? opt ":")
|
||||||
|
"Task does not exist: "
|
||||||
|
"File does not exist: ") opt) 1)))))))
|
||||||
|
opts-map))]
|
||||||
|
opts))))
|
||||||
|
|
||||||
|
(defn resolve-task [tasks task {:keys [:command-line-args]}]
|
||||||
|
(let [{:keys [:task :opts :args]} (decode-task task)]
|
||||||
|
opts ;; not used
|
||||||
|
(case task
|
||||||
|
babashka
|
||||||
|
(let [cmd-line-args args]
|
||||||
|
(parse-opts (seq (map str (concat cmd-line-args command-line-args)))))
|
||||||
|
shell
|
||||||
|
(let [args (if (string? (first args))
|
||||||
|
(into (p/tokenize (first args)) (rest args))
|
||||||
|
args)
|
||||||
|
args (into (vec args) command-line-args)]
|
||||||
|
{:exec (fn []
|
||||||
|
[nil
|
||||||
|
(-> (p/process args {:inherit true})
|
||||||
|
deref
|
||||||
|
:exit)])})
|
||||||
|
main
|
||||||
|
(let [main-arg (first args)
|
||||||
|
cmd-line-args (rest args)]
|
||||||
|
(parse-opts (seq (map str (concat ["--main" main-arg] cmd-line-args command-line-args)))))
|
||||||
|
clojure
|
||||||
|
(parse-opts (seq (map str (concat ["--clojure"] args command-line-args))))
|
||||||
|
do
|
||||||
|
{:do (map #(resolve-task tasks % nil) args)}
|
||||||
|
;; default
|
||||||
|
(if-let [t (get tasks task)]
|
||||||
|
(resolve-task tasks t nil)
|
||||||
|
(error (str "No such task: " task) 1)))))
|
||||||
|
|
||||||
|
(def should-load-inits?
|
||||||
|
"if true, then we should still load preloads and user.clj"
|
||||||
|
(volatile! true))
|
||||||
|
|
||||||
|
(def env (atom {}))
|
||||||
|
|
||||||
|
(defn exec [opts]
|
||||||
(binding [*unrestricted* true]
|
(binding [*unrestricted* true]
|
||||||
(sci/binding [reflection-var false
|
(sci/binding [core/warn-on-reflection @core/warn-on-reflection
|
||||||
core/data-readers @core/data-readers
|
core/data-readers @core/data-readers
|
||||||
sci/ns @sci/ns]
|
sci/ns @sci/ns]
|
||||||
(let [{version-opt :version
|
(let [{version-opt :version
|
||||||
:keys [:shell-in :edn-in :shell-out :edn-out
|
:keys [:shell-in :edn-in :shell-out :edn-out
|
||||||
:help? :file :command-line-args
|
:help :file :command-line-args
|
||||||
:expressions :stream?
|
:expressions :stream?
|
||||||
:repl :socket-repl :nrepl
|
:repl :socket-repl :nrepl
|
||||||
:verbose? :classpath
|
:verbose? :classpath
|
||||||
:main :uberscript :describe?
|
:main :uberscript :describe?
|
||||||
:jar :uberjar :clojure] :as opts}
|
:jar :uberjar :clojure
|
||||||
(parse-opts args)
|
:exec-src :tasks :doc]
|
||||||
_ (when clojure
|
exec-fn :exec}
|
||||||
(if-let [proc (deps/clojure (:opts opts))]
|
opts
|
||||||
(-> @proc :exit (System/exit))
|
|
||||||
(System/exit 0)))
|
|
||||||
_ (when verbose? (vreset! common/verbose? true))
|
_ (when verbose? (vreset! common/verbose? true))
|
||||||
_ (do ;; set properties
|
_ (do ;; set properties
|
||||||
(when main (System/setProperty "babashka.main" main))
|
(when main (System/setProperty "babashka.main" main))
|
||||||
|
|
@ -516,7 +671,6 @@ Use -- to separate script command line args from bb command line args.
|
||||||
:else
|
:else
|
||||||
(edn/read {:readers edn-readers} *in*))))))
|
(edn/read {:readers edn-readers} *in*))))))
|
||||||
uberscript-sources (atom ())
|
uberscript-sources (atom ())
|
||||||
env (atom {})
|
|
||||||
classpath (or classpath
|
classpath (or classpath
|
||||||
(System/getenv "BABASHKA_CLASSPATH"))
|
(System/getenv "BABASHKA_CLASSPATH"))
|
||||||
_ (when classpath
|
_ (when classpath
|
||||||
|
|
@ -546,15 +700,11 @@ Use -- to separate script command line args from bb command line args.
|
||||||
["META-INF/MANIFEST.MF"] {:url? true})]
|
["META-INF/MANIFEST.MF"] {:url? true})]
|
||||||
(cp/main-ns res))
|
(cp/main-ns res))
|
||||||
main)
|
main)
|
||||||
|
|
||||||
;; TODO: pull more of these values to compile time
|
;; TODO: pull more of these values to compile time
|
||||||
opts {:aliases aliases
|
opts {:aliases aliases
|
||||||
:namespaces (-> namespaces
|
:namespaces (-> namespaces
|
||||||
(assoc 'clojure.core
|
(assoc 'clojure.core
|
||||||
(assoc core-extras
|
(assoc core-extras
|
||||||
'*command-line-args*
|
|
||||||
(sci/new-dynamic-var '*command-line-args* command-line-args)
|
|
||||||
'*warn-on-reflection* reflection-var
|
|
||||||
'load-file load-file*))
|
'load-file load-file*))
|
||||||
(assoc-in ['clojure.java.io 'resource]
|
(assoc-in ['clojure.java.io 'resource]
|
||||||
(fn [path]
|
(fn [path]
|
||||||
|
|
@ -576,11 +726,18 @@ Use -- to separate script command line args from bb command line args.
|
||||||
opts (addons/future opts)
|
opts (addons/future opts)
|
||||||
sci-ctx (sci/init opts)
|
sci-ctx (sci/init opts)
|
||||||
_ (vreset! common/ctx sci-ctx)
|
_ (vreset! common/ctx sci-ctx)
|
||||||
preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim))
|
preloads (when @should-load-inits? (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim)))
|
||||||
[expressions exit-code]
|
[expressions exit-code]
|
||||||
(cond expressions [expressions nil]
|
(cond expressions [expressions nil]
|
||||||
main [[(format "(ns user (:require [%1$s])) (apply %1$s/-main *command-line-args*)"
|
main
|
||||||
main)] nil]
|
(let [sym (symbol main)
|
||||||
|
ns? (namespace sym)
|
||||||
|
ns (or ns? sym)
|
||||||
|
var-name (if ns?
|
||||||
|
(name sym)
|
||||||
|
"-main")]
|
||||||
|
[[(format "(ns user (:require [%1$s])) (apply %1$s/%2$s *command-line-args*)"
|
||||||
|
ns var-name)] nil])
|
||||||
file (try [[(read-file file)] nil]
|
file (try [[(read-file file)] nil]
|
||||||
(catch Exception e
|
(catch Exception e
|
||||||
(error-handler e {:expression expressions
|
(error-handler e {:expression expressions
|
||||||
|
|
@ -591,7 +748,8 @@ Use -- to separate script command line args from bb command line args.
|
||||||
exit-code
|
exit-code
|
||||||
;; handle preloads
|
;; handle preloads
|
||||||
(if exit-code exit-code
|
(if exit-code exit-code
|
||||||
(do (when preloads
|
(do (when @should-load-inits?
|
||||||
|
(when preloads
|
||||||
(sci/binding [sci/file "<preloads>"]
|
(sci/binding [sci/file "<preloads>"]
|
||||||
(try
|
(try
|
||||||
(sci/eval-string* sci-ctx preloads)
|
(sci/eval-string* sci-ctx preloads)
|
||||||
|
|
@ -600,6 +758,18 @@ Use -- to separate script command line args from bb command line args.
|
||||||
:verbose? verbose?
|
:verbose? verbose?
|
||||||
:preloads preloads
|
:preloads preloads
|
||||||
:loader (:loader @cp/cp-state)})))))
|
:loader (:loader @cp/cp-state)})))))
|
||||||
|
(when @cp/cp-state
|
||||||
|
(when-let [{:keys [:file :source]}
|
||||||
|
(cp/source-for-namespace (:loader @cp/cp-state) "user" nil)]
|
||||||
|
(sci/binding [sci/file file]
|
||||||
|
(try
|
||||||
|
(sci/eval-string* sci-ctx source)
|
||||||
|
(catch Throwable e
|
||||||
|
(error-handler e {:expression expression
|
||||||
|
:verbose? verbose?
|
||||||
|
:preloads preloads
|
||||||
|
:loader (:loader @cp/cp-state)}))))))
|
||||||
|
(vreset! should-load-inits? false))
|
||||||
nil))
|
nil))
|
||||||
;; socket REPL is start asynchronously. when no other args are
|
;; socket REPL is start asynchronously. when no other args are
|
||||||
;; provided, a normal REPL will be started as well, which causes the
|
;; provided, a normal REPL will be started as well, which causes the
|
||||||
|
|
@ -610,8 +780,9 @@ Use -- to separate script command line args from bb command line args.
|
||||||
(second
|
(second
|
||||||
(cond version-opt
|
(cond version-opt
|
||||||
[(print-version) 0]
|
[(print-version) 0]
|
||||||
help?
|
help (print-help sci-ctx command-line-args)
|
||||||
[(print-help) 0]
|
tasks (print-tasks tasks)
|
||||||
|
doc (print-doc sci-ctx command-line-args)
|
||||||
describe?
|
describe?
|
||||||
[(print-describe) 0]
|
[(print-describe) 0]
|
||||||
repl [(repl/start-repl! sci-ctx) 0]
|
repl [(repl/start-repl! sci-ctx) 0]
|
||||||
|
|
@ -626,7 +797,8 @@ Use -- to separate script command line args from bb command line args.
|
||||||
[nil 0] ;; done streaming
|
[nil 0] ;; done streaming
|
||||||
(let [res [(let [res
|
(let [res [(let [res
|
||||||
(sci/binding [sci/file (or @sci/file "<expr>")
|
(sci/binding [sci/file (or @sci/file "<expr>")
|
||||||
input-var in]
|
input-var in
|
||||||
|
core/command-line-args command-line-args]
|
||||||
(sci/eval-string* sci-ctx expression))]
|
(sci/eval-string* sci-ctx expression))]
|
||||||
(when (some? res)
|
(when (some? res)
|
||||||
(if-let [pr-f (cond shell-out println
|
(if-let [pr-f (cond shell-out println
|
||||||
|
|
@ -645,6 +817,16 @@ Use -- to separate script command line args from bb command line args.
|
||||||
:verbose? verbose?
|
:verbose? verbose?
|
||||||
:preloads preloads
|
:preloads preloads
|
||||||
:loader (:loader @cp/cp-state)}))))
|
:loader (:loader @cp/cp-state)}))))
|
||||||
|
exec-fn (exec-fn)
|
||||||
|
exec-src [(let [res (sci/binding [sci/file (or @sci/file "<task>")
|
||||||
|
core/command-line-args command-line-args]
|
||||||
|
(sci/eval-string* sci-ctx exec-src))]
|
||||||
|
(when (some? res)
|
||||||
|
(prn res)))
|
||||||
|
0]
|
||||||
|
clojure [nil (if-let [proc (deps/clojure command-line-args)]
|
||||||
|
(-> @proc :exit)
|
||||||
|
0)]
|
||||||
uberscript [nil 0]
|
uberscript [nil 0]
|
||||||
:else [(repl/start-repl! sci-ctx) 0]))
|
:else [(repl/start-repl! sci-ctx) 0]))
|
||||||
1)]
|
1)]
|
||||||
|
|
@ -664,8 +846,33 @@ Use -- to separate script command line args from bb command line args.
|
||||||
:verbose verbose?}))
|
:verbose verbose?}))
|
||||||
exit-code))))
|
exit-code))))
|
||||||
|
|
||||||
|
(defn exec* [opts]
|
||||||
|
(if-let [do-opts (:do opts)]
|
||||||
|
(reduce (fn [prev-exit opts]
|
||||||
|
;; (prn :prev prev-exit)
|
||||||
|
;; (prn :opts opts)
|
||||||
|
(if (pos? prev-exit)
|
||||||
|
(reduced prev-exit)
|
||||||
|
(exec* opts)))
|
||||||
|
0
|
||||||
|
do-opts)
|
||||||
|
(exec opts)))
|
||||||
|
|
||||||
|
(defn main [& args]
|
||||||
|
(let [bb-edn-file (or (System/getenv "BABASHKA_EDN")
|
||||||
|
"bb.edn")]
|
||||||
|
(when (fs/exists? bb-edn-file)
|
||||||
|
(let [edn (edn/read-string (slurp bb-edn-file))]
|
||||||
|
(reset! bb-edn edn)))
|
||||||
|
;; we mutate the atom from tests as well, so despite the above it can contain a bb.edn
|
||||||
|
(when-let [bb-edn @bb-edn] (deps/add-deps bb-edn)))
|
||||||
|
(let [opts (parse-opts args)]
|
||||||
|
(exec* opts)))
|
||||||
|
|
||||||
(defn -main
|
(defn -main
|
||||||
[& args]
|
[& args]
|
||||||
|
(handle-pipe!)
|
||||||
|
(handle-sigint!)
|
||||||
(if-let [dev-opts (System/getenv "BABASHKA_DEV")]
|
(if-let [dev-opts (System/getenv "BABASHKA_DEV")]
|
||||||
(let [{:keys [:n]} (if (= "true" dev-opts) {:n 1}
|
(let [{:keys [:n]} (if (= "true" dev-opts) {:n 1}
|
||||||
(edn/read-string dev-opts))
|
(edn/read-string dev-opts))
|
||||||
|
|
|
||||||
10
test-resources/bb-edn/user.clj
Normal file
10
test-resources/bb-edn/user.clj
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(ns user
|
||||||
|
(:require [babashka.process :as p]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(defn bash [& args]
|
||||||
|
;; (prn :cmd *command-line-args*)
|
||||||
|
(-> (p/process ["bash" "-c" (str/join " " args)]
|
||||||
|
{:inherit true})
|
||||||
|
p/check)
|
||||||
|
nil)
|
||||||
41
test-resources/bb.edn
Normal file
41
test-resources/bb.edn
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{:paths ["test-resources/bb-edn"] ;; no-brainer to support this
|
||||||
|
:deps {medley/medley {:mvn/version "1.3.0"}} ;; no-brainer to support this
|
||||||
|
|
||||||
|
;; here comes the part that is currently uncertain
|
||||||
|
:tasks {:count-files [shell "bash" "-c" "ls | wc -l"]
|
||||||
|
:bash [babashka user/bash]
|
||||||
|
:eval-plus [babashka -e (apply + (map (fn [i]
|
||||||
|
(Integer/parseInt i))
|
||||||
|
*command-line-args*))]
|
||||||
|
:describe [babashka clojure -Sdescribe]
|
||||||
|
:do-bash [do
|
||||||
|
[:bash "ls | wc -l"]
|
||||||
|
[:eval-plus 1 2 3]]
|
||||||
|
:all [do
|
||||||
|
[:count-files]
|
||||||
|
[:bash "ls | wc -l"]
|
||||||
|
[:eval-plus 1 2 3]
|
||||||
|
[:describe]]
|
||||||
|
;;;;
|
||||||
|
:never-failing-shell
|
||||||
|
[babashka -e (-> (do (deref (babashka.process/process ["ls" "foobar"] {:inherit true}))
|
||||||
|
(deref (babashka.process/process ["echo" "done"] {:inherit true}))
|
||||||
|
nil))]
|
||||||
|
:print-hello [babashka -e (println :hello)]
|
||||||
|
:always-failing-shell [babashka -e (babashka.process/check (babashka.process/process ["ls" "foobar"] {:inherit true}))]
|
||||||
|
:composed-never-failing [do
|
||||||
|
[:never-failing-shell]
|
||||||
|
[:print-hello]]
|
||||||
|
:composed-failing [do
|
||||||
|
[:always-failing-shell]
|
||||||
|
[:print-hello]]
|
||||||
|
,
|
||||||
|
|
||||||
|
;;;; help
|
||||||
|
:cool-task {:doc "Usage: bb :cool-task
|
||||||
|
|
||||||
|
Sum up the numbers 1, 2 and 3."
|
||||||
|
:task [babashka "-e" "(+ 1 2 3)"]}
|
||||||
|
,
|
||||||
|
}
|
||||||
|
}
|
||||||
16
test-resources/setup.clj
Normal file
16
test-resources/setup.clj
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
(defn eval-plus [& args]
|
||||||
|
(apply + (map (fn [i]
|
||||||
|
(Integer/parseInt i))
|
||||||
|
*command-line-args*)))
|
||||||
|
|
||||||
|
(defn tree []
|
||||||
|
(babashka.deps/clojure ["-Stree"]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn all [& args]
|
||||||
|
(apply eval-plus args)
|
||||||
|
(tree))
|
||||||
|
|
||||||
|
(defn bash [& args]
|
||||||
|
(babashka.process/process (into ["bash"] args)))
|
||||||
|
|
||||||
8
test-resources/task_scripts/tasks.clj
Normal file
8
test-resources/task_scripts/tasks.clj
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
(ns tasks)
|
||||||
|
|
||||||
|
(defn -main
|
||||||
|
"Usage: just pass some args.
|
||||||
|
|
||||||
|
This is the main main function in this namespace."
|
||||||
|
[& args]
|
||||||
|
args)
|
||||||
176
test/babashka/bb_edn_test.clj
Normal file
176
test/babashka/bb_edn_test.clj
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
(ns babashka.bb-edn-test
|
||||||
|
(:require
|
||||||
|
[babashka.fs :as fs]
|
||||||
|
[babashka.test-utils :as test-utils]
|
||||||
|
[clojure.edn :as edn]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[clojure.test :as test :refer [deftest is testing]]))
|
||||||
|
|
||||||
|
(defn bb [& args]
|
||||||
|
(edn/read-string
|
||||||
|
{:readers *data-readers*
|
||||||
|
:eof nil}
|
||||||
|
(apply test-utils/bb nil (map str args))))
|
||||||
|
|
||||||
|
(defmacro with-config [cfg & body]
|
||||||
|
`(let [temp-dir# (fs/create-temp-dir)
|
||||||
|
bb-edn-file# (fs/file temp-dir# "bb.edn")]
|
||||||
|
(binding [*print-meta* true]
|
||||||
|
(spit bb-edn-file# ~cfg))
|
||||||
|
(binding [test-utils/*bb-edn-path* (str bb-edn-file#)]
|
||||||
|
~@body)))
|
||||||
|
|
||||||
|
(deftest task-cli-test
|
||||||
|
(with-config {}
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
Exception #"Task does not exist: :sum"
|
||||||
|
(bb :sum))))
|
||||||
|
(with-config {}
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
Exception #"Task does not exist: :sum"
|
||||||
|
(bb "doc" :sum)))))
|
||||||
|
|
||||||
|
(deftest babashka-task-test
|
||||||
|
(with-config {:tasks {:sum ['babashka "-e" "(+ 1 2 3)"]}}
|
||||||
|
(let [res (bb :sum)]
|
||||||
|
(is (= 6 res)))))
|
||||||
|
|
||||||
|
(deftest shell-task-test
|
||||||
|
(let [temp-dir (fs/create-temp-dir)
|
||||||
|
temp-file (fs/create-file (fs/path temp-dir "temp-file.txt"))]
|
||||||
|
(with-config {:tasks {:clean ['shell "rm" (str temp-file)]}}
|
||||||
|
(is (fs/exists? temp-file))
|
||||||
|
(bb :clean)
|
||||||
|
(is (not (fs/exists? temp-file)))))
|
||||||
|
(testing "tokenization"
|
||||||
|
(let [temp-dir (fs/create-temp-dir)
|
||||||
|
temp-file (fs/create-file (fs/path temp-dir "temp-file.txt"))]
|
||||||
|
(with-config {:tasks {:clean ['shell (str "rm " (str temp-file))]}}
|
||||||
|
(is (fs/exists? temp-file))
|
||||||
|
(bb :clean)
|
||||||
|
(is (not (fs/exists? temp-file)))))
|
||||||
|
(testing "first string is tokenized even with following args"
|
||||||
|
(let [temp-dir (fs/create-temp-dir)
|
||||||
|
temp-file (fs/create-file (fs/path temp-dir "temp-file.txt"))]
|
||||||
|
(with-config {:tasks {:clean ['shell (str "rm -rf " (str temp-file))]}}
|
||||||
|
(is (fs/exists? temp-file))
|
||||||
|
(bb :clean)
|
||||||
|
(is (not (fs/exists? temp-file))))))))
|
||||||
|
|
||||||
|
(deftest sequential-task-test
|
||||||
|
(testing ":and-do"
|
||||||
|
(let [temp-dir (fs/create-temp-dir)
|
||||||
|
temp-file (fs/create-file (fs/path temp-dir "temp-file.txt"))]
|
||||||
|
(with-config {:tasks {:sum ['babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:all ['do
|
||||||
|
['shell "rm" (str temp-file)]
|
||||||
|
[:sum]]}}
|
||||||
|
(is (fs/exists? temp-file))
|
||||||
|
(let [res (bb :all)]
|
||||||
|
(is (= 6 res)))
|
||||||
|
(is (not (fs/exists? temp-file)))))
|
||||||
|
#_(testing ":and-do shortcut"
|
||||||
|
(let [temp-dir (fs/create-temp-dir)
|
||||||
|
temp-file (fs/create-file (fs/path temp-dir "temp-file.txt"))]
|
||||||
|
(with-config {:tasks {:clean [shell :clean:sum]
|
||||||
|
:sum [babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:all [babashka :clean:sum]}}
|
||||||
|
(is (fs/exists? temp-file))
|
||||||
|
(let [res (bb :clean:sum)]
|
||||||
|
(is (= 6 res)))
|
||||||
|
(is (not (fs/exists? temp-file)))))))
|
||||||
|
#_(testing "'do always continuing"
|
||||||
|
(with-config {:tasks {:sum-1 [babashka "-e" "(do (+ 4 5 6) nil)"]
|
||||||
|
:sum-2 [babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:all [babashka :sum-1:sum2]}}
|
||||||
|
(is (= 6 (bb :all))))
|
||||||
|
#_(with-config {:tasks {:div-by-zero [babashka "-e" "(/ 1 0)"]
|
||||||
|
:sum [babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:all[babashka :div-by-zero:sum] }}
|
||||||
|
(is (= 6 (bb :all)))))
|
||||||
|
(testing "task fails when one of subtask fails"
|
||||||
|
(with-config {:tasks {:div-by-zero ['babashka "-e" "(/ 1 0)"]
|
||||||
|
:sum ['babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:all ['babashka :div-by-zero:sum]}}
|
||||||
|
(is (thrown-with-msg? Exception #"Divide"
|
||||||
|
(bb :all)))))
|
||||||
|
#_(testing ":or-do short-cutting"
|
||||||
|
(with-config {:tasks {:sum-1 [babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:sum-2 [babashka "-e" "(+ 4 5 6)"]
|
||||||
|
:all [:or [:sum1] [:sum2]]}}
|
||||||
|
(is (= 6 (bb :all)))))
|
||||||
|
#_(testing ":or-do succeeding after failing"
|
||||||
|
(with-config {:tasks {:div-by-zero [babashka "-e" "(/ 1 0)"]
|
||||||
|
:sum [babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:all [babashka [:or [:div-by-zero] [:sum]]]}}
|
||||||
|
(is (= 6 (bb :all))))))
|
||||||
|
|
||||||
|
(deftest prioritize-user-task-test
|
||||||
|
(is (map? (bb "describe")))
|
||||||
|
(with-config {:tasks {:describe ['babashka "-e" "(+ 1 2 3)"]}}
|
||||||
|
(is (= 6 (bb :describe)))))
|
||||||
|
|
||||||
|
(deftest doc-task-test
|
||||||
|
(with-config {:tasks {:cool-task
|
||||||
|
{:doc "Usage: bb :cool-task
|
||||||
|
|
||||||
|
Addition is a pretty advanced topic. Let us start with the identity element
|
||||||
|
0. ..."
|
||||||
|
:task ['babashka "-e" "(+ 1 2 3)"]}}}
|
||||||
|
(is (str/includes? (apply test-utils/bb nil
|
||||||
|
(map str ["doc" :cool-task]))
|
||||||
|
"Usage: bb :cool-task"))))
|
||||||
|
|
||||||
|
(deftest list-tasks-test
|
||||||
|
(with-config {}
|
||||||
|
(let [res (test-utils/bb nil "tasks")]
|
||||||
|
(is (str/includes? res "No tasks found."))))
|
||||||
|
(with-config {:tasks {:task-1
|
||||||
|
{:description "Return the sum of 1, 2 and 3."
|
||||||
|
:doc "Usage: bb :cool-task
|
||||||
|
|
||||||
|
Addition is a pretty advanced topic. Let us start with the identity element
|
||||||
|
0. ..."}
|
||||||
|
:task ['babashka "-e" "(+ 1 2 3)"]
|
||||||
|
:cool-task-2
|
||||||
|
{:description "Return the sum of 4, 5 and 6."
|
||||||
|
:doc "Usage: bb :cool-task
|
||||||
|
|
||||||
|
Addition is a pretty advanced topic. Let us start with the identity element
|
||||||
|
0. ..."
|
||||||
|
:task ['babashka "-e" "(+ 4 5 6)"]}}}
|
||||||
|
(let [res (test-utils/bb nil "tasks")]
|
||||||
|
(is (str/includes? res "The following tasks are available:"))
|
||||||
|
(is (str/includes? res ":task-1 Return the"))
|
||||||
|
(is (str/includes? res ":cool-task-2 Return the")))))
|
||||||
|
|
||||||
|
(deftest main-task-test
|
||||||
|
(with-config {:paths ["test-resources/task_scripts"]
|
||||||
|
:tasks {:main-task ['main 'tasks 1 2 3]}}
|
||||||
|
(is (= '("1" "2" "3") (bb :main-task)))
|
||||||
|
(let [res (apply test-utils/bb nil
|
||||||
|
(map str ["doc" :main-task]))]
|
||||||
|
(is (str/includes? res "Usage: just pass some args")))))
|
||||||
|
|
||||||
|
(deftest do-test
|
||||||
|
(let [temp-dir (fs/create-temp-dir)
|
||||||
|
temp-file (fs/create-file (fs/path temp-dir "temp-file.txt"))]
|
||||||
|
(with-config {:tasks {:bye ['do
|
||||||
|
['babashka "-e" "(+ 1 2 3)"]
|
||||||
|
['shell "rm" (str temp-file)]]
|
||||||
|
:hello ['do
|
||||||
|
['babashka "-e" "(+ 1 2 3)"]
|
||||||
|
[:bye]]}}
|
||||||
|
(is (fs/exists? temp-file))
|
||||||
|
(bb :hello)
|
||||||
|
(is (not (fs/exists? temp-file))))))
|
||||||
|
|
||||||
|
(deftest clojure-test
|
||||||
|
(let [temp-dir (fs/create-temp-dir)
|
||||||
|
temp-file (fs/create-file (fs/path temp-dir "temp-file.txt"))]
|
||||||
|
(with-config {:tasks {:jvm ['clojure "-M" "-e"
|
||||||
|
(format "(do (require '[clojure.java.io :as io])
|
||||||
|
(.delete (io/file \"%s\")))" (str temp-file))]}}
|
||||||
|
(is (fs/exists? temp-file))
|
||||||
|
(bb :jvm)
|
||||||
|
(is (not (fs/exists? temp-file))))))
|
||||||
|
|
@ -7,21 +7,10 @@
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.java.shell :refer [sh]]
|
[clojure.java.shell :refer [sh]]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[clojure.test :as test :refer [deftest is testing *report-counters*]]
|
[clojure.test :as test :refer [deftest is testing]]
|
||||||
[flatland.ordered.map :refer [ordered-map]]
|
[flatland.ordered.map :refer [ordered-map]]
|
||||||
[sci.core :as sci]))
|
[sci.core :as sci]))
|
||||||
|
|
||||||
(defmethod clojure.test/report :begin-test-var [m]
|
|
||||||
(println "===" (-> m :var meta :name))
|
|
||||||
(println))
|
|
||||||
|
|
||||||
(defmethod clojure.test/report :end-test-var [_m]
|
|
||||||
(let [{:keys [:fail :error]} @*report-counters*]
|
|
||||||
(when (and (= "true" (System/getenv "BABASHKA_FAIL_FAST"))
|
|
||||||
(or (pos? fail) (pos? error)))
|
|
||||||
(println "=== Failing fast")
|
|
||||||
(System/exit 1))))
|
|
||||||
|
|
||||||
(defn bb [input & args]
|
(defn bb [input & args]
|
||||||
(edn/read-string
|
(edn/read-string
|
||||||
{:readers *data-readers*
|
{:readers *data-readers*
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,32 @@
|
||||||
(:require
|
(:require
|
||||||
[babashka.impl.classpath :as cp]
|
[babashka.impl.classpath :as cp]
|
||||||
[babashka.main :as main]
|
[babashka.main :as main]
|
||||||
[me.raynes.conch :refer [let-programs] :as sh]
|
[babashka.process :as p]
|
||||||
|
[clojure.edn :as edn]
|
||||||
|
[clojure.test :as test :refer [*report-counters*]]
|
||||||
[sci.core :as sci]
|
[sci.core :as sci]
|
||||||
[sci.impl.vars :as vars]))
|
[sci.impl.vars :as vars]))
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
|
(def ^:dynamic *bb-edn-path* nil)
|
||||||
|
|
||||||
|
(defmethod clojure.test/report :begin-test-var [m]
|
||||||
|
(println "===" (-> m :var meta :name))
|
||||||
|
(println))
|
||||||
|
|
||||||
|
(defmethod clojure.test/report :end-test-var [_m]
|
||||||
|
(let [{:keys [:fail :error]} @*report-counters*]
|
||||||
|
(when (and (= "true" (System/getenv "BABASHKA_FAIL_FAST"))
|
||||||
|
(or (pos? fail) (pos? error)))
|
||||||
|
(println "=== Failing fast")
|
||||||
|
(System/exit 1))))
|
||||||
|
|
||||||
(defn bb-jvm [input-or-opts & args]
|
(defn bb-jvm [input-or-opts & args]
|
||||||
(reset! cp/cp-state nil)
|
(reset! cp/cp-state nil)
|
||||||
|
(reset! main/env {})
|
||||||
|
(when-let [path *bb-edn-path*]
|
||||||
|
(reset! main/bb-edn (edn/read-string (slurp path))))
|
||||||
(let [os (java.io.StringWriter.)
|
(let [os (java.io.StringWriter.)
|
||||||
es (if-let [err (:err input-or-opts)]
|
es (if-let [err (:err input-or-opts)]
|
||||||
err (java.io.StringWriter.))
|
err (java.io.StringWriter.))
|
||||||
|
|
@ -30,26 +48,33 @@
|
||||||
(if (string? input-or-opts)
|
(if (string? input-or-opts)
|
||||||
(with-in-str input-or-opts (apply main/main args))
|
(with-in-str input-or-opts (apply main/main args))
|
||||||
(apply main/main args)))]
|
(apply main/main args)))]
|
||||||
|
;; (prn :err (str es))
|
||||||
(if (zero? res)
|
(if (zero? res)
|
||||||
(str os)
|
(str os)
|
||||||
|
(do
|
||||||
|
(println (str os))
|
||||||
(throw (ex-info (str es)
|
(throw (ex-info (str es)
|
||||||
{:stdout (str os)
|
{:stdout (str os)
|
||||||
:stderr (str es)})))))
|
:stderr (str es)}))))))
|
||||||
(finally
|
(finally
|
||||||
(when (string? input-or-opts) (vars/bindRoot sci/in *in*))
|
(when (string? input-or-opts) (vars/bindRoot sci/in *in*))
|
||||||
(vars/bindRoot sci/out *out*)
|
(vars/bindRoot sci/out *out*)
|
||||||
(vars/bindRoot sci/err *err*)))))
|
(vars/bindRoot sci/err *err*)))))
|
||||||
|
|
||||||
(defn bb-native [input & args]
|
(defn bb-native [input & args]
|
||||||
(let-programs [bb "./bb"]
|
(let [res (p/process (into ["./bb"] args)
|
||||||
(try (if input
|
(cond-> {:in input
|
||||||
(apply bb (conj (vec args)
|
:out :string
|
||||||
{:in input}))
|
:err :string}
|
||||||
(apply bb args))
|
*bb-edn-path*
|
||||||
(catch Exception e
|
(assoc
|
||||||
(let [d (ex-data e)
|
:env (assoc (into {} (System/getenv))
|
||||||
err-msg (or (:stderr (ex-data e)) "")]
|
"BABASHKA_EDN" *bb-edn-path*))))
|
||||||
(throw (ex-info err-msg d)))))))
|
res (deref res)
|
||||||
|
exit (:exit res)
|
||||||
|
error? (pos? exit)]
|
||||||
|
(if error? (throw (ex-info (or (:err res) "") {}))
|
||||||
|
(:out res))))
|
||||||
|
|
||||||
(def bb
|
(def bb
|
||||||
(case (System/getenv "BABASHKA_TEST_ENV")
|
(case (System/getenv "BABASHKA_TEST_ENV")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue