-
Notifications
You must be signed in to change notification settings - Fork 9
/
jar.clj
70 lines (61 loc) · 2.49 KB
/
jar.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
67
68
69
70
(ns cider.enrich-classpath.jar
(:require
[cider.enrich-classpath.jdk :as jdk]
[cider.enrich-classpath.xdg :as xdg]
[clojure.java.io :as io]
[clojure.string :as string])
(:import
(cider.enrich_classpath Calc72)
(java.io ByteArrayOutputStream File PrintStream)
(java.util.jar JarInputStream JarOutputStream Manifest)
(java.util.zip CRC32)))
;; Manifest files must be wrapped every 72 lines, with one space of padding for every inserted newline.
;; In principle the `Manifest` class provides this wrapping already, however beyond certain input size,
;; it will throw an exception.
;; An already-wrapped string will be accepted by `Manifest` without altering it or throwing any exception.
(defn wrap72 [s]
(let [b (ByteArrayOutputStream.)]
(Calc72/calc72 (PrintStream. b)
s
(boolean (jdk/jdk8?)))
(str b)))
(defn crc32 ^String [^String s]
(let [s-bytes (-> s .getBytes)]
(-> (CRC32.)
(doto (.update s-bytes 0 (alength s-bytes)))
.getValue
str)))
(defn jars->classpath [jars]
(wrap72 (str "Class-Path: "
(string/join " " jars))))
(def template
"Manifest-Version: 1.0
%s
Created-By: mx.cider/enrich-classpath
")
(defn manifest ^String [classpath]
(format template classpath))
(defn jar-file->manifest-contents [^File file]
(let [os (ByteArrayOutputStream.)]
(-> file io/input-stream JarInputStream. .getManifest (.write os))
(-> os .toByteArray (String. "UTF-8"))))
(defn jar-for! ^String [jars]
(when-let [corpus (->> jars
;; nil values should never be included (`integration_test.clj` asserts this),
;; but just in case:
(filter some?)
;; maybe there's nothing to enrich in a small-enough project:
(seq))]
(let [corpus-crc (-> corpus string/join crc32)
dir-crc (-> "user.dir" System/getProperty crc32)
dir (-> xdg/cache-root
(io/file "mx.cider" "enrich-classpath" (jdk/digits-str) dir-crc)
(doto .mkdirs))
filename (-> dir
(io/file (str corpus-crc ".jar"))
str)]
(when-not (-> filename File. .exists)
(let [manifest-contents (-> corpus jars->classpath manifest)
manifest (-> manifest-contents (.getBytes "UTF-8") io/input-stream Manifest.)]
(-> filename io/output-stream (JarOutputStream. manifest) (.close))))
filename)))