diff --git a/API.md b/API.md
index b20987c..cd977d2 100644
--- a/API.md
+++ b/API.md
@@ -5,6 +5,7 @@
- [`*clojure-tools-download-fn*`](#borkdude.deps/*clojure-tools-download-fn*) - Can be dynamically rebound to customise the download of the Clojure tools.
- [`*dir*`](#borkdude.deps/*dir*) - Directory in which deps.clj should be executed.
- [`*exit-fn*`](#borkdude.deps/*exit-fn*) - Function that is called on exit with :exit
code and :message
, an exceptional message when exit is non-zero.
+ - [`*getenv-fn*`](#borkdude.deps/*getenv-fn*) - Get ENV'ironment variable, typically used for getting CLJ_CONFIG
, etc.
- [`-main`](#borkdude.deps/-main) - See help-text
.
- [`clojure-tools-download-direct!`](#borkdude.deps/clojure-tools-download-direct!) - Downloads from :url
to :dest
file returning true on success.
- [`clojure-tools-download-java!`](#borkdude.deps/clojure-tools-download-java!) - Downloads :url
zip file to :dest
by invoking java
with :proxy
options on a .java
program file, and returns true on success.
@@ -101,6 +102,15 @@ Directory in which deps.clj should be executed.
Function that is called on exit with `:exit` code and `:message`, an exceptional message when exit is non-zero
Source
+## `*getenv-fn*`
+``` clojure
+
+(*getenv-fn* env)
+```
+
+Get ENV'ironment variable, typically used for getting `CLJ_CONFIG`, etc.
+Source
+
## `-main`
``` clojure
diff --git a/deps.bat b/deps.bat
index c363da1..f755f86 100644
--- a/deps.bat
+++ b/deps.bat
@@ -122,7 +122,7 @@
(defn ^:dynamic *aux-process-fn*
"Invokes `java` with arguments to calculate classpath, etc. May be
- replacement by rebinding this dynamic var.
+ replaced by rebinding this dynamic var.
Called with a map of:
@@ -138,13 +138,13 @@
(defn ^:dynamic *clojure-process-fn*
"Invokes `java` with arguments to `clojure.main` to start Clojure. May
- be replacement by rebinding this dynamic var.
+ be replaced by rebinding this dynamic var.
Called with a map of:
- `:cmd`: a vector of strings
- Must return a map of `:exit`, the exit code of te process."
+ Must return a map of `:exit`, the exit code of the process."
[{:keys [cmd]}]
(internal-shell-command cmd))
@@ -241,8 +241,8 @@ For more info, see:
(print "\n ") (describe-line line))
(println "}")))
-(defn- ^:dynamic *getenv-fn*
- "Get ENV'ironment variable. Only used for testing, not part of the public API (yet)."
+(defn ^:dynamic *getenv-fn*
+ "Get ENV'ironment variable, typically used for getting `CLJ_CONFIG`, etc."
^String [env]
(java.lang.System/getenv env))
@@ -335,7 +335,7 @@ For more info, see:
(defn set-proxy-system-props!
"Sets the proxy system properties in the current JVM.
- proxy-info parameter is as returned from env-proxy-info."
+ proxy-info parameter is as returned from `get-proxy-info.`"
[{:keys [http-proxy https-proxy]}]
(when http-proxy
(System/setProperty "http.proxyHost" (:host http-proxy))
@@ -454,7 +454,7 @@ public class ClojureToolsDownloader {
(defn proxy-jvm-opts
"Returns a vector containing the JVM system property arguments to be passed to a new process
to set its proxy system properties.
- proxy-info parameter is as returned from env-proxy-info."
+ proxy-info parameter is as returned from `get-proxy-info.`"
[{:keys [http-proxy https-proxy]}]
(cond-> []
http-proxy (concat [(str "-Dhttp.proxyHost=" (:host http-proxy))
@@ -490,16 +490,20 @@ public class ClojureToolsDownloader {
- `:dest`: The path to the file to download it to, as a string
- `:proxy-opts`: a map as returned by `get-proxy-info`
- `:clj-jvm-opts`: a vector of JVM opts (as passed on the command line).
- Should return true if the `download` was successful, or false if not."
+
+ Should return `true` if the download was successful, or false if not."
nil)
-(defn clojure-tools-download!
- "Downloads clojure tools archive in `:out-dir`, if not already there,
- and extracts in-place the clojure tools jar file and other important
- files.
+(defn clojure-tools-install!
+ "Installs clojure tools archive by downloading it in `:out-dir`, if not already there,
+ and extracting in-place.
+
+ If `*clojure-tools-download-fn*` is set, it will be called for
+ download the tools archive. This function should return a truthy
+ value to indicate a successful download.
The download is attempted directly from this process, unless
- `:jvm-opts` is set, in which case a java subprocess
+ `:clj-jvm-opts` is set, in which case a java subprocess
is created to download the archive passing in its value as command
line options.
@@ -722,16 +726,19 @@ public class ClojureToolsDownloader {
[(.getPath (io/file config-dir "deps.edn"))
deps-edn])))
-(defn- calculate-checksum [opts config-paths]
+(defn get-checksum
+ "Returns checksum based on cli-opts (as returned by `parse-cli-opts`)
+ and config-paths (as returned by `get-config-paths`)"
+ [{:keys [cli-opts config-paths]}]
(let [val*
(str/join "|"
(concat [cache-version]
- (:repl-aliases opts)
- [(:exec-aliases opts)
- (:main-aliases opts)
- (:deps-data opts)
- (:tool-name opts)
- (:tool-aliases opts)]
+ (:repl-aliases cli-opts)
+ [(:exec-aliases cli-opts)
+ (:main-aliases cli-opts)
+ (:deps-data cli-opts)
+ (:tool-name cli-opts)
+ (:tool-aliases cli-opts)]
(map (fn [config-path]
(if (.exists (io/file config-path))
config-path
@@ -749,6 +756,27 @@ public class ClojureToolsDownloader {
[]
(println @help-text))
+(defn get-basis-file
+ "Returns path to basis file. Required options:
+
+ * - `cache-dir` as returned by `get-cache-dir`
+ * - `checksum` as returned by `get-check-sum`"
+ [{:keys [cache-dir checksum]}]
+ (.getPath (io/file cache-dir (str checksum ".basis"))))
+
+(defn- auto-file-arg [cp]
+ ;; see https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553
+ ;; command line limit on Windows with process builder
+ (if (and windows? (> (count cp) 32766))
+ (let [tmp-file (.toFile (java.nio.file.Files/createTempFile
+ "file_arg" ".txt"
+ (into-array java.nio.file.attribute.FileAttribute [])))]
+ (.deleteOnExit tmp-file)
+ ;; we use pr-str since whitespaces in the classpath will be treated as separate args otherwise
+ (spit tmp-file (pr-str cp))
+ (str "@" tmp-file))
+ cp))
+
(defn -main
"See `help-text`.
@@ -789,7 +817,7 @@ public class ClojureToolsDownloader {
(when (.exists tools-jar) (.getPath tools-jar))
(binding [*out* *err*]
(warn "Clojure tools not yet in expected location:" (str tools-jar))
- (clojure-tools-download! {:out-dir libexec-dir :debug debug :clj-jvm-opts clj-jvm-opts :proxy-opts proxy-opts})
+ (clojure-tools-install! {:out-dir libexec-dir :debug debug :clj-jvm-opts clj-jvm-opts :proxy-opts proxy-opts})
tools-jar))
mode (:mode cli-opts)
exec? (= :exec mode)
@@ -835,11 +863,11 @@ public class ClojureToolsDownloader {
;; Construct location of cached classpath file
tool-name (:tool-name cli-opts)
tool-aliases (:tool-aliases cli-opts)
- ck (calculate-checksum cli-opts config-paths)
+ ck (get-checksum {:cli-opts cli-opts :config-paths config-paths})
cp-file (.getPath (io/file cache-dir (str ck ".cp")))
jvm-file (.getPath (io/file cache-dir (str ck ".jvm")))
main-file (.getPath (io/file cache-dir (str ck ".main")))
- basis-file (.getPath (io/file cache-dir (str ck ".basis")))
+ basis-file (get-basis-file {:cache-dir cache-dir :checksum ck})
manifest-file (.getPath (io/file cache-dir (str ck ".manifest")))
_ (when (:verbose cli-opts)
(println "deps.clj version =" deps-clj-version)
@@ -988,7 +1016,7 @@ public class ClojureToolsDownloader {
jvm-cache-opts
(:jvm-opts cli-opts)
[(str "-Dclojure.basis=" (relativize basis-file))
- "-classpath" cp
+ "-classpath" (auto-file-arg cp)
"clojure.main"]
main-opts)
main-args (filterv some? main-args)
diff --git a/deps.clj b/deps.clj
index 54a9351..78bf421 100755
--- a/deps.clj
+++ b/deps.clj
@@ -117,7 +117,7 @@
(defn ^:dynamic *aux-process-fn*
"Invokes `java` with arguments to calculate classpath, etc. May be
- replacement by rebinding this dynamic var.
+ replaced by rebinding this dynamic var.
Called with a map of:
@@ -133,13 +133,13 @@
(defn ^:dynamic *clojure-process-fn*
"Invokes `java` with arguments to `clojure.main` to start Clojure. May
- be replacement by rebinding this dynamic var.
+ be replaced by rebinding this dynamic var.
Called with a map of:
- `:cmd`: a vector of strings
- Must return a map of `:exit`, the exit code of te process."
+ Must return a map of `:exit`, the exit code of the process."
[{:keys [cmd]}]
(internal-shell-command cmd))
@@ -236,8 +236,8 @@ For more info, see:
(print "\n ") (describe-line line))
(println "}")))
-(defn- ^:dynamic *getenv-fn*
- "Get ENV'ironment variable. Only used for testing, not part of the public API (yet)."
+(defn ^:dynamic *getenv-fn*
+ "Get ENV'ironment variable, typically used for getting `CLJ_CONFIG`, etc."
^String [env]
(java.lang.System/getenv env))
@@ -330,7 +330,7 @@ For more info, see:
(defn set-proxy-system-props!
"Sets the proxy system properties in the current JVM.
- proxy-info parameter is as returned from env-proxy-info."
+ proxy-info parameter is as returned from `get-proxy-info.`"
[{:keys [http-proxy https-proxy]}]
(when http-proxy
(System/setProperty "http.proxyHost" (:host http-proxy))
@@ -449,7 +449,7 @@ public class ClojureToolsDownloader {
(defn proxy-jvm-opts
"Returns a vector containing the JVM system property arguments to be passed to a new process
to set its proxy system properties.
- proxy-info parameter is as returned from env-proxy-info."
+ proxy-info parameter is as returned from `get-proxy-info.`"
[{:keys [http-proxy https-proxy]}]
(cond-> []
http-proxy (concat [(str "-Dhttp.proxyHost=" (:host http-proxy))
@@ -485,16 +485,20 @@ public class ClojureToolsDownloader {
- `:dest`: The path to the file to download it to, as a string
- `:proxy-opts`: a map as returned by `get-proxy-info`
- `:clj-jvm-opts`: a vector of JVM opts (as passed on the command line).
- Should return true if the `download` was successful, or false if not."
+
+ Should return `true` if the download was successful, or false if not."
nil)
-(defn clojure-tools-download!
- "Downloads clojure tools archive in `:out-dir`, if not already there,
- and extracts in-place the clojure tools jar file and other important
- files.
+(defn clojure-tools-install!
+ "Installs clojure tools archive by downloading it in `:out-dir`, if not already there,
+ and extracting in-place.
+
+ If `*clojure-tools-download-fn*` is set, it will be called for
+ download the tools archive. This function should return a truthy
+ value to indicate a successful download.
The download is attempted directly from this process, unless
- `:jvm-opts` is set, in which case a java subprocess
+ `:clj-jvm-opts` is set, in which case a java subprocess
is created to download the archive passing in its value as command
line options.
@@ -717,16 +721,19 @@ public class ClojureToolsDownloader {
[(.getPath (io/file config-dir "deps.edn"))
deps-edn])))
-(defn- calculate-checksum [opts config-paths]
+(defn get-checksum
+ "Returns checksum based on cli-opts (as returned by `parse-cli-opts`)
+ and config-paths (as returned by `get-config-paths`)"
+ [{:keys [cli-opts config-paths]}]
(let [val*
(str/join "|"
(concat [cache-version]
- (:repl-aliases opts)
- [(:exec-aliases opts)
- (:main-aliases opts)
- (:deps-data opts)
- (:tool-name opts)
- (:tool-aliases opts)]
+ (:repl-aliases cli-opts)
+ [(:exec-aliases cli-opts)
+ (:main-aliases cli-opts)
+ (:deps-data cli-opts)
+ (:tool-name cli-opts)
+ (:tool-aliases cli-opts)]
(map (fn [config-path]
(if (.exists (io/file config-path))
config-path
@@ -744,6 +751,27 @@ public class ClojureToolsDownloader {
[]
(println @help-text))
+(defn get-basis-file
+ "Returns path to basis file. Required options:
+
+ * - `cache-dir` as returned by `get-cache-dir`
+ * - `checksum` as returned by `get-check-sum`"
+ [{:keys [cache-dir checksum]}]
+ (.getPath (io/file cache-dir (str checksum ".basis"))))
+
+(defn- auto-file-arg [cp]
+ ;; see https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553
+ ;; command line limit on Windows with process builder
+ (if (and windows? (> (count cp) 32766))
+ (let [tmp-file (.toFile (java.nio.file.Files/createTempFile
+ "file_arg" ".txt"
+ (into-array java.nio.file.attribute.FileAttribute [])))]
+ (.deleteOnExit tmp-file)
+ ;; we use pr-str since whitespaces in the classpath will be treated as separate args otherwise
+ (spit tmp-file (pr-str cp))
+ (str "@" tmp-file))
+ cp))
+
(defn -main
"See `help-text`.
@@ -784,7 +812,7 @@ public class ClojureToolsDownloader {
(when (.exists tools-jar) (.getPath tools-jar))
(binding [*out* *err*]
(warn "Clojure tools not yet in expected location:" (str tools-jar))
- (clojure-tools-download! {:out-dir libexec-dir :debug debug :clj-jvm-opts clj-jvm-opts :proxy-opts proxy-opts})
+ (clojure-tools-install! {:out-dir libexec-dir :debug debug :clj-jvm-opts clj-jvm-opts :proxy-opts proxy-opts})
tools-jar))
mode (:mode cli-opts)
exec? (= :exec mode)
@@ -830,11 +858,11 @@ public class ClojureToolsDownloader {
;; Construct location of cached classpath file
tool-name (:tool-name cli-opts)
tool-aliases (:tool-aliases cli-opts)
- ck (calculate-checksum cli-opts config-paths)
+ ck (get-checksum {:cli-opts cli-opts :config-paths config-paths})
cp-file (.getPath (io/file cache-dir (str ck ".cp")))
jvm-file (.getPath (io/file cache-dir (str ck ".jvm")))
main-file (.getPath (io/file cache-dir (str ck ".main")))
- basis-file (.getPath (io/file cache-dir (str ck ".basis")))
+ basis-file (get-basis-file {:cache-dir cache-dir :checksum ck})
manifest-file (.getPath (io/file cache-dir (str ck ".manifest")))
_ (when (:verbose cli-opts)
(println "deps.clj version =" deps-clj-version)
@@ -983,7 +1011,7 @@ public class ClojureToolsDownloader {
jvm-cache-opts
(:jvm-opts cli-opts)
[(str "-Dclojure.basis=" (relativize basis-file))
- "-classpath" cp
+ "-classpath" (auto-file-arg cp)
"clojure.main"]
main-opts)
main-args (filterv some? main-args)
diff --git a/src/borkdude/deps.clj b/src/borkdude/deps.clj
index 5906b53..3d68b12 100755
--- a/src/borkdude/deps.clj
+++ b/src/borkdude/deps.clj
@@ -16,7 +16,7 @@
;; see https://github.com/clojure/brew-install/blob/1.11.1/CHANGELOG.md
(def ^:private version
(delay (or (System/getenv "DEPS_CLJ_TOOLS_VERSION")
- "1.11.1.1273")))
+ "1.11.1.1347")))
(def ^:private cache-version "4")
@@ -233,8 +233,8 @@ For more info, see:
(print "\n ") (describe-line line))
(println "}")))
-(defn- ^:dynamic *getenv-fn*
- "Get ENV'ironment variable. Only used for testing, not part of the public API (yet)."
+(defn ^:dynamic *getenv-fn*
+ "Get ENV'ironment variable, typically used for getting `CLJ_CONFIG`, etc."
^String [env]
(java.lang.System/getenv env))
@@ -652,6 +652,14 @@ public class ClojureToolsDownloader {
(unixify (.toAbsolutePath (as-path f))))
f))))
+(defn- resolve-in-dir
+ "Resolves against directory (when provided). Absolute paths are unchanged.
+ Returns string."
+ [dir path]
+ (if dir
+ (str (.resolve (as-path dir) (str path)))
+ (str path)))
+
(defn- get-env-tools-dir
"Retrieves the tools-directory from environment variable `DEPS_CLJ_TOOLS_DIR`"
[]
@@ -902,7 +910,7 @@ public class ClojureToolsDownloader {
entries (vec (.split ^String cp java.io.File/pathSeparator))]
(some (fn [entry]
(when (str/ends-with? entry ".jar")
- (not (.exists (io/file entry)))))
+ (not (.exists (io/file (resolve-in-dir *dir* entry))))))
entries)))
tools-args
(when (or stale (:pom cli-opts))
diff --git a/test/borkdude/deps_test.clj b/test/borkdude/deps_test.clj
index 4aa2fd9..8a53460 100644
--- a/test/borkdude/deps_test.clj
+++ b/test/borkdude/deps_test.clj
@@ -474,3 +474,9 @@
(borkdude.deps/-main "-Scp" long-cp "-M" "-e" "nil"))
(is (or (nil? @ret)
(zero? (:exit @ret)))))))
+
+(deftest resolve-in-dir-test
+ (let [tmp-dir (System/getProperty "java.io.tmpdir")
+ home-dir (System/getProperty "user.home")]
+ (is (str/starts-with? (#'borkdude.deps/resolve-in-dir tmp-dir "dude") tmp-dir))
+ (is (= home-dir (#'borkdude.deps/resolve-in-dir tmp-dir home-dir)))))