[#780] Fix uberjar CLI parsing and throw when no classpath is provided

This commit is contained in:
Michiel Borkent 2021-04-22 11:56:13 +02:00 committed by GitHub
parent 3dfc15f5a4
commit 15e71b0807
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 195 additions and 155 deletions

@ -1 +1 @@
Subproject commit e74b8ac05c64efb815153fbfdd2d31e3cad098cb Subproject commit c419b8c82041855d55593c5b561fc7cea8234712

View file

@ -81,6 +81,24 @@ To progress work on sqlite and mySQL, I need a working Clojure example. If you
want to contribute, consider making a an example Clojure GraalVM CLI that puts want to contribute, consider making a an example Clojure GraalVM CLI that puts
something in a sqlite / mysql DB and reads something from it. something in a sqlite / mysql DB and reads something from it.
## ADR
Some decisions:
### bb.edn
- We chose the name `bb.edn` (rather than `babashka.edn`) for the configuration
file based on this
[poll](https://twitter.com/borkdude/status/1374720217608302595). The name `bb`
combined with `.edn` is not likely to cause conflicts with other tools.
- We did not choose to put the babashka configuration in `deps.edn` to keep bb config isolated (and more flexible) and also support it in projects that do not use `deps.edn`
### .babashka
- Rather than naming the home config dir `~/.bb` we chose `~/.babashka` to
prevent conflicts with other global tools. We might introduce a project local
`~/.babashka` directory for storing caches or whatnot too.
## Binary size ## Binary size
Keep notes here about how adding libraries and classes to Babashka affects the binary size. Keep notes here about how adding libraries and classes to Babashka affects the binary size.

View file

@ -415,154 +415,169 @@ When no eval opts or subcommand is provided, the implicit subcommand is repl.")
(assoc opts-map :run fst :command-line-args (next args)))) (assoc opts-map :run fst :command-line-args (next args))))
opts-map))) opts-map)))
(defn parse-opts [options] (defn parse-classpath [options]
(let [opt (first options) (when-let [f (first options)]
tasks (into #{} (map str) (keys (:tasks @common/bb-edn)))] (case f
(when opt ("--classpath" "-cp") [(nnext options) (second options)]
(cond (contains? tasks opt) [options nil])))
{:run opt
:command-line-args (rest options)} (defn parse-opts
(fs/regular-file? opt) ([options] (parse-opts options nil))
(if (str/ends-with? opt ".jar") ([options opts]
{:jar opt (let [[options classpath] (parse-classpath options)
:command-line-args (next options)} opts (if classpath (assoc opts :classpath classpath)
{:file opt opts)
:command-line-args (next options)}) opt (first options)
(command? opt) tasks (into #{} (map str) (keys (:tasks @common/bb-edn)))]
(recur (cons (str "--" opt) (next options))) (when opt
:else (cond (contains? tasks opt)
(let [opts (loop [options options {:run opt
opts-map {}] :classpath classpath
(if options :command-line-args (rest options)}
(let [opt (first options)] (fs/regular-file? opt)
(case opt (if (str/ends-with? opt ".jar")
("--") (assoc opts-map :command-line-args (next options)) {:classpath classpath
("--clojure") (assoc opts-map :clojure true :jar opt
:command-line-args (rest options)) :command-line-args (next options)}
("--version") {:version true} {:classpath classpath
("--help" "-h" "-?" "help") :file opt
{:help true :command-line-args (next options)})
:command-line-args (rest options)} (command? opt)
("--doc") (recur (cons (str "--" opt) (next options)) opts)
{:doc true :else
:command-line-args (rest options)} (let [opts (loop [options options
("--verbose") (recur (next options) opts-map opts]
(assoc opts-map (if options
:verbose? true)) (let [opt (first options)]
("--describe") (recur (next 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)}
("--verbose") (recur (next options)
(assoc opts-map (assoc opts-map
:describe? true)) :verbose? true))
("--stream") (recur (next options) ("--describe") (recur (next options)
(assoc opts-map (assoc opts-map
:stream? true)) :describe? true))
("-i") (recur (next options) ("--stream") (recur (next options)
(assoc opts-map (assoc opts-map
:shell-in true)) :stream? true))
("-I") (recur (next options) ("-i") (recur (next options)
(assoc opts-map (assoc opts-map
:edn-in true)) :shell-in true))
("-o") (recur (next options) ("-I") (recur (next options)
(assoc opts-map (assoc opts-map
:shell-out true)) :edn-in true))
("-O") (recur (next options) ("-o") (recur (next options)
(assoc opts-map
:edn-out true))
("-io") (recur (next options)
(assoc opts-map (assoc opts-map
:shell-in true
:shell-out true)) :shell-out true))
("-iO") (recur (next options) ("-O") (recur (next options)
(assoc opts-map (assoc opts-map
:shell-in true
:edn-out true)) :edn-out true))
("-Io") (recur (next options) ("-io") (recur (next options)
(assoc opts-map (assoc opts-map
:edn-in true :shell-in true
:shell-out true)) :shell-out true))
("-IO") (recur (next options) ("-iO") (recur (next options)
(assoc opts-map (assoc opts-map
:edn-in true :shell-in true
:edn-out true)) :edn-out true))
("--classpath", "-cp") ("-Io") (recur (next options)
(let [options (next options)] (assoc opts-map
(recur (next options) :edn-in true
(assoc opts-map :classpath (first options)))) :shell-out true))
("--uberscript") ("-IO") (recur (next options)
(let [options (next options)] (assoc opts-map
(recur (next options) :edn-in true
(assoc opts-map :edn-out true))
:uberscript (first options)))) ("--classpath", "-cp")
("--uberjar") (let [options (next options)]
(let [options (next options)] (recur (next options)
(recur (next options) (assoc opts-map :classpath (first options))))
(assoc opts-map ("--uberscript")
:uberjar (first options)))) (let [options (next options)]
("-f" "--file") (recur (next options)
(let [options (next options)] (assoc opts-map
(recur (next options) :uberscript (first options))))
(assoc opts-map ("--uberjar")
:file (first options)))) (let [options (next options)]
("--jar" "-jar") (recur (next options)
(let [options (next options)] (assoc opts-map
(recur (next options) :uberjar (first options))))
(assoc opts-map ("-f" "--file")
:jar (first options)))) (let [options (next options)]
("--repl") (recur (next options)
(let [options (next options)] (assoc opts-map
(recur (next options) :file (first options))))
(assoc opts-map ("--jar" "-jar")
:repl true))) (let [options (next options)]
("--socket-repl") (recur (next options)
(let [options (next options) (assoc opts-map
opt (first options) :jar (first options))))
opt (when (and opt (not (str/starts-with? opt "-"))) ("--repl")
opt) (let [options (next options)]
options (if opt (next options) (recur (next options)
options)] (assoc opts-map
(recur options :repl true)))
(assoc opts-map ("--socket-repl")
:socket-repl (or opt "1666")))) (let [options (next options)
("--nrepl-server") opt (first options)
(let [options (next options) opt (when (and opt (not (str/starts-with? opt "-")))
opt (first options) opt)
opt (when (and opt (not (str/starts-with? opt "-"))) options (if opt (next options)
opt) options)]
options (if opt (next options) (recur options
options)] (assoc opts-map
(recur options :socket-repl (or opt "1666"))))
(assoc opts-map ("--nrepl-server")
:nrepl (or opt "1667")))) (let [options (next options)
("--eval", "-e") opt (first options)
(let [options (next options)] opt (when (and opt (not (str/starts-with? opt "-")))
(recur (next options) opt)
(update opts-map :expressions (fnil conj []) (first options)))) options (if opt (next options)
("--main", "-m",) options)]
(let [options (next options)] (recur options
(recur (next options) (assoc opts-map
(assoc opts-map :main (first options)))) :nrepl (or opt "1667"))))
("--run") ("--eval", "-e")
(parse-run-opts opts-map (next options)) (let [options (next options)]
("--tasks") (recur (next options)
(assoc opts-map :list-tasks true (update opts-map :expressions (fnil conj []) (first options))))
:command-line-args (next options)) ("--main", "-m",)
;; fallback (let [options (next options)]
(if (some opts-map [:file :jar :socket-repl :expressions :main :run]) (recur (next options)
(assoc opts-map (assoc opts-map :main (first options))))
:command-line-args options) ("--run")
(let [trimmed-opt (str/triml opt) (parse-run-opts opts-map (next options))
c (.charAt trimmed-opt 0)] ("--tasks")
(case c (assoc opts-map :list-tasks true
(\( \{ \[ \* \@ \#) :command-line-args (next options))
(-> opts-map ;; fallback
(update :expressions (fnil conj []) (first options)) (if (and opts-map
(assoc :command-line-args (next options))) (some opts-map [:file :jar :socket-repl :expressions :main :run]))
(assoc opts-map (assoc opts-map
(if (str/ends-with? opt ".jar") :command-line-args options)
:jar (let [trimmed-opt (str/triml opt)
:file) opt c (.charAt trimmed-opt 0)]
:command-line-args (next options))))))) (case c
opts-map))] (\( \{ \[ \* \@ \#)
opts))))) (-> 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 env (atom {})) (def env (atom {}))
@ -750,11 +765,13 @@ When no eval opts or subcommand is provided, the implicit subcommand is repl.")
(spit uberscript-out preloads :append true) (spit uberscript-out preloads :append true)
(spit uberscript-out expression :append true))) (spit uberscript-out expression :append true)))
(when uberjar (when uberjar
(uberjar/run {:dest uberjar (if-let [cp (cp/get-classpath)]
:jar :uber (uberjar/run {:dest uberjar
:classpath (cp/get-classpath) :jar :uber
:main-class main :classpath cp
:verbose verbose?})) :main-class main
:verbose verbose?})
(throw (Exception. "The uberjar task needs a classpath."))))
exit-code)))) exit-code))))
(defn main [& args] (defn main [& args]

View file

@ -18,18 +18,23 @@
(apply test-utils/bb (when (some? input) (str input)) (map str args)))) (apply test-utils/bb (when (some? input) (str input)) (map str args))))
(deftest parse-opts-test (deftest parse-opts-test
(is (= {:nrepl "1667"} (is (= "1667"
(main/parse-opts ["--nrepl-server"]))) (:nrepl (main/parse-opts ["--nrepl-server"]))))
(is (= {:socket-repl "1666"} (is (= "1666"
(main/parse-opts ["--socket-repl"]))) (:socket-repl (main/parse-opts ["--socket-repl"]))))
(is (= {:nrepl "1667", :classpath "src"} (is (= {:nrepl "1667", :classpath "src"}
(main/parse-opts ["--nrepl-server" "-cp" "src"]))) (main/parse-opts ["--nrepl-server" "-cp" "src"])))
(is (= {:nrepl "1667", :classpath "src"}
(main/parse-opts ["-cp" "src" "nrepl-server"])))
(is (= {:socket-repl "1666", :expressions ["123"]} (is (= {:socket-repl "1666", :expressions ["123"]}
(main/parse-opts ["--socket-repl" "-e" "123"]))) (main/parse-opts ["--socket-repl" "-e" "123"])))
(is (= {:socket-repl "1666", :expressions ["123"]} (is (= {:socket-repl "1666", :expressions ["123"]}
(main/parse-opts ["--socket-repl" "1666" "-e" "123"]))) (main/parse-opts ["--socket-repl" "1666" "-e" "123"])))
(is (= {:nrepl "1666", :expressions ["123"]} (is (= {:nrepl "1666", :expressions ["123"]}
(main/parse-opts ["--nrepl-server" "1666" "-e" "123"]))) (main/parse-opts ["--nrepl-server" "1666" "-e" "123"])))
(is (= {:classpath "src"
:uberjar "foo.jar"}
(main/parse-opts ["--classpath" "src" "uberjar" "foo.jar"])))
(is (= 123 (bb nil "(println 123)"))) (is (= 123 (bb nil "(println 123)")))
(is (= 123 (bb nil "-e" "(println 123)"))) (is (= 123 (bb nil "-e" "(println 123)")))
(is (= 123 (bb nil "--eval" "(println 123)"))) (is (= 123 (bb nil "--eval" "(println 123)")))

View file

@ -9,7 +9,7 @@
(let [tmp-file (java.io.File/createTempFile "uber" ".jar") (let [tmp-file (java.io.File/createTempFile "uber" ".jar")
path (.getPath tmp-file)] path (.getPath tmp-file)]
(.deleteOnExit tmp-file) (.deleteOnExit tmp-file)
(tu/bb nil "uberjar" path "--classpath" "test-resources/babashka/uberjar/src" "-m" "my.main-main") (tu/bb nil "--classpath" "test-resources/babashka/uberjar/src" "uberjar" path "-m" "my.main-main")
(is (= "(\"1\" \"2\" \"3\" \"4\")\n" (is (= "(\"1\" \"2\" \"3\" \"4\")\n"
(tu/bb nil "--jar" path "1" "2" "3" "4"))) (tu/bb nil "--jar" path "1" "2" "3" "4")))
(is (= "(\"1\" \"2\" \"3\" \"4\")\n" (is (= "(\"1\" \"2\" \"3\" \"4\")\n"
@ -24,7 +24,7 @@
(let [tmp-file (java.io.File/createTempFile "uber" ".jar") (let [tmp-file (java.io.File/createTempFile "uber" ".jar")
path (.getPath tmp-file)] path (.getPath tmp-file)]
(.deleteOnExit tmp-file) (.deleteOnExit tmp-file)
(tu/bb nil "uberjar" path "--classpath" "test-resources/babashka/uberjar/src") (tu/bb nil "--classpath" "test-resources/babashka/uberjar/src" "uberjar" path)
(is (str/includes? (tu/bb "(+ 1 2 3)" path) "6")))) (is (str/includes? (tu/bb "(+ 1 2 3)" path) "6"))))
(testing "use bb.edn classpath when no other --classpath" (testing "use bb.edn classpath when no other --classpath"
(tu/with-config {:paths ["test-resources/babashka/uberjar/src"]} (tu/with-config {:paths ["test-resources/babashka/uberjar/src"]}