[#677, #678] babashka.deps add-deps + clojure + clojure subcommand

This commit is contained in:
Michiel Borkent 2020-12-13 11:41:20 +01:00 committed by GitHub
parent af3128527a
commit 7b8745806f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 199 additions and 4 deletions

3
.gitmodules vendored
View file

@ -17,3 +17,6 @@
[submodule "pods"]
path = pods
url = https://github.com/babashka/pods
[submodule "deps.clj"]
path = deps.clj
url = https://github.com/borkdude/deps.clj

1
deps.clj Submodule

@ -0,0 +1 @@
Subproject commit 1418e6d704df5b3331a080a2cff240fdb60c82bf

View file

@ -6,6 +6,7 @@
"sci/src" "babashka.curl/src" "pods/src"
"babashka.nrepl/src"
"depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources"
"resources" "sci/resources"],
:deps {org.clojure/clojure {:mvn/version "1.10.2-alpha2"},
org.clojure/tools.reader {:mvn/version "1.3.3"},

View file

@ -8,7 +8,8 @@
:license {:name "Eclipse Public License 1.0"
:url "http://opensource.org/licenses/eclipse-1.0.php"}
:source-paths ["src" "sci/src" "babashka.curl/src" "pods/src"
"babashka.nrepl/src" "depstar/src" "process/src"]
"babashka.nrepl/src" "depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources"]
;; for debugging Reflector.java code:
;; :java-source-paths ["sci/reflector/src-java"]
:java-source-paths ["src-java"]

120
src/babashka/impl/deps.clj Normal file
View file

