Skip to content

Commit

Permalink
Merge pull request #4 from zeitstein/multi-platform-emit
Browse files Browse the repository at this point in the history
Support building bins for multiple `:platforms` in one invocation
  • Loading branch information
ericdallo authored Jan 18, 2024
2 parents 413a2f9 + 9d6b974 commit 18aab8f
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 21 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ $ clojure -X:jar && clojure -X:bin
- `:name` sym-or-str -- specify the name of the generated BIN file
- `:skip-realign` true -- if should skip byte alignment repair.
- `:jvm-opts` [strs] -- optional list of JVM options to use during bin executing
- `:platforms` [kws] -- optional list of platforms for which to emit bins, valid kws: :unix, :windows, defaults to system platform

## Contribution

Expand Down
67 changes: 47 additions & 20 deletions src/deps_bin/impl/bin.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@
[clostache.parser :refer [render]]
[me.raynes.fs :as fs]))

(def ^:private windows?
(str/starts-with? (System/getProperty "os.name") "Windows"))
(def ^:private allowed-platforms
#{:unix :windows})

(def ^:private preamble-template
(if windows?
"@echo off\r\njava {{{jvm-opts}}} -jar \"%~f0\" %*\r\nexit /b %errorlevel%\r\n"
"#!/usr/bin/env bash\nexec java {{{jvm-opts}}} -jar $0 \"$@\"\ngoto :eof\n"))
(defn ^:private system-platform []
(if (str/starts-with? (System/getProperty "os.name") "Windows")
:windows
:unix))

(defn ^:private platform-filename [platform name]
(case platform
:windows (str name ".bat")
:unix name))

(defn ^:private preamble-template [platform]
(case platform
:unix "#!/usr/bin/env bash\nexec java {{{jvm-opts}}} -jar $0 \"$@\"\ngoto :eof\n"
:windows "@echo off\r\njava {{{jvm-opts}}} -jar \"%~f0\" %*\r\nexit /b %errorlevel%\r\n"))

(defn ^:private print-help []
(println "library usage:")
Expand All @@ -22,11 +32,13 @@
(println " :jar sym-or-str -- specify the source name of the JAR file")
(println " :name sym-or-str -- specify the name of the generated BIN file")
(println " :skip-realign true -- whether should skip byte alignment repair")
(println " :jvm-opts [strs] -- optional list of JVM options to use during bin executing"))
(println " :jvm-opts [strs] -- optional list of JVM options to use during bin executing")
(println " :platforms [kws] -- optional list of platforms for which to emit bins,")
(println " valid kws: :unix, :windows, defaults to system platform"))

(defn ^:private preamble [{:keys [jvm-opts] :as options}]
(-> (render preamble-template (merge options
{:jvm-opts (str/join " " jvm-opts)}))
(defn ^:private preamble [platform {:keys [jvm-opts] :as options}]
(-> (preamble-template platform)
(render (merge options {:jvm-opts (str/join " " jvm-opts)}))
(str/replace #"\\\$" "\\$")))

(defn ^:private write-bin [bin-file jar preamble]
Expand All @@ -36,17 +48,36 @@
(io/copy (fs/file jar) bin))
(fs/chmod "+x" bin-file))

(defn ^:private coerce-platforms [coll]
(if-some [platforms (->> coll (keep allowed-platforms) distinct not-empty)]
platforms
[(system-platform)]))

(defn emit-bin!
"Writes bin, optionally re-aligns it and returns its canonical path."
[platform {:keys [jar name skip-realign] :as options}]
(let [name (platform-filename platform name)
bin-file (io/file name)
preamble (preamble platform options)]
(println "Creating" (clojure.core/name platform) "standalone executable:" name)
(write-bin name jar preamble)
(when-not skip-realign
(println "Re-aligning zip offsets...")
(repair-zip-with-preamble-bytes bin-file))
(.getCanonicalPath bin-file)))

(defn build-bin
"Core functionality for deps-bin. Can be called from a REPL or as a library.
Returns a hash map containing:
* `:success` -- `true` or `false`
* `:bin-path` -- On `:success`, it is the abs path to the binary.
* `:bin-paths` -- Same as above, but when building for multiple platforms.
* `:reason` -- if `:success` is `false`, this explains what failed:
* `:help` -- help was requested
* `:no-jar` -- the `:jar` option was missing
* `:no-name` -- the `:name` option was missing
Additional detail about success and failure is also logged."
[{:keys [help jar name skip-realign] :as options}]
[{:keys [help jar name skip-realign platforms] :as options}]
(cond

help
Expand All @@ -59,15 +90,11 @@
{:success false :reason :no-name}

:else
(let [name (if windows? (str name ".bat") name)
bin-file (io/file name)]
(println "Creating standalone executable:" name)
(write-bin name jar (preamble options))
(when-not skip-realign
(println "Re-aligning zip offsets...")
(repair-zip-with-preamble-bytes bin-file))
{:success true
:bin-path (.getCanonicalPath bin-file)})))
(let [platforms (coerce-platforms platforms)
emitted-paths (mapv #(emit-bin! % options) platforms)]
(if (= (count emitted-paths) 1)
{:success true :bin-path (first emitted-paths)}
{:success true :bin-paths emitted-paths}))))

(defn build-bin-as-main
"Command-line entry point for `-X` (and legacy `-M`) that performs
Expand Down
19 changes: 18 additions & 1 deletion test/deps_bin/impl/bin_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,24 @@
(is (= {:success true
:bin-path (str (fs/canonicalize (cond-> "some-bin" (fs/windows?) (str ".bat"))))}
(bin/build-bin {:jar "some-jar.jar"
:name "some-bin"}))))))
:name "some-bin"})))))
(testing "with :platforms provided"
(with-redefs [bin/write-bin (constantly nil)
clj-zip-meta/repair-zip-with-preamble-bytes (constantly nil)]
(is (= {:success true
:bin-paths [(str (fs/canonicalize "some-bin.bat"))
(str (fs/canonicalize "some-bin"))]}
(bin/build-bin {:jar "some-jar.jar"
:name "some-bin"
:platforms ["foo" :windows :unix :unix]})))))
(testing "with invalid :platforms, default to system platform"
(with-redefs [bin/write-bin (constantly nil)
clj-zip-meta/repair-zip-with-preamble-bytes (constantly nil)]
(is (= {:success true
:bin-path (str (fs/canonicalize (cond-> "some-bin" (fs/windows?) (str ".bat"))))}
(bin/build-bin {:jar "some-jar.jar"
:name "some-bin"
:platforms [:bad-platform]}))))))

(deftest binary
(let [test-jar "test/test-jar/testjar.jar"]
Expand Down

0 comments on commit 18aab8f

Please sign in to comment.