forked from technomancy/leiningen
-
Notifications
You must be signed in to change notification settings - Fork 1
/
uberjar.clj
66 lines (62 loc) · 2.8 KB
/
uberjar.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
(ns leiningen.uberjar
"Create a jar containing the compiled code, source, and all dependencies."
(:require [clojure.xml :as xml])
(:use [clojure.zip :only [xml-zip]]
[clojure.contrib.java-utils :only [file]]
[clojure.contrib.duck-streams :only [copy]]
[clojure.contrib.zip-filter.xml :only [xml-> tag=]]
[leiningen.deps :only [deps]]
[leiningen.jar :only [jar]])
(:import [java.util.zip ZipFile ZipOutputStream ZipEntry]
[java.io File FileOutputStream PrintWriter]))
(defn read-components [zipfile]
(when-let [entry (.getEntry zipfile "META-INF/plexus/components.xml")]
(-> (xml-> (xml-zip (xml/parse (.getInputStream zipfile entry)))
(tag= :components))
first first :content)))
(defn copy-entries
"Copies the entries of ZipFile in to the ZipOutputStream out, skipping
the entries which satisfy skip-pred. Returns the names of the
entries copied."
[in out & [skip-pred]]
(for [file (enumeration-seq (.entries in))
:when (not (skip-pred file))]
(do
(.setCompressedSize file -1) ; some jars report size incorrectly
(.putNextEntry out file)
(copy (.getInputStream in file) out)
(.closeEntry out)
(.getName file))))
;; we have to keep track of every entry we've copied so that we can
;; skip duplicates. We also collect together all the plexus components so
;; that we can merge them.
(defn include-dep [out [skip-set components] dep]
(println "Including" (.getName dep))
(with-open [zipfile (ZipFile. dep)]
[(into skip-set (copy-entries zipfile out #(skip-set (.getName %))))
(concat components (read-components zipfile))]))
(defn uberjar
"Create a jar like the jar task, but including the contents of each of
the dependency jars. Suitable for standalone distribution."
[project & args]
(jar project)
(with-open [out (-> (file (:root project)
(str (:name project) "-standalone.jar"))
(FileOutputStream.) (ZipOutputStream.))]
;; TODO: any way to make sure we skip dev dependencies?
(let [deps (->> (file-seq (file (:library-path project)))
(filter #(.endsWith (.getName %) ".jar"))
(cons (file (:root project) (str (:name project) ".jar"))))
[_ components] (reduce (partial include-dep out)
[#{"META-INF/plexus/components.xml"} nil]
deps)]
(when-not (empty? components)
(.putNextEntry out (ZipEntry. "META-INF/plexus/components.xml"))
(binding [*out* (PrintWriter. out)]
(xml/emit {:tag :component-set
:content
[{:tag :components
:content
components}]})
(.flush *out*))
(.closeEntry out)))))