@ -0,0 +1,120 @@
(ns babashka.impl.deps
(:require [babashka.impl.classpath :as cp]
[borkdude.deps :as deps]
[clojure.string :as str]
[sci.core :as sci]
[babashka.process :as p]))
(def dns (sci/create-ns 'dns nil))
;;;; merge deps.edn files
(defn- merge-or-replace
"If maps, merge, otherwise replace"
[& vals]
(when (some identity vals)
(reduce (fn [ret val]
(if (and (map? ret) (map? val))
(merge ret val)
(or val ret)))
nil vals)))
(defn merge-deps
"Merge multiple deps edn maps from left to right into a single deps edn map."
[deps-edn-maps]
(apply merge-with merge-or-replace (remove nil? deps-edn-maps)))
(defn- merge-defaults [deps defaults]
(let [overriden (select-keys deps (keys defaults))
overriden-deps (keys overriden)
defaults (select-keys defaults overriden-deps)]
(merge deps defaults)))
(defn merge-default-deps [deps-map defaults]
(let [paths (into [[:deps]]
(map (fn [alias]
[:aliases alias])
(keys (:aliases deps-map))))]
(reduce
(fn [acc path]
(update-in acc path merge-defaults defaults))
deps-map
paths)))
#_(merge-default-deps '{:deps {medley/medley nil}
:aliases {:foo {medley/medley nil}}}
'{medley/medley {:mvn/version "1.3.0"}})
;;;; end merge edn files
;; We are optimizing for the 1-file script with deps scenario where people can
;; call this function to include e.g. {:deps {medley/medley
;; {:mvn/version "1.3.3"}}}. Optionally they can include aliases, to modify the
;; classpath.
(defn add-deps
"Takes deps edn map and optionally a map with :aliases (seq of
keywords) which will used to calculate classpath. The classpath is
then used to resolve dependencies in babashka."
([deps-map] (add-deps deps-map nil))
([deps-map {:keys [:aliases]}]
(let [args ["-Spath" "-Sdeps" (str deps-map)]
args (cond-> args
aliases (conj (str "-A:" (str/join ":" aliases))))
cp (with-out-str (apply deps/-main args))]
(cp/add-classpath cp))))
(defn clojure
"Starts clojure similar to CLI. Use `rlwrap bb` for `clj`-like invocation.
Invokes java with babashka.process/process for `-M`, `-X` and `-A`
and returns the associated record. Default options passed to
babashka.process/process are:
{:in :inherit
:out :inherit
:err :inherit
:shutdown p/destroy-tree}
which can be overriden with opts.
Returns `nil` and prints to *out* for --help, -Spath, -Sdescribe and
-Stree.
Examples:
(-> (clojure '[-M -e (+ 1 2 3)] {:out :string}) deref :out) returns
\"6\n\".
(-> @(clojure) :exit) starts a clojure REPL, waits for it
to finish and returns the exit code from the process."
([] (clojure []))
([args] (clojure args nil))
([args opts]
(let [opts (merge {:in :inherit
:out :inherit
:err :inherit
:shutdown p/destroy-tree}
opts)]
(binding [*in* @sci/in
*out* @sci/out
*err* @sci/err
deps/*process-fn* (fn
([cmd] (p/process cmd opts))
([cmd _] (p/process cmd opts)))
deps/*exit-fn* (fn
([_])
([_exit-code msg]
(throw (Exception. msg))))]
(apply deps/-main (map str args))))))
;; (-> (clojure ["-Sdeps" edn "-M:foo"] {:out :inherit}) p/check)
;; TODO:
;; (uberjar {:out "final.jar" :main 'foo.bar})
;; (uberscript {:out "final.clj" :main 'foo.bar})
(def deps-namespace
{'add-deps (sci/copy-var add-deps dns)
'clojure (sci/copy-var clojure dns)
'merge-deps (sci/copy-var merge-deps dns)
;; undocumented
'merge-defaults (sci/copy-var merge-default-deps dns)})

View file

@ -18,6 +18,7 @@
[babashka.impl.curl :refer [curl-namespace]]
[babashka.impl.data :as data]
[babashka.impl.datafy :refer [datafy-namespace]]
[babashka.impl.deps :as deps :refer [deps-namespace]]
[babashka.impl.error-handler :refer [error-handler]]
[babashka.impl.features :as features]
[babashka.impl.pods :as pods]
@ -30,6 +31,7 @@
[babashka.impl.test :as t]
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
[babashka.nrepl.server :as nrepl-server]
[babashka.process :as process]
[babashka.wait :as wait]
[clojure.edn :as edn]
[clojure.java.io :as io]
@ -109,6 +111,8 @@
(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)
@ -345,7 +349,8 @@ If neither -e, -f, or --socket-repl are specified, then the first argument that
io clojure.java.io
json cheshire.core
curl babashka.curl
bencode bencode.core}
bencode bencode.core
deps babashka.deps}
features/xml? (assoc 'xml 'clojure.data.xml)
features/yaml? (assoc 'yaml 'clj-yaml.core)
features/jdbc? (assoc 'jdbc 'next.jdbc)
@ -391,7 +396,8 @@ If neither -e, -f, or --socket-repl are specified, then the first argument that
'clojure.datafy datafy-namespace
'clojure.core.protocols protocols-namespace
'clojure.core.server clojure-core-server
'babashka.process process-namespace}
'babashka.process process-namespace
'babashka.deps deps-namespace}
features/xml? (assoc 'clojure.data.xml @(resolve 'babashka.impl.xml/xml-namespace))
features/yaml? (assoc 'clj-yaml.core @(resolve 'babashka.impl.yaml/yaml-namespace)
'flatland.ordered.map @(resolve 'babashka.impl.ordered/ordered-map-ns))
@ -476,8 +482,12 @@ If neither -e, -f, or --socket-repl are specified, then the first argument that
:repl :socket-repl :nrepl
:verbose? :classpath
:main :uberscript :describe?
:jar :uberjar] :as _opts}
:jar :uberjar :clojure] :as opts}
(parse-opts args)
_ (when clojure
(if-let [proc (deps/clojure (:opts opts))]
(-> @proc :exit (System/exit))
(System/exit 0)))
_ (when verbose? (vreset! common/verbose? true))
_ (do ;; set properties
(when main (System/setProperty "babashka.main" main))

View file

@ -0,0 +1,59 @@
(ns babashka.deps-test
(:require
[babashka.test-utils :as test-utils]
[clojure.edn :as edn]
[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))))
(deftest dependency-test (is (= #{:a :c :b} (bb "
(require '[babashka.deps :as deps])
(deps/add-deps '{:deps {com.stuartsierra/dependency {:mvn/version \"1.0.0\"}}})
(require '[com.stuartsierra.dependency :as dep])
(def g1 (-> (dep/graph)
(dep/depend :b :a)
(dep/depend :c :b)
(dep/depend :c :a)
(dep/depend :d :c)))
(dep/transitive-dependencies g1 :d)
"))))
(deftest clojure-test
(testing "-Stree prints to *out*"
(is (true? (bb "
(require '[babashka.deps :as deps])
(require '[clojure.string :as str])
(str/includes?
(with-out-str (babashka.deps/clojure [\"-Stree\"]))
\"org.clojure/clojure\")
"))))
(testing "-P does not exit babashka script"
(is (true? (bb "
(require '[babashka.deps :as deps])
(require '[clojure.string :as str])
(babashka.deps/clojure [\"-P\"])
true
"))))
(is (= "6\n" (bb "
(require '[babashka.deps :as deps])
(require '[babashka.process :as p])
(-> (babashka.deps/clojure [\"-M\" \"-e\" \"(+ 1 2 3)\"] {:out :string})
(p/check)
:out)
")))
(when-not test-utils/native?
(is (thrown-with-msg? Exception #"Option changed" (bb "
(require '[babashka.deps :as deps])
(babashka.deps/clojure [\"-Sresolve-tags\"])
"))))
(is (true? (bb "
(= 5 (:exit @(babashka.deps/clojure [] {:in \"(System/exit 5)\" :out :string})))"))))