|
19 | 19 | [java.io File InputStream FileInputStream BufferedInputStream |
20 | 20 | OutputStream FileOutputStream BufferedOutputStream ByteArrayOutputStream] |
21 | 21 | [java.nio.file Files] |
22 | | - [java.nio.file.attribute FileAttribute] |
| 22 | + [java.nio.file.attribute FileAttribute FileTime] |
23 | 23 | [java.util.jar JarEntry JarInputStream JarOutputStream Manifest])) |
24 | 24 |
|
25 | 25 | (set! *warn-on-reflection* true) |
|
104 | 104 | (throw (ex-info (str "Conflicting path at " path " from " lib) {}))) |
105 | 105 |
|
106 | 106 | (defn- handler-emit |
107 | | - [entry buffer out-dir path write-spec] |
| 107 | + [^FileTime last-modified-time buffer out-dir path write-spec] |
108 | 108 | (let [{:keys [string stream append] :or {append false}} write-spec |
109 | 109 | out-file (jio/file out-dir path)] |
110 | 110 | (if string |
111 | 111 | (spit out-file string :append ^boolean append) |
112 | 112 | (copy-stream! ^InputStream stream (BufferedOutputStream. (FileOutputStream. out-file ^boolean append)) buffer)) |
113 | | - (Files/setLastModifiedTime (.toPath out-file) (.getLastModifiedTime ^JarEntry entry)))) |
| 113 | + (Files/setLastModifiedTime (.toPath out-file) last-modified-time))) |
114 | 114 |
|
115 | 115 | (defn- handle-conflict |
116 | | - [handlers entry buffer out-dir {:keys [state path] :as handler-params}] |
| 116 | + [handlers last-modified-time buffer out-dir {:keys [state path] :as handler-params}] |
117 | 117 | (let [use-handler (loop [[[re handler] & hs] (dissoc handlers :default)] |
118 | 118 | (if re |
119 | 119 | (if (re-matches re path) |
|
124 | 124 | (let [{new-state :state, write :write} (use-handler handler-params)] |
125 | 125 | (when write |
126 | 126 | (doseq [[path write-spec] write] |
127 | | - (handler-emit entry buffer out-dir path write-spec))) |
| 127 | + (handler-emit last-modified-time buffer out-dir path write-spec))) |
128 | 128 | (or new-state state)) |
129 | 129 | (throw (ex-info (format "No handler found for conflict at %s" path) {}))))) |
130 | 130 |
|
|
138 | 138 | true |
139 | 139 | (throw (ex-info (str "Unable to create parent dirs for: " (.toString child)) {}))))) |
140 | 140 |
|
| 141 | +(defn- explode1 |
| 142 | + "Given one entry/src file, copy to target pursuant to excludes and handlers. |
| 143 | + Returns possibly updated state for further exploding." |
| 144 | + [^InputStream is ^String path dir? ^FileTime last-modified-time |
| 145 | + ^File out-file lib {:keys [out-dir buffer exclude handlers] :as context} state] |
| 146 | + (cond |
| 147 | + ;; excluded or directory - do nothing |
| 148 | + (or (exclude-from-uber? exclude path) dir?) |
| 149 | + state |
| 150 | + |
| 151 | + ;; conflict, same file from multiple sources - handle |
| 152 | + (.exists out-file) |
| 153 | + (handle-conflict handlers last-modified-time buffer out-dir |
| 154 | + {:lib lib, :path path, :in is, :existing out-file, :state state}) |
| 155 | + |
| 156 | + ;; write new file, parent dir exists for writing |
| 157 | + (ensure-dir (.getParentFile out-file) out-file) |
| 158 | + (do |
| 159 | + (copy-stream! ^InputStream is (BufferedOutputStream. (FileOutputStream. out-file)) buffer) |
| 160 | + (Files/setLastModifiedTime (.toPath out-file) last-modified-time) |
| 161 | + state) |
| 162 | + |
| 163 | + :parent-dir-is-a-file |
| 164 | + (throw (ex-info (format "Cannot write %s from %s as parent dir is a file from another lib. One of them must be excluded." |
| 165 | + path lib) {})))) |
| 166 | + |
141 | 167 | (defn- explode |
142 | | - [^File lib-file lib {:keys [out-dir buffer exclude handlers]} state] |
| 168 | + [^File lib-file lib {:keys [out-dir buffer exclude handlers] :as context} state] |
143 | 169 | (cond |
144 | 170 | (not (.exists lib-file)) |
145 | 171 | state |
|
151 | 177 | (let [path (.getName entry) |
152 | 178 | ;; should rarely happen (except /), but chop to make relative: |
153 | 179 | path (if (str/starts-with? path "/") (subs path 1) path) |
154 | | - out-file (jio/file out-dir path) |
155 | | - parent-file (.getParentFile out-file)] |
156 | | - (cond |
157 | | - ;; excluded or directory - do nothing |
158 | | - (or (exclude-from-uber? exclude path) (.isDirectory entry)) |
159 | | - (recur the-state) |
160 | | - |
161 | | - ;; conflict, same file from multiple sources - handle |
162 | | - (.exists out-file) |
163 | | - (recur (handle-conflict handlers entry buffer out-dir |
164 | | - {:lib lib, :path path, :in jis, :existing out-file, :state the-state})) |
165 | | - |
166 | | - ;; write new file, parent dir exists for writing |
167 | | - (ensure-dir parent-file out-file) |
168 | | - (do |
169 | | - (copy-stream! ^InputStream jis (BufferedOutputStream. (FileOutputStream. out-file)) buffer) |
170 | | - (Files/setLastModifiedTime (.toPath out-file) (.getLastModifiedTime entry)) |
171 | | - (recur the-state)) |
172 | | - |
173 | | - :parent-dir-is-a-file |
174 | | - (throw (ex-info (format "Cannot write %s from %s as parent dir is a file from another lib. One of them must be excluded." |
175 | | - path lib) {})))) |
| 180 | + out-file (jio/file out-dir path)] |
| 181 | + (recur |
| 182 | + (explode1 jis path (.isDirectory entry) (.getLastModifiedTime ^JarEntry entry) |
| 183 | + out-file lib context the-state))) |
176 | 184 | the-state))) |
177 | 185 |
|
178 | 186 | (.isDirectory lib-file) |
179 | | - (do |
180 | | - (file/copy-contents lib-file out-dir) |
181 | | - state) |
| 187 | + (let [source-dir (.getAbsoluteFile lib-file) |
| 188 | + source-path (.toPath source-dir) |
| 189 | + fs (file/collect-files source-dir :dirs true)] |
| 190 | + (loop [[^File f & restf] fs, the-state state] |
| 191 | + (if f |
| 192 | + (let [is (when (.isFile f) (jio/input-stream f)) |
| 193 | + path (.toString (.relativize source-path (.toPath f))) |
| 194 | + source-time (FileTime/fromMillis (.lastModified f)) |
| 195 | + out-file (jio/file out-dir path)] |
| 196 | + (recur restf (explode1 is path (.isDirectory f) source-time out-file lib context the-state))) |
| 197 | + the-state))) |
182 | 198 |
|
183 | 199 | :else |
184 | 200 | (throw (ex-info (format "Unexpected lib file: %s" (.toString lib-file)) {})))) |
|
0 commit comments