[#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
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
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))))
opts-map)))
(defn parse-opts [options]
(let [opt (first options)
tasks (into #{} (map str) (keys (:tasks @common/bb-edn)))]
(when opt
(cond (contains? tasks opt)
{:run opt
:command-line-args (rest options)}
(fs/regular-file? opt)
(if (str/ends-with? opt ".jar")
{:jar opt
:command-line-args (next options)}
{:file opt
:command-line-args (next options)})
(command? 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)}
("--verbose") (recur (next options)
(assoc opts-map
:verbose? true))
("--describe") (recur (next options)
(defn parse-classpath [options]
(when-let [f (first options)]
(case f
("--classpath" "-cp") [(nnext options) (second options)]
[options nil])))
(defn parse-opts
([options] (parse-opts options nil))
([options opts]
(let [[options classpath] (parse-classpath options)
opts (if classpath (assoc opts :classpath classpath)
opts)
opt (first options)
tasks (into #{} (map str) (keys (:tasks @common/bb-edn)))]
(when opt
(cond (contains? tasks opt)
{:run opt
:classpath classpath
:command-line-args (rest options)}
(fs/regular-file? opt)
(if (str/ends-with? opt ".jar")
{:classpath classpath
:jar opt
:command-line-args (next options)}
{:classpath classpath
:file opt
:command-line-args (next options)})
(command? opt)
(recur (cons (str "--" opt) (next options)) opts)
:else
(let [opts (loop [options options
opts-map opts]
(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)}
("--verbose") (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)
: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-in true
:shell-out true))
("-iO") (recur (next options)
("-O") (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))))
("--run")
(parse-run-opts opts-map (next options))
("--tasks")
(assoc opts-map :list-tasks true
:command-line-args (next options))
;; fallback
(if (some opts-map [:file :jar :socket-repl :expressions :main :run])
(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)))))
("-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))))
("--run")
(parse-run-opts opts-map (next options))
("--tasks")
(assoc opts-map :list-tasks true
:command-line-args (next options))
;; fallback
(if (and opts-map
(some opts-map [:file :jar :socket-repl :expressions :main :run]))
(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 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 expression :append true)))
(when uberjar
(uberjar/run {:dest uberjar
:jar :uber
:classpath (cp/get-classpath)
:main-class main
:verbose verbose?}))
(if-let [cp (cp/get-classpath)]
(uberjar/run {:dest uberjar
:jar :uber
:classpath cp
:main-class main
:verbose verbose?})
(throw (Exception. "The uberjar task needs a classpath."))))
exit-code))))
(defn main [& args]

View file

@ -18,18 +18,23 @@
(apply test-utils/bb (when (some? input) (str input)) (map str args))))
(deftest parse-opts-test
(is (= {:nrepl "1667"}
(main/parse-opts ["--nrepl-server"])))
(is (= {:socket-repl "1666"}
(main/parse-opts ["--socket-repl"])))
(is (= "1667"
(:nrepl (main/parse-opts ["--nrepl-server"]))))
(is (= "1666"
(:socket-repl (main/parse-opts ["--socket-repl"]))))
(is (= {:nrepl "1667", :classpath "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"]}
(main/parse-opts ["--socket-repl" "-e" "123"])))
(is (= {:socket-repl "1666", :expressions ["123"]}
(main/parse-opts ["--socket-repl" "1666" "-e" "123"])))
(is (= {:nrepl "1666", :expressions ["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 "-e" "(println 123)")))
(is (= 123 (bb nil "--eval" "(println 123)")))

View file

@ -9,7 +9,7 @@
(let [tmp-file (java.io.File/createTempFile "uber" ".jar")
path (.getPath 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"
(tu/bb nil "--jar" path "1" "2" "3" "4")))
(is (= "(\"1\" \"2\" \"3\" \"4\")\n"
@ -24,7 +24,7 @@
(let [tmp-file (java.io.File/createTempFile "uber" ".jar")
path (.getPath 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"))))
(testing "use bb.edn classpath when no other --classpath"
(tu/with-config {:paths ["test-resources/babashka/uberjar/src"]}