--------------------------------------------------------------------------------
/src/test/clojure/clojure/tools/build/tasks/test_copy.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.test-copy
10 | (:require
11 | [clojure.test :refer :all]
12 | [clojure.java.io :as jio]
13 | [clojure.string :as str]
14 | [clojure.tools.build.api :as api]
15 | [clojure.tools.build.util.file :as file]
16 | [clojure.tools.build.util.zip :as zip]
17 | [clojure.tools.build.test-util :refer :all])
18 | (:import
19 | [java.io File FileInputStream ByteArrayOutputStream]
20 | [java.nio.file Files LinkOption FileSystems]
21 | [java.nio.file.attribute PosixFilePermission]
22 | [java.util UUID]))
23 |
24 | (defn slurp-binary
25 | [^File f]
26 | (let [fis (FileInputStream. f)
27 | os (ByteArrayOutputStream.)
28 | buffer (byte-array 4096)]
29 | (zip/copy-stream! fis os buffer)
30 | (.toByteArray os)))
31 |
32 | (deftest test-copy
33 | (with-test-dir "test-data/p1"
34 | (let [txt (str (UUID/randomUUID))]
35 | (api/set-project-root! (.getAbsolutePath *test-dir*))
36 | (api/copy-dir {:target-dir "target/classes"
37 | :src-dirs ["src" "resources"]
38 | :replace {"__REPLACE__" txt}})
39 | (let [source-file (jio/file (project-path "target/classes/foo/bar.clj"))
40 | contents (slurp source-file)]
41 | (is (.exists source-file))
42 | (is (str/includes? contents txt)))
43 |
44 | ;; binary files in replaced exts should be copied but not replaced
45 | (let [binary-in (jio/file (project-path "resources/test.png"))
46 | binary-out (jio/file (project-path "target/classes/test.png"))]
47 | (is (.exists binary-out))
48 | (is (= (seq (slurp-binary binary-in)) (seq (slurp-binary binary-out))))))))
49 |
50 | (deftest test-replace-retains-perms
51 | (when (contains? (.supportedFileAttributeViews (FileSystems/getDefault)) "posix")
52 | (with-test-dir "test-data/p1"
53 | (api/set-project-root! (.getAbsolutePath *test-dir*))
54 | (let [start-file (jio/file (project-path "target/x/f"))
55 | _start (file/ensure-file start-file "abc")
56 | start-path (.toPath start-file)]
57 | (Files/setPosixFilePermissions start-path #{PosixFilePermission/OWNER_READ PosixFilePermission/GROUP_READ PosixFilePermission/OWNER_EXECUTE})
58 | (api/copy-dir {:src-dirs [(project-path "target/x")] :target-dir (project-path "target/y") :replace {"abc" "xyz"}})
59 | (let [end (jio/file (project-path "target/y/f"))
60 | end-path (.toPath end)
61 | perms (Files/getPosixFilePermissions end-path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))]
62 | (is (= (slurp end) "xyz"))
63 | (is (contains? perms PosixFilePermission/OWNER_EXECUTE)))))))
64 |
65 | (comment
66 | (run-tests)
67 | )
68 |
--------------------------------------------------------------------------------
/docs/js/page_effects.js:
--------------------------------------------------------------------------------
1 | function visibleInParent(element) {
2 | var position = $(element).position().top
3 | return position > -50 && position < ($(element).offsetParent().height() - 50)
4 | }
5 |
6 | function hasFragment(link, fragment) {
7 | return $(link).attr("href").indexOf("#" + fragment) != -1
8 | }
9 |
10 | function findLinkByFragment(elements, fragment) {
11 | return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
12 | }
13 |
14 | function scrollToCurrentVarLink(elements) {
15 | var elements = $(elements);
16 | var parent = elements.offsetParent();
17 |
18 | if (elements.length == 0) return;
19 |
20 | var top = elements.first().position().top;
21 | var bottom = elements.last().position().top + elements.last().height();
22 |
23 | if (top >= 0 && bottom <= parent.height()) return;
24 |
25 | if (top < 0) {
26 | parent.scrollTop(parent.scrollTop() + top);
27 | }
28 | else if (bottom > parent.height()) {
29 | parent.scrollTop(parent.scrollTop() + bottom - parent.height());
30 | }
31 | }
32 |
33 | function setCurrentVarLink() {
34 | $('.secondary a').parent().removeClass('current')
35 | $('.anchor').
36 | filter(function(index) { return visibleInParent(this) }).
37 | each(function(index, element) {
38 | findLinkByFragment(".secondary a", element.id).
39 | parent().
40 | addClass('current')
41 | });
42 | scrollToCurrentVarLink('.secondary .current');
43 | }
44 |
45 | var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
46 |
47 | function scrollPositionId(element) {
48 | var directory = window.location.href.replace(/[^\/]+\.html$/, '')
49 | return 'scroll::' + $(element).attr('id') + '::' + directory
50 | }
51 |
52 | function storeScrollPosition(element) {
53 | if (!hasStorage) return;
54 | localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
55 | localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
56 | }
57 |
58 | function recallScrollPosition(element) {
59 | if (!hasStorage) return;
60 | $(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
61 | $(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
62 | }
63 |
64 | function persistScrollPosition(element) {
65 | recallScrollPosition(element)
66 | $(element).scroll(function() { storeScrollPosition(element) })
67 | }
68 |
69 | function sidebarContentWidth(element) {
70 | var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
71 | return Math.max.apply(Math, widths)
72 | }
73 |
74 | function calculateSize(width, snap, margin, minimum) {
75 | if (width == 0) {
76 | return 0
77 | }
78 | else {
79 | return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
80 | }
81 | }
82 |
83 | function resizeSidebars() {
84 | var primaryWidth = sidebarContentWidth('.primary')
85 | var secondaryWidth = 0
86 |
87 | if ($('.secondary').length != 0) {
88 | secondaryWidth = sidebarContentWidth('.secondary')
89 | }
90 |
91 | // snap to grid
92 | primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
93 | secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
94 |
95 | $('.primary').css('width', primaryWidth)
96 | $('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
97 |
98 | if (secondaryWidth > 0) {
99 | $('#content').css('left', primaryWidth + secondaryWidth + 2)
100 | }
101 | else {
102 | $('#content').css('left', primaryWidth + 1)
103 | }
104 | }
105 |
106 | $(window).ready(resizeSidebars)
107 | $(window).ready(setCurrentVarLink)
108 | $(window).ready(function() { persistScrollPosition('.primary')})
109 | $(window).ready(function() {
110 | $('#content').scroll(setCurrentVarLink)
111 | $(window).resize(setCurrentVarLink)
112 | })
113 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/build/tasks/copy.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.copy
10 | (:require
11 | [clojure.string :as str]
12 | [clojure.tools.build.api :as api]
13 | [clojure.tools.build.util.file :as file])
14 | (:import
15 | [java.io File]
16 | [java.nio.file FileSystems FileVisitor FileVisitResult Files Path LinkOption]))
17 |
18 | (set! *warn-on-reflection* true)
19 |
20 | ;; copy spec:
21 | ;; :from (coll of dirs), default = ["."]
22 | ;; ;include (glob), default = "**"
23 | ;; :replace (map of replacements) - performed while copying
24 |
25 | (defn- match-paths
26 | "Match glob to paths under root and return a collection of Path objects"
27 | [^File root glob]
28 | (let [root-path (.toPath root)
29 | matcher (.getPathMatcher (FileSystems/getDefault) (str "glob:" glob))
30 | paths (volatile! [])
31 | visitor (reify FileVisitor
32 | (visitFile [_ path _attrs]
33 | (when (.matches matcher (.relativize root-path ^Path path))
34 | (vswap! paths conj path))
35 | FileVisitResult/CONTINUE)
36 | (visitFileFailed [_ _path _ex] FileVisitResult/CONTINUE)
37 | (preVisitDirectory [_ _ _] FileVisitResult/CONTINUE)
38 | (postVisitDirectory [_ _ _] FileVisitResult/CONTINUE))]
39 | (Files/walkFileTree root-path visitor)
40 | @paths))
41 |
42 | (def default-ignores
43 | [".*~$"
44 | "^#.*#$"
45 | "^\\.#.*"
46 | "^.DS_Store$"])
47 |
48 | (defn ignore? [name ignore-regexes]
49 | (boolean (some #(re-matches % name) ignore-regexes)))
50 |
51 | (def default-non-replaced-exts
52 | ["jpg" "jpeg" "png" "gif" "bmp"])
53 |
54 | (defn- ends-with-ext?
55 | [exts path]
56 | (loop [[ext & es] exts]
57 | (if ext
58 | (if (str/ends-with? path ext)
59 | true
60 | (recur es))
61 | false)))
62 |
63 | (defn copy
64 | [{:keys [target-dir src-dirs include replace ignores non-replaced-exts]
65 | :or {include "**", ignores default-ignores, non-replaced-exts default-non-replaced-exts}
66 | :as _params}]
67 | (let [to-path (.toPath (file/ensure-dir (api/resolve-path target-dir)))
68 | ignore-regexes (map re-pattern ignores)
69 | non-replaced (map #(str "." %) default-non-replaced-exts)]
70 | (doseq [dir src-dirs]
71 | ;(println "from" dir)
72 | (let [from-file (api/resolve-path dir)
73 | paths (match-paths from-file include)]
74 | (doseq [^Path path paths]
75 | (let [path-file (.toFile path)
76 | path-file-name (.getName path-file)
77 | target-file (.toFile (.resolve to-path (.relativize (.toPath from-file) path)))]
78 | (when-not (ignore? path-file-name ignore-regexes)
79 | ;(println "copying" (.toString path-file) (.toString target-file) (boolean (not (empty? replace))))
80 | (if (or (empty? replace) (ends-with-ext? non-replaced (.getName path-file)))
81 | (file/copy-file path-file target-file)
82 | (let [contents (slurp path-file)
83 | replaced (reduce (fn [s [find replace]] (str/replace s find replace))
84 | contents replace)
85 | perms (when (contains? (.supportedFileAttributeViews (FileSystems/getDefault)) "posix")
86 | (Files/getPosixFilePermissions (.toPath path-file)
87 | (into-array LinkOption [LinkOption/NOFOLLOW_LINKS])))]
88 | (file/ensure-file target-file replaced :append false)
89 | (when perms
90 | (Files/setPosixFilePermissions (.toPath target-file) perms)
91 | nil))))))))))
92 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/build/util/zip.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.util.zip
10 | (:require
11 | [clojure.java.io :as jio]
12 | [clojure.tools.build.util.file :as file]
13 | [clojure.string :as str])
14 | (:import
15 | [java.io File InputStream OutputStream]
16 | [java.nio.file Files LinkOption]
17 | [java.nio.file.attribute BasicFileAttributes]
18 | [java.util.zip ZipFile ZipInputStream ZipOutputStream ZipEntry]
19 | [java.util.jar Manifest Attributes$Name]))
20 |
21 | (set! *warn-on-reflection* true)
22 |
23 | (defn- add-zip-entry
24 | [^ZipOutputStream output-stream ^String path ^File file]
25 | (let [dir (.isDirectory file)
26 | attrs (Files/readAttributes (.toPath file) BasicFileAttributes ^"[Ljava.nio.file.LinkOption;" (into-array LinkOption []))
27 | path (if (and dir (not (.endsWith path "/"))) (str path "/") path)
28 | path (str/replace path \\ \/) ;; only use unix-style paths in jars
29 | entry (doto (ZipEntry. path)
30 | ;(.setSize (.size attrs))
31 | ;(.setLastAccessTime (.lastAccessTime attrs))
32 | (.setLastModifiedTime (.lastModifiedTime attrs)))]
33 | (.putNextEntry output-stream entry)
34 | (when-not dir
35 | (with-open [fis (jio/input-stream file)]
36 | (jio/copy fis output-stream)))
37 |
38 | (.closeEntry output-stream)))
39 |
40 | (defn copy-to-zip
41 | [^ZipOutputStream jos ^File root]
42 | (let [root-path (.toPath root)
43 | files (file/collect-files root :dirs true)]
44 | (run! (fn [^File f]
45 | (let [rel-path (.toString (.relativize root-path (.toPath f)))]
46 | (when-not (= rel-path "")
47 | ;(println " Adding" rel-path)
48 | (add-zip-entry jos rel-path f))))
49 | files)))
50 |
51 | (defn fill-manifest!
52 | [^Manifest manifest props]
53 | (let [attrs (.getMainAttributes manifest)]
54 | (run!
55 | (fn [[name value]]
56 | (.put attrs (Attributes$Name. ^String name) value)) props)))
57 |
58 | (defn list-zip
59 | [^String zip-path]
60 | (let [zip-file (jio/file zip-path)]
61 | (when (.exists zip-file)
62 | (with-open [zip (ZipFile. zip-file)]
63 | (let [entries (enumeration-seq (.entries zip))]
64 | (sort-by :name
65 | (into [] (map (fn [^ZipEntry entry]
66 | {:name (.getName entry)
67 | :created (.getCreationTime entry)
68 | :modified (.getLastModifiedTime entry)
69 | :size (.getSize entry)}))
70 | entries)))))))
71 |
72 | (defn copy-stream!
73 | "Copy input stream to output stream using buffer.
74 | Caller is responsible for passing buffered streams and closing streams."
75 | [^InputStream is ^OutputStream os ^bytes buffer]
76 | (loop []
77 | (let [size (.read is buffer)]
78 | (if (pos? size)
79 | (do
80 | (.write os buffer 0 size)
81 | (recur))
82 | (.close os)))))
83 |
84 | (defn unzip
85 | [^String zip-path ^String target-dir]
86 | (let [buffer (byte-array 4096)
87 | zip-file (jio/file zip-path)]
88 | (if (.exists zip-file)
89 | (with-open [zis (ZipInputStream. (jio/input-stream zip-file))]
90 | (loop []
91 | (if-let [entry (.getNextEntry zis)]
92 | ;(println "entry:" (.getName entry) (.isDirectory entry))
93 | (let [out-file (jio/file target-dir (.getName entry))]
94 | (jio/make-parents out-file)
95 | (when-not (.isDirectory entry)
96 | (with-open [output (jio/output-stream out-file)]
97 | (copy-stream! zis output buffer)
98 | (Files/setLastModifiedTime (.toPath out-file) (.getLastModifiedTime entry))))
99 | (recur))
100 | true)))
101 | false)))
102 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | io.github.clojure
4 | tools.build
5 | 0.10.12-SNAPSHOT
6 | tools.build
7 | Clojure builds as Clojure programs.
8 |
9 |
10 | org.clojure
11 | pom.contrib
12 | 1.3.0
13 |
14 |
15 |
16 |
17 | puredanger
18 | Alex Miller
19 |
20 |
21 |
22 |
23 |
24 | true
25 | 1.12.0
26 |
27 |
28 |
29 |
30 | org.clojure
31 | clojure
32 | ${clojure.version}
33 |
34 |
35 | org.clojure
36 | tools.deps
37 | 0.22.1492
38 |
39 |
40 | org.clojure
41 | tools.namespace
42 | 1.5.0
43 |
44 |
45 | org.slf4j
46 | slf4j-nop
47 | 1.7.36
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | sonatype-nexus-staging
56 | https://s01.oss.sonatype.org/content/repositories/snapshots
57 |
58 |
59 |
60 |
61 |
62 |
63 | src/main/resources
64 | true
65 |
66 |
67 |
68 |
69 | org.apache.maven.plugins
70 | maven-resources-plugin
71 | 3.1.0
72 |
73 |
74 |
77 | com.theoryinpractise
78 | clojure-maven-plugin
79 | 1.7.1
80 | true
81 |
82 | ${clojure.warnOnReflection}
83 | true
84 |
85 |
86 |
87 | clojure-compile
88 | none
89 |
90 |
91 | clojure-test
92 | test
93 |
94 | test
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | org.sonatype.plugins
103 | nexus-staging-maven-plugin
104 | 1.6.8
105 | true
106 |
107 |
108 | sonatype-nexus-staging
109 | https://s01.oss.sonatype.org/
110 | true
111 |
112 |
113 |
114 |
115 |
116 |
117 | scm:git:git@github.com:clojure/tools.build.git
118 | scm:git:git@github.com:clojure/tools.build.git
119 | git@github.com:clojure/tools.build.git
120 | HEAD
121 |
122 |
123 |
124 |
125 | clojars
126 | https://clojars.org/repo/
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/build/util/file.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.util.file
10 | (:require
11 | [clojure.java.io :as jio]
12 | [clojure.string :as str])
13 | (:import
14 | [java.io File]
15 | [java.nio.file Path Files LinkOption CopyOption StandardCopyOption]
16 | [clojure.lang PersistentQueue]))
17 |
18 | (set! *warn-on-reflection* true)
19 |
20 | (defn collect-files
21 | "Recursively collect all paths under path, starting from root.
22 | Options:
23 | :dirs - whether to collect directories (default false)
24 | :collect - function for whether to collect a path (default yes)"
25 | [^File root & {:keys [dirs collect]
26 | :or {dirs false
27 | collect (constantly true)}}]
28 | (when (.exists root)
29 | (loop [queue (conj PersistentQueue/EMPTY root)
30 | collected []]
31 | (let [^File file (peek queue)]
32 | (if file
33 | (let [path (.toPath file)
34 | is-dir (Files/isDirectory path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
35 | children (when is-dir (with-open [entries (Files/newDirectoryStream path)]
36 | (mapv #(.toFile ^Path %) entries)))
37 | collect? (and (if is-dir dirs true) (collect file))]
38 | (recur (into (pop queue) children) (if collect? (conj collected file) collected)))
39 | (when (seq collected) collected))))))
40 |
41 | (defn suffixes
42 | "Returns a predicate matching suffixes"
43 | [& suffixes]
44 | (apply some-fn
45 | (map #(fn [^File f] (str/ends-with? (.toString f) ^String %)) suffixes)))
46 |
47 | (defn delete
48 | "Recursively delete file, where file is coerced with clojure.java.io/file"
49 | [file]
50 | (run! #(.delete ^File %) (reverse (collect-files (jio/file file) :dirs true))))
51 |
52 | (def ^{:private true, :tag "[Ljava.nio.file.CopyOption;"}
53 | copy-options
54 | (into-array CopyOption [StandardCopyOption/COPY_ATTRIBUTES StandardCopyOption/REPLACE_EXISTING]))
55 |
56 | (defn copy-file
57 | "Copy file from src to target, retaining file attributes. Returns nil."
58 | [^File src-file ^File target-file]
59 | (.mkdirs target-file)
60 | (Files/copy (.toPath src-file) (.toPath target-file) copy-options)
61 | nil)
62 |
63 | (defn copy-contents
64 | "Copy files in src dir to target dir, optionally filtering by prefix paths"
65 | ([^File src-dir ^File target-dir]
66 | (let [source-path (.toPath src-dir)
67 | target-path (.toPath target-dir)
68 | source-files (collect-files src-dir)]
69 | ;(println "source" (str source-path))
70 | ;(println "target" (str target-path))
71 | ;(println "source-files" (map str source-files))
72 | (run!
73 | (fn [^File f]
74 | (let [p (.toPath f)
75 | new-path (.resolve target-path (.relativize source-path p))]
76 | ;(println "copying" (str p) (str new-path))
77 | (copy-file f (.toFile new-path))))
78 | source-files)))
79 | ([^File src-dir ^File target-dir prefixes]
80 | (when (.exists src-dir)
81 | (let [root (.toPath src-dir)
82 | target (.toPath target-dir)]
83 | (loop [queue (conj PersistentQueue/EMPTY src-dir)]
84 | (let [^File file (peek queue)]
85 | (when file
86 | (let [path (.toPath file)
87 | relative (.relativize root path)]
88 | ;(println "consider" (.toString file) "match" (some #(str/starts-with? (.toString relative) %) prefixes) "dir" (Files/isDirectory path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS])))
89 | (cond
90 | ;; match, copy this file/dir
91 | (some #(str/starts-with? (.toString relative) %) prefixes)
92 | (let [end-path (.resolve target relative)]
93 | (copy-contents file (.toFile end-path))
94 | (recur (pop queue)))
95 |
96 | ;; no match, but continue looking in this directory if it could match later
97 | (and
98 | (Files/isDirectory path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
99 | (some #(str/starts-with? % (.toString relative)) prefixes))
100 | (recur (into (pop queue)
101 | (with-open [entries (Files/newDirectoryStream path)]
102 | (mapv #(.toFile ^Path %) entries))))
103 |
104 | ;; work the queue
105 | :else
106 | (recur (pop queue)))))))))))
107 |
108 | (defn ensure-dir
109 | "Ensure dir exists by making all parent directories and return it"
110 | ^File [dir]
111 | (let [d (jio/file dir)]
112 | (if (.exists d)
113 | d
114 | (if (.mkdirs d)
115 | d
116 | (throw (ex-info (str "Can't create directory " dir) {}))))))
117 |
118 | (defn ensure-file
119 | ([file] (ensure-file file ""))
120 | ([file contents & opts]
121 | (let [file (jio/file file)
122 | parent (.getParent file)]
123 | (if (.exists (jio/file parent))
124 | (apply spit file contents opts)
125 | (do
126 | (ensure-dir parent)
127 | (apply spit file contents opts))))))
128 |
--------------------------------------------------------------------------------
/src/test/clojure/clojure/tools/build/tasks/test_compile_clj.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.test-compile-clj
10 | (:require
11 | [clojure.test :refer :all :as test]
12 | [clojure.java.io :as jio]
13 | [clojure.string :as str]
14 | [clojure.tools.build.api :as api]
15 | [clojure.tools.build.tasks.compile-clj :as compile-clj]
16 | [clojure.tools.build.test-util :refer :all]))
17 |
18 | (deftest test-topo
19 | ;; deps: a -> b -> c, d
20 | ;; expect: c b a (reverse topo sort), then d at the end
21 | (is (= '[c b a d]
22 | (#'compile-clj/nses-in-topo [(jio/file "test-data/nses/src")]))))
23 |
24 | (deftest test-compile
25 | (with-test-dir "test-data/p1"
26 | (api/set-project-root! (.getAbsolutePath *test-dir*))
27 | (api/compile-clj {:class-dir "target/classes"
28 | :src-dirs ["src"]
29 | :basis (api/create-basis nil)})
30 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar.class")))))
31 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar__init.class")))))
32 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar$hello.class")))))))
33 |
34 | ;; use :src-dirs from basis paths
35 | (deftest test-compile-basis-paths
36 | (with-test-dir "test-data/p1"
37 | (api/set-project-root! (.getAbsolutePath *test-dir*))
38 | (api/compile-clj {:class-dir "target/classes"
39 | :basis (api/create-basis nil)})
40 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar.class")))))
41 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar__init.class")))))
42 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar$hello.class")))))))
43 |
44 | (defn find-java []
45 | (-> (api/process {:command-args [(if windows? "where" "which") "java"]
46 | :out :capture})
47 | :out
48 | str/split-lines
49 | first))
50 |
51 | (deftest test-compile-passthrough-opts
52 | (when-not (str/starts-with? (System/getProperty "java.version") "1.")
53 | (let [java-cmd (find-java)]
54 | (with-test-dir "test-data/p1"
55 | (api/set-project-root! (.getAbsolutePath *test-dir*))
56 | (api/compile-clj {:class-dir "target/classes"
57 | :src-dirs ["src"]
58 | :basis (api/create-basis nil)
59 | ;; pass these through to java command
60 | :java-opts ["-Dhi=there"]
61 | :use-cp-file :always
62 | :java-cmd java-cmd})
63 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar.class")))))
64 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar__init.class")))))
65 | (is (true? (.exists (jio/file (project-path "target/classes/foo/bar$hello.class")))))))))
66 |
67 | (deftest test-turn-off-assert-with-bindings
68 | (with-test-dir "test-data/assert"
69 | (api/set-project-root! (.getAbsolutePath *test-dir*))
70 | (let [basis (api/create-basis nil)
71 | invoke #(-> {:basis basis :main 'clojure.main :main-args ["-e" "((requiring-resolve 'foo.check-assert/f) 100)"]}
72 | api/java-command
73 | (merge {:out :capture, :err :ignore})
74 | api/process)
75 | compile-params {:class-dir "target/classes" :src-dirs ["src"] :basis basis}]
76 |
77 | ;; by default, assertions are on when compiling, then invocation fails (assertion expects keyword)
78 | (api/compile-clj compile-params) ;; no :bindings set
79 | (is (= {:exit 1} (invoke)))
80 |
81 | ;; recompile with binding to turn off assertions, then it passes (assertion not checked)
82 | (api/delete {:path "target/classes"})
83 | (api/compile-clj (assoc compile-params :bindings {#'clojure.core/*assert* false})) ;; turn off asserts
84 | (is (= {:exit 0, :out (str "100" (System/lineSeparator))} (invoke))))))
85 |
86 | (deftest test-capture-reflection
87 | (with-test-dir "test-data/reflecting"
88 | (api/set-project-root! (.getAbsolutePath *test-dir*))
89 | (let [basis (api/create-basis nil)
90 | compile-params {:class-dir "target/classes"
91 | :src-dirs ["src"]
92 | :basis basis
93 | :ns-compile ['foo.bar]}]
94 |
95 | ;; by default, reflection does not warn
96 | (is (nil? (api/compile-clj compile-params))) ;; no :bindings set
97 |
98 | ;; compile with reflection warnings and capture the error output
99 | (api/delete {:path "target/classes"})
100 | (is (str/starts-with?
101 | (:err
102 | (api/compile-clj (merge compile-params
103 | {:bindings {#'clojure.core/*warn-on-reflection* true}
104 | :err :capture})))
105 | "Reflection warning")))))
106 |
107 | (deftest test-accidental-basis-delay
108 | (with-test-dir "test-data/p1"
109 | (api/set-project-root! (.getAbsolutePath *test-dir*))
110 | (is (thrown? clojure.lang.ExceptionInfo
111 | (api/compile-clj {:class-dir "target/classes"
112 | :src-dirs ["src"]
113 | :basis (delay (api/create-basis nil))})))))
114 |
115 | (comment
116 | (run-tests)
117 | )
118 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/build/tasks/compile_clj.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.compile-clj
10 | (:require
11 | [clojure.java.io :as jio]
12 | [clojure.pprint :as pprint]
13 | [clojure.string :as str]
14 | [clojure.tools.build.api :as api]
15 | [clojure.tools.build.util.file :as file]
16 | [clojure.tools.build.tasks.process :as process]
17 | [clojure.tools.namespace.find :as find]
18 | [clojure.tools.namespace.dependency :as dependency]
19 | [clojure.tools.namespace.parse :as parse])
20 | (:import
21 | [java.io File]
22 | [java.nio.file Files]
23 | [java.nio.file.attribute FileAttribute]))
24 |
25 | (set! *warn-on-reflection* true)
26 |
27 | (defn- write-compile-script!
28 | ^File [^File script-file ^File compile-dir nses compiler-opts bindings]
29 | (let [compile-bindings (merge bindings
30 | {#'*compile-path* (.toString compile-dir)
31 | #'*compiler-options* compiler-opts})
32 | binding-nses (->> compile-bindings
33 | keys
34 | (map #(-> % symbol namespace symbol)) ;; Var->namespace
35 | distinct
36 | (remove #(= % 'clojure.core)))
37 | requires (map (fn [n] `(require '~n)) binding-nses)
38 | do-compile `(with-bindings ~compile-bindings
39 | ~@(map (fn [n] `(~'compile '~n)) nses)
40 | (System/exit 0))
41 | script (->> (conj (vec requires) do-compile)
42 | (map #(with-out-str (pprint/pprint %)))
43 | (str/join (System/lineSeparator)))]
44 | (spit script-file script)))
45 |
46 | (defn- ns->path
47 | [ns-sym]
48 | (str/replace (clojure.lang.Compiler/munge (str ns-sym)) \. \/))
49 |
50 | (defn- nses-in-bfs
51 | [dirs]
52 | (mapcat #(find/find-namespaces-in-dir % find/clj) dirs))
53 |
54 | (defn- nses-in-topo
55 | [dirs]
56 | (let [ns-decls (mapcat find/find-ns-decls-in-dir dirs)
57 | ns-candidates (set (map parse/name-from-ns-decl ns-decls))
58 | graph (reduce
59 | (fn [graph decl]
60 | (let [sym (parse/name-from-ns-decl decl)]
61 | (reduce
62 | (fn [graph dep] (dependency/depend graph sym dep))
63 | graph
64 | (parse/deps-from-ns-decl decl))))
65 | (dependency/graph)
66 | ns-decls)]
67 | (->> graph
68 | dependency/topo-sort
69 | (filter ns-candidates) ;; only keep stuff in these dirs
70 | (#(concat % ns-candidates)) ;; but make sure everything is in there at least once
71 | distinct)))
72 |
73 | (defn- basis-paths
74 | "Extract all path entries from basis, in classpath order"
75 | [{:keys [classpath classpath-roots]}]
76 | (let [path-set (->> classpath
77 | (filter #(contains? (val %) :path-key))
78 | (map key)
79 | set)]
80 | (filter path-set classpath-roots)))
81 |
82 | (defn compile-clj
83 | [{:keys [basis src-dirs compile-opts ns-compile filter-nses class-dir sort bindings] :as params
84 | :or {sort :topo}}]
85 | (let [working-dir (.toFile (Files/createTempDirectory "compile-clj" (into-array FileAttribute [])))
86 | compile-dir-file (file/ensure-dir (api/resolve-path class-dir))
87 | clj-paths (map api/resolve-path (or src-dirs (basis-paths basis)))
88 | nses (cond
89 | (seq ns-compile) ns-compile
90 | (= sort :topo) (nses-in-topo clj-paths)
91 | (= sort :bfs) (nses-in-bfs clj-paths)
92 | :else (throw (ex-info "Missing :ns-compile or :sort order in compile-clj task" {})))
93 | working-compile-dir (file/ensure-dir (jio/file working-dir "compile-clj"))
94 | compile-script (jio/file working-dir "compile.clj")
95 | _ (write-compile-script! compile-script working-compile-dir nses compile-opts bindings)
96 |
97 | ;; java-command will run in context of *project-dir* - basis, classpaths, etc
98 | ;; should all be relative to that (or absolute like working-compile-dir)
99 | process-args (merge
100 | (process/java-command
101 | (merge
102 | (select-keys params [:java-cmd :java-opts :use-cp-file])
103 | {:cp [(.getPath working-compile-dir) class-dir]
104 | :basis basis
105 | :main 'clojure.main
106 | :main-args [(.getCanonicalPath compile-script)]}))
107 | (select-keys params [:out :err :out-file :err-file]))
108 | _ (spit (jio/file working-dir "compile.args") (str/join " " (:command-args process-args)))
109 | {exit :exit, ps-out :out, ps-err :err} (process/process process-args)
110 | ret (cond-> nil
111 | ps-out (assoc :out ps-out)
112 | ps-err (assoc :err ps-err))]
113 | (if (zero? exit)
114 | (do
115 | (if (seq filter-nses)
116 | (file/copy-contents working-compile-dir compile-dir-file (map ns->path filter-nses))
117 | (file/copy-contents working-compile-dir compile-dir-file))
118 | ;; only delete on success, otherwise leave the evidence!
119 | (file/delete working-dir)
120 | ret)
121 | (throw (ex-info (str "Clojure compilation failed, working dir preserved: " (.toString working-dir)) ret)))))
122 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/build/tasks/process.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.process
10 | (:require
11 | [clojure.java.io :as jio]
12 | [clojure.java.process :as proc]
13 | [clojure.tools.deps :as deps]
14 | [clojure.tools.build.api :as api]
15 | [clojure.string :as str])
16 | (:import
17 | [java.io InputStream StringWriter File]))
18 |
19 | (set! *warn-on-reflection* true)
20 |
21 | (defn- trim-blank [^String s]
22 | (if (str/blank? s) nil s))
23 |
24 | (defn process
25 | "Exec the command made from command-args, redirect out and err as directed,
26 | and return {:exit exit-code, :out captured-out, :err captured-err}
27 |
28 | Options:
29 | :command-args - required, coll of string args
30 | :dir - directory to run the command from, default current directory
31 | :out - one of :inherit :capture :write :append :ignore
32 | :err - one of :inherit :capture :write :append :ignore
33 | :out-file - file path to write if :out is :write or :append
34 | :err-file - file path to write if :err is :write or :append
35 | :env - map of environment variables to set
36 |
37 | The :out and :err input flags take one of the following options:
38 | :inherit - inherit the stream and write the subprocess io to this process's stream (default)
39 | :capture - capture the stream to a string and return it
40 | :write - write to :out-file or :err-file
41 | :append - append to :out-file or :err-file
42 | :ignore - ignore the stream"
43 | [{:keys [command-args dir env out err out-file err-file]
44 | :or {dir ".", out :inherit, err :inherit} :as opts}]
45 | (when (not (seq command-args))
46 | (throw (ex-info "process missing required arg :command-args" opts)))
47 | (let [stream-opt (fn [opt file]
48 | (case opt
49 | :inherit :inherit
50 | :write (proc/to-file (api/resolve-path file))
51 | :append (proc/to-file (api/resolve-path file) :append true)
52 | :ignore :discard
53 | (:capture :pipe) :pipe))
54 | proc-opts {:dir (api/resolve-path (or dir "."))
55 | :out (stream-opt out out-file)
56 | :err (stream-opt err err-file)
57 | :env env}
58 | proc (apply proc/start proc-opts command-args)
59 | out-f (when (= out :capture) (proc/io-task #(slurp (proc/stdout proc))))
60 | err-f (when (= err :capture) (proc/io-task #(slurp (proc/stderr proc))))
61 | exit (deref (proc/exit-ref proc))
62 | out-str (when out-f (trim-blank @out-f))
63 | err-str (when err-f (trim-blank @err-f))]
64 | (cond-> {:exit exit}
65 | out-str (assoc :out out-str)
66 | err-str (assoc :err err-str))))
67 |
68 | (comment
69 | (api/process {:command-args ["ls" "-l"]})
70 | (api/process {:command-args ["git" "log"] :out :ignore})
71 | (api/process {:command-args ["java" "-version"] :err :capture})
72 | (api/process {:command-args ["java" "--version"] :out :capture})
73 | (api/process {:env {"FOO" "hi"}
74 | :command-args ["echo" "$FOO"]
75 | :out :capture})
76 | )
77 |
78 | (defn- need-cp-file
79 | [os-name java-version command-length]
80 | (and
81 | ;; this is only an issue on Windows
82 | (str/starts-with? os-name "Win")
83 | ;; CLI support only exists in Java 9+, for Java <= 1.8, the version number is 1.x
84 | (not (str/starts-with? java-version "1."))
85 | ;; the actual limit on windows is 8191 (<8k), but giving some room
86 | (> command-length 8000)))
87 |
88 | (defn- make-java-args
89 | [java-cmd java-opts cp main main-args use-cp-file]
90 | (let [full-args (vec (concat [java-cmd] java-opts ["-cp" cp (name main)] main-args))
91 | arg-str (str/join " " full-args)]
92 | (if (or (= use-cp-file :always)
93 | (and (= use-cp-file :auto)
94 | (need-cp-file (System/getProperty "os.name") (System/getProperty "java.version") (count arg-str))))
95 | (let [cp-file (doto (File/createTempFile "tbuild-" ".cp") (.deleteOnExit))]
96 | (spit cp-file cp)
97 | (vec (concat [java-cmd] java-opts ["-cp" (str "@" (.getAbsolutePath cp-file)) (name main)] main-args)))
98 | full-args)))
99 |
100 | (defn which
101 | "Given the name of an executable, return either a full path to
102 | its location on the system PATH or nil if not found"
103 | [cmd]
104 | (when-let [path (System/getenv "PATH")]
105 | (let [paths (str/split path (re-pattern File/pathSeparator))]
106 | (loop [paths paths]
107 | (when-first [p paths]
108 | (let [f (jio/file p cmd)]
109 | (if (and (.isFile f) (.canExecute f))
110 | (.getCanonicalPath f)
111 | (recur (rest paths)))))))))
112 |
113 | (defn- windows?
114 | []
115 | (str/starts-with? (System/getProperty "os.name") "Windows"))
116 |
117 | (defn- java-exe
118 | []
119 | (if (windows?) "java.exe" "java"))
120 |
121 | (defn- java-home-bin
122 | "Returns path $JAVA_HOME/bin/java if JAVA_HOME set, or nil"
123 | []
124 | (when-let [jhome (System/getenv "JAVA_HOME")]
125 | (let [exe (jio/file jhome "bin" (java-exe))]
126 | (when (and (.exists exe) (.canExecute exe))
127 | (.getCanonicalPath exe)))))
128 |
129 | (defn java-executable
130 | "Given the environment, emulate the Clojure CLI logic to determine the
131 | Java executable path and return it by trying in order:
132 | $JAVA_CMD
133 | java on the PATH
134 | $JAVA_HOME/bin/java"
135 | []
136 | (or
137 | (System/getenv "JAVA_CMD")
138 | (which (java-exe))
139 | (java-home-bin)
140 | (throw (ex-info "Couldn't find java executable via $JAVA_CMD, $PATH, or $JAVA_HOME" {}))))
141 |
142 | (defn java-command
143 | "Create Java command line args. The classpath will be the combination of
144 | :cp followed by the classpath from the basis, both are optional.
145 |
146 | Options:
147 | :java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
148 | :cp - coll of string classpath entries, used first (if provided)
149 | :basis - runtime basis used for classpath, used last (if provided)
150 | :java-opts - coll of string jvm opts
151 | :main - required, main class symbol
152 | :main-args - coll of main class args
153 | :use-cp-file - one of:
154 | :auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
155 | :always - always write classpath to temp file and include
156 | :never - never write classpath to temp file (pass on command line)
157 |
158 | Returns:
159 | :command-args - coll of command arg strings"
160 | [{:keys [java-cmd cp basis java-opts main main-args use-cp-file]
161 | :or {use-cp-file :auto} :as _params}]
162 | (let [cmd (or java-cmd (java-executable))
163 | {:keys [classpath-roots argmap]} basis
164 | cp-entries (concat cp classpath-roots)
165 | cp-str (deps/join-classpath cp-entries)
166 | combined-java-opts (concat java-opts (:jvm-opts argmap))]
167 | {:command-args (make-java-args cmd combined-java-opts cp-str main main-args use-cp-file)}))
168 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | ===========
3 |
4 | * v0.10.11 c6c670a on Oct 28, 2025
5 | * write-pom - TBUILD-41 - add :src-pom :none option
6 | * v0.10.10 deedd62 on Jul 29, 2025
7 | * compile-clj - TBUILD-46 Capture out and error if process is unsuccessful
8 | * v0.10.9 e405aac on May 13, 2025
9 | * write-pom - TBUILD-44 - build.properties file should use `SOURCE_DATE_EPOCH` if set for reproducible builds
10 | * v0.10.8 2fdfd66 on Mar 25, 2025
11 | * process - TBUILD-1 Fix blocked buffering when capturing large output
12 | * v0.10.7 573711e on Feb 8, 2025
13 | * write-pom - add warning if pom-data ignored because src-pom template exists
14 | * Update deps to latest
15 | * v0.10.6 52cf7d6 on Nov 22, 2024
16 | * compile-clj - add stream control args for compilation so out and err can be captured
17 | * java-command - remove assert that :basis is required (that is no longer true)
18 | * v0.10.5 2a21b7a on July 12, 2024
19 | * compile-clj - fix ordering of namespaces not included in topo sort
20 | * v0.10.4 31388ff on Jun 8, 2024
21 | * uber, jar, zip - TBUILD-42 Use buffered output streams everywhere
22 | * v0.10.3 15ead66 on May 1, 2024
23 | * compile-clj - add simple spec for :basis arg
24 | * v0.10.1 5e3b8f3 on Apr 28, 2024
25 | * Update deps to latest
26 | * compile-clj - validate that basis is non-nil
27 | * v0.10.0 3a2c484 on Mar 8, 2024
28 | * Updated deps to latest tools.deps and Clojure 1.11.2
29 | * v0.9.6 8e78bcc on Oct 6, 2023
30 | * write-pom - add :pom-data to supply extra pom data when generating a new pom
31 | * uber - fix exclusions and conflict handling when including local deps on windows
32 | * v0.9.5 24f2894 on Aug 11, 2023
33 | * java-command - TBUILD-14 Use :jvm-opts from aliases in basis, if provided
34 | * Update to latest deps
35 | * v0.9.4 76b78fe on Mar 6, 2023
36 | * uber - exclude Emacs backup files from uberjar inclusion (useful with local/git deps)
37 | * uber - improve error message when file in local or git lib can't be read
38 | * write-pom - improve docstring
39 | * Switch to tools.deps 0.17.1297
40 | * v0.9.3 e537cd1 on Feb 1, 2023
41 | * NO CHANGES - just moved Maven artifact to io.github.clojure groupId to match git dep
42 | * v0.9.2 fe6b140 on Jan 17, 2023
43 | * uber - fix from TBUILD-30 to close copied file streams
44 | * v0.9.1 27ff8a4 on Jan 13, 2023
45 | * uber - TBUILD-35 Fix error on exploding jar with / entry
46 | * uber - TBUILD-30 Apply exclusions and conflict handlers for local and git libs
47 | * v0.9.0 8c93e0c on Dec 22, 2022
48 | * Add clojure.tools.build.api/with-project-root macro
49 | * java-command, compile-clj - TBUILD-34 - Use Clojure CLI logic in finding Java executable
50 | * Switch to tools.deps 0.16.1264
51 | * v0.8.5 9c738da on Nov 14, 2022
52 | * Add support for snapshot and release policies on :mvn/repos (see TDEPS-101)
53 | * v0.8.4 8c3cd69 on Nov 3, 2022
54 | * TBUILD-26 Released as a Maven artifact
55 | * v0.8.3 0d20256 on Jun 28, 2022
56 | * uber - TBUILD-32 - Preserve reader conditionals when merging data\_readers.cljc
57 | * uber - TBUILD-33 - Adjust regex for data\_readers to omit .cljs
58 | * Update to tools.deps.alpha 0.14.1212
59 | * v0.8.2 ba1a2bf on May 6, 2022
60 | * Update deps to latest
61 | * v0.8.1 7d40500 on Mar 11, 2022
62 | * compile-clj - TBUILD-29 - add support for setting bindings during compilation
63 | * v0.8.0 e3e3532 on Feb 24, 2022
64 | * compile-clj - always create classpath entries relative to `*project-root*`
65 | * java-command - don't resolve classpath entries, leave them relative to `*project-root*`
66 | * v0.7.7 1474ad6 on Feb 18, 2022
67 | * compile-clj - TBUILD-27 - Fix bug in prior impl
68 | * v0.7.6 3549b5f on Feb 18, 2022
69 | * compile-clj - TBUILD-27 - Use basis as default src dirs
70 | * Update to tools.deps.alpha 0.12.1148
71 | * v0.7.5 34727f7 on Jan 5, 2022
72 | * Update to tools.deps.alpha 0.12.1109
73 | * v0.7.4 ac442da on Dec 23, 2021
74 | * Update to tools.deps.alpha 0.12.1104
75 | * v0.7.3 2699924 on Dec 22, 2021
76 | * Update to tools.deps.alpha 0.12.1098 (fix occasional race condition in parallel load of S3TransporterFactory)
77 | * v0.7.2 0361dde on Dec 13, 2021
78 | * copy-dir - copy posix file permissions only when posix permissions are supported
79 | * v0.7.1 13f0fec on Dec 12, 2021
80 | * copy-dir - TBUILD-24 - retain file permissions when doing string replace
81 | * v0.7.0 16eddbf on Dec 12, 2021
82 | * write-pom - TBUILD-23 - specify explicit output path with :target
83 | * Update to tools.namespace 1.2.0
84 | * Update to tools.deps.alpha 0.12.1090
85 | * v0.6.8 d79ae84 on Nov 26, 2021
86 | * uber - fix service append regex
87 | * v0.6.7 8cca4f4 on Nov 24, 2021
88 | * git-process - remove debug output
89 | * v0.6.6 4d41c26 on Nov 14, 2021
90 | * install - fix use of deprecated local-repo default in install - thanks @borkdude!
91 | * v0.6.5 a0c3ff6 on Nov 12, 2021
92 | * git-process - NEW task to run an arbitrary git process and return the output
93 | * git-rev-count - updated to use git-process, added :git-command attribute
94 | * v0.6.4 ea76dff on Nov 12, 2021
95 | * java-command - add control over using classpath file with :use-cp-file (default=:auto)
96 | * compile-clj - can now accept java-command passthrough args :java-cmd, :java-opts, :use-cp-file
97 | * v0.6.3 4a1b53a on Nov 8, 2021
98 | * Update to tools.deps 0.12.1071
99 | * v0.6.2 226fb52 on Oct 12, 2021
100 | * Update to tools.deps 0.12.1053
101 | * v0.6.1 515b334 on Oct 10, 2021
102 | * copy-dir - update attribute name added in v0.6.0
103 | * v0.6.0 b139316 on Oct 10, 2021
104 | * compile-clj - TBUILD-20 - fix regression with including class dir on classpath
105 | * copy-dir - add option to copy but not replace in binary files by extension
106 | * v0.5.1 21da7d4 on Sep 21, 2021
107 | * Update to latest tools.deps 0.12.1048
108 | * v0.5.0 7d77952 on Sep 16, 2021
109 | * create-basis - do not include user deps.edn by default
110 | * v0.4.1 452db44 on Sep 16, 2021
111 | * Add some param spec checking
112 | * v0.4.0 801a22f on Sep 15, 2021
113 | * uber - TBUILD-2 - add support for configurable conflict handlers
114 | * uber - TBUILD-11 - detect file and dir with same name in uber
115 | * uber - TBUILD-16 - expand default exclusions
116 | * uber - add support for custom exclusions
117 | * v0.3.0 e418fc9 on Sep 11, 2021
118 | * Bump to latest tools.deps - 0.12.1036
119 | * v0.2.2 3049217 on Sep 7, 2021
120 | * unzip - new task to unzip a zip file in a dir
121 | * v0.2.1 dd64636 on Sep 4, 2021
122 | * jar, uber - replace - with _ in main class name
123 | * v0.2.0 7cbb94b on Aug 31, 2021
124 | * compile-clj - fix docs and code to not require :src-dirs
125 | * compile-clj - TBUILD-7 - sort namespaces using topological sort by default
126 | * v0.1.9 6736c83 on Aug 22, 2021
127 | * git-count-revs - add :path option
128 | * pom-path - new task that computes the path to the pom.xml in a jar
129 | * v0.1.8 38d2780 on Aug 13, 2021
130 | * write-file - TBUILD-15 - add :string option
131 | * write-pom - TBUILD-13 - add :scm options to write scm properties
132 | * v0.1.7 8a3abc2 on July 28, 2021
133 | * TBUILD-10 - fix missing assertions in tests
134 | * Remove unnecessary resource file that overrides tools.deps
135 | * v0.1.6 5636e61 on July 21, 2021
136 | * copy-dir - Fix TBUILD-4 - set up default and overridable file ignore patterns
137 | * v0.1.5 1cd59e6 on July 21, 2021
138 | * jar, uber - Fix TBUILD-8 - jar files built on Windows had bad paths
139 | * v0.1.4 169fef9 on July 20, 2021
140 | * jar - add support for custom :manifest attributes
141 | * uber - add support for custom :manifest attributes
142 | * create-basis - make more tolerant of missing deps.edn file
143 | * update tools.deps.alpha dependency to latest
144 | * v0.1.3 660a71f on July 13, 2021
145 | * write-pom - Fix TBUILD-3 - now takes deps from output of basis libs, so includes alias effects
146 | * uber - exclude META-INF/\*.MF files
147 | * v0.1.2 81f05b7 on July 9, 2021
148 | * Update tools.deps.alpha dependency, public release
149 | * v0.1.1 on July 7, 2021
150 | * Add `java-command` take to create Java command line from basis
151 | * v0.1.0 on July 5, 2021
152 | * Renaming things towards release
153 |
--------------------------------------------------------------------------------
/docs/js/highlight.min.js:
--------------------------------------------------------------------------------
1 | /*! highlight.js v9.6.0 | BSD3 License | git.io/hljslicense */
2 | !function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/[&<>]/gm,function(e){return I[e]})}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return R(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||R(i))return i}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){l+=""+t(e)+">"}function c(e){("start"===e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):E(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"===e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function l(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function h(e,n,t,r){var a=r?"":y.classPrefix,i='',i+n+o}function p(){var e,t,r,a;if(!E.k)return n(B);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(B);r;)a+=n(B.substr(t,r.index-t)),e=g(E,r),e?(M+=e[1],a+=h(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(B);return a+n(B.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!x[E.sL])return n(B);var t=e?l(E.sL,B,!0,L[E.sL]):f(B,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(L[E.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){k+=null!=E.sL?d():p(),B=""}function v(e){k+=e.cN?h(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(B+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?B+=n:(t.eB&&(B+=n),b(),t.rB||t.eB||(B=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?B+=n:(a.rE||a.eE||(B+=n),b(),a.eE&&(B=n));do E.cN&&(k+=C),E.skip||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return B+=n,n.length||1}var N=R(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var w,E=i||N,L={},k="";for(w=E;w!==N;w=w.parent)w.cN&&(k=h(w.cN,"",!0)+k);var B="",M=0;try{for(var I,j,O=0;;){if(E.t.lastIndex=O,I=E.t.exec(t),!I)break;j=m(t.substr(O,I.index-O),I[0]),O=I.index+j}for(m(t.substr(O)),w=E;w.parent;w=w.parent)w.cN&&(k+=C);return{r:M,value:k,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function f(e,t){t=t||y.languages||E(x);var r={r:0,value:n(e)},a=r;return t.filter(R).forEach(function(n){var t=l(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function g(e){return y.tabReplace||y.useBR?e.replace(M,function(e,n){return y.useBR&&"\n"===e?" ":y.tabReplace?n.replace(/\t/g,y.tabReplace):void 0}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n,t,r,o,s,p=i(e);a(p)||(y.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/ /g,"\n")):n=e,s=n.textContent,r=p?l(p,s,!0):f(s),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),s)),r.value=g(r.value),e.innerHTML=r.value,e.className=h(e.className,p,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function d(e){y=o(y,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");w.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function N(){return E(x)}function R(e){return e=(e||"").toLowerCase(),x[e]||x[L[e]]}var w=[],E=Object.keys,x={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="",y={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},I={"&":"&","<":"<",">":">"};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=R,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("clojure",function(e){var t={"builtin-name":"def defonce cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="a-zA-Z_\\-!.?+*=<>'",n="["+r+"]["+r+"0-9/;:]*",a="[-+]?\\d+(\\.\\d+)?",o={b:n,r:0},s={cN:"number",b:a,r:0},i=e.inherit(e.QSM,{i:null}),c=e.C(";","$",{r:0}),d={cN:"literal",b:/\b(true|false|nil)\b/},l={b:"[\\[\\{]",e:"[\\]\\}]"},m={cN:"comment",b:"\\^"+n},p=e.C("\\^\\{","\\}"),u={cN:"symbol",b:"[:]{1,2}"+n},f={b:"\\(",e:"\\)"},h={eW:!0,r:0},y={k:t,l:n,cN:"name",b:n,starts:h},b=[f,i,m,p,c,u,l,s,d,o];return f.c=[e.C("comment",""),y,h],h.c=b,l.c=b,{aliases:["clj"],i:/\S/,c:[f,i,m,p,c,u,l,s,d]}});hljs.registerLanguage("clojure-repl",function(e){return{c:[{cN:"meta",b:/^([\w.-]+|\s*#_)=>/,starts:{e:/$/,sL:"clojure"}}]}});
--------------------------------------------------------------------------------
/docs/css/default.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica, Arial, sans-serif;
3 | font-size: 15px;
4 | }
5 |
6 | pre, code {
7 | font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
8 | font-size: 9pt;
9 | margin: 15px 0;
10 | }
11 |
12 | h1 {
13 | font-weight: normal;
14 | font-size: 29px;
15 | margin: 10px 0 2px 0;
16 | padding: 0;
17 | }
18 |
19 | h2 {
20 | font-weight: normal;
21 | font-size: 25px;
22 | }
23 |
24 | h5.license {
25 | margin: 9px 0 22px 0;
26 | color: #555;
27 | font-weight: normal;
28 | font-size: 12px;
29 | font-style: italic;
30 | }
31 |
32 | .document h1, .namespace-index h1 {
33 | font-size: 32px;
34 | margin-top: 12px;
35 | }
36 |
37 | #header, #content, .sidebar {
38 | position: fixed;
39 | }
40 |
41 | #header {
42 | top: 0;
43 | left: 0;
44 | right: 0;
45 | height: 22px;
46 | color: #f5f5f5;
47 | padding: 5px 7px;
48 | }
49 |
50 | #content {
51 | top: 32px;
52 | right: 0;
53 | bottom: 0;
54 | overflow: auto;
55 | background: #fff;
56 | color: #333;
57 | padding: 0 18px;
58 | }
59 |
60 | .sidebar {
61 | position: fixed;
62 | top: 32px;
63 | bottom: 0;
64 | overflow: auto;
65 | }
66 |
67 | .sidebar.primary {
68 | background: #e2e2e2;
69 | border-right: solid 1px #cccccc;
70 | left: 0;
71 | width: 250px;
72 | }
73 |
74 | .sidebar.secondary {
75 | background: #f2f2f2;
76 | border-right: solid 1px #d7d7d7;
77 | left: 251px;
78 | width: 200px;
79 | }
80 |
81 | #content.namespace-index, #content.document {
82 | left: 251px;
83 | }
84 |
85 | #content.namespace-docs {
86 | left: 452px;
87 | }
88 |
89 | #content.document {
90 | padding-bottom: 10%;
91 | }
92 |
93 | #header {
94 | background: #3f3f3f;
95 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
96 | z-index: 100;
97 | }
98 |
99 | #header h1 {
100 | margin: 0;
101 | padding: 0;
102 | font-size: 18px;
103 | font-weight: lighter;
104 | text-shadow: -1px -1px 0px #333;
105 | }
106 |
107 | #header h1 .project-version {
108 | font-weight: normal;
109 | }
110 |
111 | .project-version {
112 | padding-left: 0.15em;
113 | }
114 |
115 | #header a, .sidebar a {
116 | display: block;
117 | text-decoration: none;
118 | }
119 |
120 | #header a {
121 | color: #f5f5f5;
122 | }
123 |
124 | .sidebar a {
125 | color: #333;
126 | }
127 |
128 | #header h2 {
129 | float: right;
130 | font-size: 9pt;
131 | font-weight: normal;
132 | margin: 4px 3px;
133 | padding: 0;
134 | color: #bbb;
135 | }
136 |
137 | #header h2 a {
138 | display: inline;
139 | }
140 |
141 | .sidebar h3 {
142 | margin: 0;
143 | padding: 10px 13px 0 13px;
144 | font-size: 19px;
145 | font-weight: lighter;
146 | }
147 |
148 | .sidebar h3 a {
149 | color: #444;
150 | }
151 |
152 | .sidebar h3.no-link {
153 | color: #636363;
154 | }
155 |
156 | .sidebar ul {
157 | padding: 7px 0 6px 0;
158 | margin: 0;
159 | }
160 |
161 | .sidebar ul.index-link {
162 | padding-bottom: 4px;
163 | }
164 |
165 | .sidebar li {
166 | display: block;
167 | vertical-align: middle;
168 | }
169 |
170 | .sidebar li a, .sidebar li .no-link {
171 | border-left: 3px solid transparent;
172 | padding: 0 10px;
173 | white-space: nowrap;
174 | }
175 |
176 | .sidebar li .no-link {
177 | display: block;
178 | color: #777;
179 | font-style: italic;
180 | }
181 |
182 | .sidebar li .inner {
183 | display: inline-block;
184 | padding-top: 7px;
185 | height: 24px;
186 | }
187 |
188 | .sidebar li a, .sidebar li .tree {
189 | height: 31px;
190 | }
191 |
192 | .depth-1 .inner { padding-left: 2px; }
193 | .depth-2 .inner { padding-left: 6px; }
194 | .depth-3 .inner { padding-left: 20px; }
195 | .depth-4 .inner { padding-left: 34px; }
196 | .depth-5 .inner { padding-left: 48px; }
197 | .depth-6 .inner { padding-left: 62px; }
198 |
199 | .sidebar li .tree {
200 | display: block;
201 | float: left;
202 | position: relative;
203 | top: -10px;
204 | margin: 0 4px 0 0;
205 | padding: 0;
206 | }
207 |
208 | .sidebar li.depth-1 .tree {
209 | display: none;
210 | }
211 |
212 | .sidebar li .tree .top, .sidebar li .tree .bottom {
213 | display: block;
214 | margin: 0;
215 | padding: 0;
216 | width: 7px;
217 | }
218 |
219 | .sidebar li .tree .top {
220 | border-left: 1px solid #aaa;
221 | border-bottom: 1px solid #aaa;
222 | height: 19px;
223 | }
224 |
225 | .sidebar li .tree .bottom {
226 | height: 22px;
227 | }
228 |
229 | .sidebar li.branch .tree .bottom {
230 | border-left: 1px solid #aaa;
231 | }
232 |
233 | .sidebar.primary li.current a {
234 | border-left: 3px solid #a33;
235 | color: #a33;
236 | }
237 |
238 | .sidebar.secondary li.current a {
239 | border-left: 3px solid #33a;
240 | color: #33a;
241 | }
242 |
243 | .namespace-index h2 {
244 | margin: 30px 0 0 0;
245 | }
246 |
247 | .namespace-index h3 {
248 | font-size: 16px;
249 | font-weight: bold;
250 | margin-bottom: 0;
251 | }
252 |
253 | .namespace-index .topics {
254 | padding-left: 30px;
255 | margin: 11px 0 0 0;
256 | }
257 |
258 | .namespace-index .topics li {
259 | padding: 5px 0;
260 | }
261 |
262 | .namespace-docs h3 {
263 | font-size: 18px;
264 | font-weight: bold;
265 | }
266 |
267 | .public h3 {
268 | margin: 0;
269 | float: left;
270 | }
271 |
272 | .usage {
273 | clear: both;
274 | }
275 |
276 | .public {
277 | margin: 0;
278 | border-top: 1px solid #e0e0e0;
279 | padding-top: 14px;
280 | padding-bottom: 6px;
281 | }
282 |
283 | .public:last-child {
284 | margin-bottom: 20%;
285 | }
286 |
287 | .members .public:last-child {
288 | margin-bottom: 0;
289 | }
290 |
291 | .members {
292 | margin: 15px 0;
293 | }
294 |
295 | .members h4 {
296 | color: #555;
297 | font-weight: normal;
298 | font-variant: small-caps;
299 | margin: 0 0 5px 0;
300 | }
301 |
302 | .members .inner {
303 | padding-top: 5px;
304 | padding-left: 12px;
305 | margin-top: 2px;
306 | margin-left: 7px;
307 | border-left: 1px solid #bbb;
308 | }
309 |
310 | #content .members .inner h3 {
311 | font-size: 12pt;
312 | }
313 |
314 | .members .public {
315 | border-top: none;
316 | margin-top: 0;
317 | padding-top: 6px;
318 | padding-bottom: 0;
319 | }
320 |
321 | .members .public:first-child {
322 | padding-top: 0;
323 | }
324 |
325 | h4.type,
326 | h4.dynamic,
327 | h4.added,
328 | h4.deprecated {
329 | float: left;
330 | margin: 3px 10px 15px 0;
331 | font-size: 15px;
332 | font-weight: bold;
333 | font-variant: small-caps;
334 | }
335 |
336 | .public h4.type,
337 | .public h4.dynamic,
338 | .public h4.added,
339 | .public h4.deprecated {
340 | font-size: 13px;
341 | font-weight: bold;
342 | margin: 3px 0 0 10px;
343 | }
344 |
345 | .members h4.type,
346 | .members h4.added,
347 | .members h4.deprecated {
348 | margin-top: 1px;
349 | }
350 |
351 | h4.type {
352 | color: #717171;
353 | }
354 |
355 | h4.dynamic {
356 | color: #9933aa;
357 | }
358 |
359 | h4.added {
360 | color: #508820;
361 | }
362 |
363 | h4.deprecated {
364 | color: #880000;
365 | }
366 |
367 | .namespace {
368 | margin-bottom: 30px;
369 | }
370 |
371 | .namespace:last-child {
372 | margin-bottom: 10%;
373 | }
374 |
375 | .index {
376 | padding: 0;
377 | font-size: 80%;
378 | margin: 15px 0;
379 | line-height: 16px;
380 | }
381 |
382 | .index * {
383 | display: inline;
384 | }
385 |
386 | .index p {
387 | padding-right: 3px;
388 | }
389 |
390 | .index li {
391 | padding-right: 5px;
392 | }
393 |
394 | .index ul {
395 | padding-left: 0;
396 | }
397 |
398 | .type-sig {
399 | clear: both;
400 | color: #088;
401 | }
402 |
403 | .type-sig pre {
404 | padding-top: 10px;
405 | margin: 0;
406 | }
407 |
408 | .usage code {
409 | display: block;
410 | color: #008;
411 | margin: 2px 0;
412 | }
413 |
414 | .usage code:first-child {
415 | padding-top: 10px;
416 | }
417 |
418 | p {
419 | margin: 15px 0;
420 | }
421 |
422 | .public p:first-child, .public pre.plaintext {
423 | margin-top: 12px;
424 | }
425 |
426 | .doc {
427 | margin: 0 0 26px 0;
428 | clear: both;
429 | }
430 |
431 | .public .doc {
432 | margin: 0;
433 | }
434 |
435 | .namespace-index .doc {
436 | margin-bottom: 20px;
437 | }
438 |
439 | .namespace-index .namespace .doc {
440 | margin-bottom: 10px;
441 | }
442 |
443 | .markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
444 | line-height: 22px;
445 | }
446 |
447 | .markdown li {
448 | padding: 2px 0;
449 | }
450 |
451 | .markdown h2 {
452 | font-weight: normal;
453 | font-size: 25px;
454 | margin: 30px 0 10px 0;
455 | }
456 |
457 | .markdown h3 {
458 | font-weight: normal;
459 | font-size: 20px;
460 | margin: 30px 0 0 0;
461 | }
462 |
463 | .markdown h4 {
464 | font-size: 15px;
465 | margin: 22px 0 -4px 0;
466 | }
467 |
468 | .doc, .public, .namespace .index {
469 | max-width: 680px;
470 | overflow-x: visible;
471 | }
472 |
473 | .markdown pre > code {
474 | display: block;
475 | padding: 10px;
476 | }
477 |
478 | .markdown pre > code, .src-link a {
479 | border: 1px solid #e4e4e4;
480 | border-radius: 2px;
481 | }
482 |
483 | .markdown code:not(.hljs), .src-link a {
484 | background: #f6f6f6;
485 | }
486 |
487 | pre.deps {
488 | display: inline-block;
489 | margin: 0 10px;
490 | border: 1px solid #e4e4e4;
491 | border-radius: 2px;
492 | padding: 10px;
493 | background-color: #f6f6f6;
494 | }
495 |
496 | .markdown hr {
497 | border-style: solid;
498 | border-top: none;
499 | color: #ccc;
500 | }
501 |
502 | .doc ul, .doc ol {
503 | padding-left: 30px;
504 | }
505 |
506 | .doc table {
507 | border-collapse: collapse;
508 | margin: 0 10px;
509 | }
510 |
511 | .doc table td, .doc table th {
512 | border: 1px solid #dddddd;
513 | padding: 4px 6px;
514 | }
515 |
516 | .doc table th {
517 | background: #f2f2f2;
518 | }
519 |
520 | .doc dl {
521 | margin: 0 10px 20px 10px;
522 | }
523 |
524 | .doc dl dt {
525 | font-weight: bold;
526 | margin: 0;
527 | padding: 3px 0;
528 | border-bottom: 1px solid #ddd;
529 | }
530 |
531 | .doc dl dd {
532 | padding: 5px 0;
533 | margin: 0 0 5px 10px;
534 | }
535 |
536 | .doc abbr {
537 | border-bottom: 1px dotted #333;
538 | font-variant: none;
539 | cursor: help;
540 | }
541 |
542 | .src-link {
543 | margin-bottom: 15px;
544 | }
545 |
546 | .src-link a {
547 | font-size: 70%;
548 | padding: 1px 4px;
549 | text-decoration: none;
550 | color: #5555bb;
551 | }
552 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/build/tasks/write_pom.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.write-pom
10 | (:require
11 | [clojure.java.io :as jio]
12 | [clojure.string :as str]
13 | [clojure.data.xml :as xml]
14 | [clojure.data.xml.tree :as tree]
15 | [clojure.data.xml.event :as event]
16 | [clojure.walk :as walk]
17 | [clojure.zip :as zip]
18 | [clojure.tools.deps.util.maven :as maven]
19 | [clojure.tools.deps.util.io :refer [printerrln]]
20 | [clojure.tools.build.api :as api]
21 | [clojure.tools.build.util.file :as file])
22 | (:import [clojure.data.xml.node Element]
23 | [java.io Reader]
24 | [java.time Instant ZoneId ZonedDateTime]
25 | [java.time.format DateTimeFormatter]))
26 |
27 | (set! *warn-on-reflection* true)
28 |
29 | (xml/alias-uri 'pom "http://maven.apache.org/POM/4.0.0")
30 | (def ^:private pom-ns (name (.-name ^clojure.lang.Namespace (get (ns-aliases *ns*) 'pom))))
31 |
32 |
33 | (defn- to-dep
34 | [[lib {:keys [mvn/version exclusions optional] :as coord}]]
35 | (let [[group-id artifact-id classifier] (maven/lib->names lib)]
36 | (if version
37 | (cond->
38 | [::pom/dependency
39 | [::pom/groupId group-id]
40 | [::pom/artifactId artifact-id]
41 | [::pom/version version]]
42 |
43 | classifier
44 | (conj [::pom/classifier classifier])
45 |
46 | (seq exclusions)
47 | (conj [::pom/exclusions
48 | (map (fn [excl]
49 | [::pom/exclusion
50 | [::pom/groupId (or (namespace excl) (name excl))]
51 | [::pom/artifactId (name excl)]])
52 | exclusions)])
53 |
54 | optional
55 | (conj [::pom/optional "true"]))
56 | (printerrln "Skipping coordinate:" coord))))
57 |
58 | (defn- gen-deps
59 | [deps]
60 | [::pom/dependencies
61 | (map to-dep deps)])
62 |
63 | (defn- gen-source-dir
64 | [path]
65 | [::pom/sourceDirectory path])
66 |
67 | (defn- to-resource
68 | [resource]
69 | [::pom/resource
70 | [::pom/directory resource]])
71 |
72 | (defn- gen-resources
73 | [rpaths]
74 | [::pom/resources
75 | (map to-resource rpaths)])
76 |
77 | (defn- to-repo-policy
78 | [parent-tag {:keys [enabled update checksum]}]
79 | [parent-tag
80 | (when (some? enabled) [::pom/enabled (str enabled)])
81 | (when update [::pom/updatePolicy (if (keyword? update) (name update) (str "interval:" update))])
82 | (when checksum [::pom/checksumPolicy (name checksum)])])
83 |
84 | (defn- to-repo
85 | [[name {:keys [url snapshots releases]}]]
86 | [::pom/repository
87 | [::pom/id name]
88 | [::pom/url url]
89 | (when releases (to-repo-policy ::pom/releases releases))
90 | (when snapshots (to-repo-policy ::pom/snapshots snapshots))])
91 |
92 | (defn- gen-repos
93 | [repos]
94 | [::pom/repositories
95 | (map to-repo repos)])
96 |
97 | (defn- pomify
98 | [val]
99 | (if (and (vector? val) (keyword? (first val)))
100 | (into [(keyword pom-ns (name (first val)))] (rest val))
101 | val))
102 |
103 | (defn- gen-pom
104 | [{:keys [deps src-paths resource-paths repos group artifact version scm pom-data]
105 | :or {version "0.1.0"}}]
106 | (let [[path & paths] src-paths
107 | {:keys [connection developerConnection tag url]} scm]
108 | (xml/sexp-as-element
109 | (into
110 | [::pom/project
111 | {:xmlns "http://maven.apache.org/POM/4.0.0"
112 | (keyword "xmlns:xsi") "http://www.w3.org/2001/XMLSchema-instance"
113 | (keyword "xsi:schemaLocation") "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"}
114 | [::pom/modelVersion "4.0.0"]
115 | [::pom/packaging "jar"]
116 | [::pom/groupId group]
117 | [::pom/artifactId artifact]
118 | [::pom/version version]
119 | [::pom/name artifact]
120 | (gen-deps deps)
121 | (when (or path (seq resource-paths))
122 | (when (seq paths) (apply printerrln "Skipping paths:" paths))
123 | [::pom/build
124 | (when path (gen-source-dir path))
125 | (when (seq resource-paths) (gen-resources resource-paths))])
126 | (gen-repos repos)
127 | (when scm
128 | [::pom/scm
129 | (when connection [::pom/connection connection])
130 | (when developerConnection [::pom/developerConnection developerConnection])
131 | (when tag [::pom/tag tag])
132 | (when url [::pom/url url])])]
133 | (walk/postwalk pomify pom-data)))))
134 |
135 | (defn- make-xml-element
136 | [{:keys [tag attrs] :as node} children]
137 | (with-meta
138 | (apply xml/element tag attrs children)
139 | (meta node)))
140 |
141 | (defn- xml-update
142 | [root tag-path replace-node]
143 | (let [z (zip/zipper xml/element? :content make-xml-element root)]
144 | (zip/root
145 | (loop [[tag & more-tags :as tags] tag-path, parent z, child (zip/down z)]
146 | (if child
147 | (if (= tag (:tag (zip/node child)))
148 | (if (seq more-tags)
149 | (recur more-tags child (zip/down child))
150 | (zip/edit child (constantly replace-node)))
151 | (if-let [next-sibling (zip/right child)]
152 | (recur tags parent next-sibling)
153 | (if (seq more-tags)
154 | (let [new-parent (zip/append-child parent (xml/sexp-as-element tag))
155 | new-child (zip/rightmost (zip/down new-parent))]
156 | (recur more-tags new-child (zip/down new-child)))
157 | (zip/append-child parent replace-node))))
158 | (if (seq more-tags)
159 | (let [new-parent (zip/append-child parent (xml/sexp-as-element tag))
160 | new-child (zip/rightmost (zip/down new-parent))]
161 | (recur more-tags new-child (zip/down new-child)))
162 | (zip/append-child parent replace-node)))))))
163 |
164 | (defn- replace-deps
165 | [pom deps]
166 | (xml-update pom [::pom/dependencies] (xml/sexp-as-element (gen-deps deps))))
167 |
168 | (defn- replace-paths
169 | [pom [path & paths]]
170 | (if path
171 | (do
172 | (when (seq paths) (apply printerrln "Skipping paths:" paths))
173 | (xml-update pom [::pom/build ::pom/sourceDirectory] (xml/sexp-as-element (gen-source-dir path))))
174 | pom))
175 |
176 | (defn- replace-resources
177 | [pom resource-paths]
178 | (if (seq resource-paths)
179 | (xml-update pom [::pom/build ::pom/resources] (xml/sexp-as-element (gen-resources resource-paths)))
180 | pom))
181 |
182 | (defn- replace-repos
183 | [pom repos]
184 | (if (seq repos)
185 | (xml-update pom [::pom/repositories] (xml/sexp-as-element (gen-repos repos)))
186 | pom))
187 |
188 | (defn- replace-lib
189 | [pom lib]
190 | (if lib
191 | (-> pom
192 | (xml-update [::pom/groupId] (xml/sexp-as-element [::pom/groupId (namespace lib)]))
193 | (xml-update [::pom/artifactId] (xml/sexp-as-element [::pom/artifactId (name lib)]))
194 | (xml-update [::pom/name] (xml/sexp-as-element [::pom/name (name lib)])))
195 | pom))
196 |
197 | (defn- replace-version
198 | [pom version]
199 | (if version
200 | (xml-update pom [::pom/version] (xml/sexp-as-element [::pom/version version]))
201 | pom))
202 |
203 | (defn- replace-scm
204 | [pom {:keys [connection developerConnection tag url] :as scm}]
205 | (if scm
206 | (cond-> pom
207 | connection (xml-update [::pom/scm ::pom/connection] (xml/sexp-as-element [::pom/connection connection]))
208 | developerConnection (xml-update [::pom/scm ::pom/developerConnection] (xml/sexp-as-element [::pom/developerConnection developerConnection]))
209 | tag (xml-update [::pom/scm ::pom/tag] (xml/sexp-as-element [::pom/tag tag]))
210 | url (xml-update [::pom/scm ::pom/url] (xml/sexp-as-element [::pom/url url])))
211 | pom))
212 |
213 | (defn- parse-xml
214 | [^Reader rdr]
215 | (let [roots (tree/seq-tree event/event-element event/event-exit? event/event-node
216 | (xml/event-seq rdr {:include-node? #{:element :characters :comment}
217 | :skip-whitespace true}))]
218 | (first (filter #(instance? Element %) (first roots)))))
219 |
220 | (defn- libs->deps
221 | "Convert libmap to root deps"
222 | [libs]
223 | (reduce-kv
224 | (fn [ret lib {:keys [dependents] :as coord}]
225 | (if (seq dependents)
226 | ret
227 | (assoc ret lib coord)))
228 | {} libs))
229 |
230 | (defn meta-maven-path
231 | [params]
232 | (let [{:keys [lib]} params
233 | pom-file (jio/file "META-INF" "maven" (namespace lib) (name lib))]
234 | (.toString pom-file)))
235 |
236 | (defn write-pom
237 | [params]
238 | (let [{:keys [basis class-dir target src-pom lib version scm src-dirs resource-dirs repos pom-data]} params
239 | {:keys [libs]} basis
240 | root-deps (libs->deps libs)
241 | src-pom-file (when-not (= :none src-pom)
242 | (api/resolve-path (or src-pom "pom.xml")))
243 | repos (or repos (remove #(= "https://repo1.maven.org/maven2/" (-> % val :url)) (:mvn/repos basis)))
244 | pom (if (and src-pom-file (.exists src-pom-file))
245 | (do
246 | (when pom-data
247 | (println "Warning in write-pom: pom-data supplied but not used because pom template exists at" (or src-pom "pom.xml")))
248 | (with-open [rdr (jio/reader src-pom-file)]
249 | (-> rdr
250 | parse-xml
251 | (replace-deps root-deps)
252 | (replace-paths src-dirs)
253 | (replace-resources resource-dirs)
254 | (replace-repos repos)
255 | (replace-lib lib)
256 | (replace-version version)
257 | (replace-scm scm))))
258 | (gen-pom
259 | (cond->
260 | {:deps root-deps
261 | :src-paths src-dirs
262 | :resource-paths resource-dirs
263 | :repos repos
264 | :group (namespace lib)
265 | :artifact (name lib)}
266 | version (assoc :version version)
267 | scm (assoc :scm scm)
268 | pom-data (assoc :pom-data pom-data))))
269 | pom-dir-file (file/ensure-dir
270 | (cond
271 | class-dir (jio/file (api/resolve-path class-dir) (meta-maven-path {:lib lib}))
272 | target (-> target api/resolve-path jio/file file/ensure-dir)
273 | :else (throw (ex-info "write-pom requires either :class-dir or :target" {}))))]
274 | (spit (jio/file pom-dir-file "pom.xml") (xml/indent-str pom))
275 | (spit (jio/file pom-dir-file "pom.properties")
276 | (str/join (System/lineSeparator)
277 | ["# Generated by org.clojure/tools.build"
278 | (let [dtf (DateTimeFormatter/ofPattern "E MMM d HH:mm:ss 'UTC' u")
279 | inst (or (some-> "SOURCE_DATE_EPOCH"
280 | System/getenv
281 | parse-long
282 | Instant/ofEpochSecond)
283 | (Instant/now))]
284 | (str "# " (.format dtf (ZonedDateTime/ofInstant inst (ZoneId/of "Z")))))
285 | (format "version=%s" version)
286 | (format "groupId=%s" (namespace lib))
287 | (format "artifactId=%s" (name lib))]))))
288 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Eclipse Public License - v 1.0
2 |
3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6 |
7 | 1. DEFINITIONS
8 |
9 | "Contribution" means:
10 |
11 | a) in the case of the initial Contributor, the initial code and documentation
12 | distributed under this Agreement, and
13 | b) in the case of each subsequent Contributor:
14 | i) changes to the Program, and
15 | ii) additions to the Program;
16 |
17 | where such changes and/or additions to the Program originate from and are
18 | distributed by that particular Contributor. A Contribution 'originates'
19 | from a Contributor if it was added to the Program by such Contributor
20 | itself or anyone acting on such Contributor's behalf. Contributions do not
21 | include additions to the Program which: (i) are separate modules of
22 | software distributed in conjunction with the Program under their own
23 | license agreement, and (ii) are not derivative works of the Program.
24 |
25 | "Contributor" means any person or entity that distributes the Program.
26 |
27 | "Licensed Patents" mean patent claims licensable by a Contributor which are
28 | necessarily infringed by the use or sale of its Contribution alone or when
29 | combined with the Program.
30 |
31 | "Program" means the Contributions distributed in accordance with this
32 | Agreement.
33 |
34 | "Recipient" means anyone who receives the Program under this Agreement,
35 | including all Contributors.
36 |
37 | 2. GRANT OF RIGHTS
38 | a) Subject to the terms of this Agreement, each Contributor hereby grants
39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
40 | reproduce, prepare derivative works of, publicly display, publicly
41 | perform, distribute and sublicense the Contribution of such Contributor,
42 | if any, and such derivative works, in source code and object code form.
43 | b) Subject to the terms of this Agreement, each Contributor hereby grants
44 | Recipient a non-exclusive, worldwide, royalty-free patent license under
45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise
46 | transfer the Contribution of such Contributor, if any, in source code and
47 | object code form. This patent license shall apply to the combination of
48 | the Contribution and the Program if, at the time the Contribution is
49 | added by the Contributor, such addition of the Contribution causes such
50 | combination to be covered by the Licensed Patents. The patent license
51 | shall not apply to any other combinations which include the Contribution.
52 | No hardware per se is licensed hereunder.
53 | c) Recipient understands that although each Contributor grants the licenses
54 | to its Contributions set forth herein, no assurances are provided by any
55 | Contributor that the Program does not infringe the patent or other
56 | intellectual property rights of any other entity. Each Contributor
57 | disclaims any liability to Recipient for claims brought by any other
58 | entity based on infringement of intellectual property rights or
59 | otherwise. As a condition to exercising the rights and licenses granted
60 | hereunder, each Recipient hereby assumes sole responsibility to secure
61 | any other intellectual property rights needed, if any. For example, if a
62 | third party patent license is required to allow Recipient to distribute
63 | the Program, it is Recipient's responsibility to acquire that license
64 | before distributing the Program.
65 | d) Each Contributor represents that to its knowledge it has sufficient
66 | copyright rights in its Contribution, if any, to grant the copyright
67 | license set forth in this Agreement.
68 |
69 | 3. REQUIREMENTS
70 |
71 | A Contributor may choose to distribute the Program in object code form under
72 | its own license agreement, provided that:
73 |
74 | a) it complies with the terms and conditions of this Agreement; and
75 | b) its license agreement:
76 | i) effectively disclaims on behalf of all Contributors all warranties
77 | and conditions, express and implied, including warranties or
78 | conditions of title and non-infringement, and implied warranties or
79 | conditions of merchantability and fitness for a particular purpose;
80 | ii) effectively excludes on behalf of all Contributors all liability for
81 | damages, including direct, indirect, special, incidental and
82 | consequential damages, such as lost profits;
83 | iii) states that any provisions which differ from this Agreement are
84 | offered by that Contributor alone and not by any other party; and
85 | iv) states that source code for the Program is available from such
86 | Contributor, and informs licensees how to obtain it in a reasonable
87 | manner on or through a medium customarily used for software exchange.
88 |
89 | When the Program is made available in source code form:
90 |
91 | a) it must be made available under this Agreement; and
92 | b) a copy of this Agreement must be included with each copy of the Program.
93 | Contributors may not remove or alter any copyright notices contained
94 | within the Program.
95 |
96 | Each Contributor must identify itself as the originator of its Contribution,
97 | if
98 | any, in a manner that reasonably allows subsequent Recipients to identify the
99 | originator of the Contribution.
100 |
101 | 4. COMMERCIAL DISTRIBUTION
102 |
103 | Commercial distributors of software may accept certain responsibilities with
104 | respect to end users, business partners and the like. While this license is
105 | intended to facilitate the commercial use of the Program, the Contributor who
106 | includes the Program in a commercial product offering should do so in a manner
107 | which does not create potential liability for other Contributors. Therefore,
108 | if a Contributor includes the Program in a commercial product offering, such
109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
110 | every other Contributor ("Indemnified Contributor") against any losses,
111 | damages and costs (collectively "Losses") arising from claims, lawsuits and
112 | other legal actions brought by a third party against the Indemnified
113 | Contributor to the extent caused by the acts or omissions of such Commercial
114 | Contributor in connection with its distribution of the Program in a commercial
115 | product offering. The obligations in this section do not apply to any claims
116 | or Losses relating to any actual or alleged intellectual property
117 | infringement. In order to qualify, an Indemnified Contributor must:
118 | a) promptly notify the Commercial Contributor in writing of such claim, and
119 | b) allow the Commercial Contributor to control, and cooperate with the
120 | Commercial Contributor in, the defense and any related settlement
121 | negotiations. The Indemnified Contributor may participate in any such claim at
122 | its own expense.
123 |
124 | For example, a Contributor might include the Program in a commercial product
125 | offering, Product X. That Contributor is then a Commercial Contributor. If
126 | that Commercial Contributor then makes performance claims, or offers
127 | warranties related to Product X, those performance claims and warranties are
128 | such Commercial Contributor's responsibility alone. Under this section, the
129 | Commercial Contributor would have to defend claims against the other
130 | Contributors related to those performance claims and warranties, and if a
131 | court requires any other Contributor to pay any damages as a result, the
132 | Commercial Contributor must pay those damages.
133 |
134 | 5. NO WARRANTY
135 |
136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
140 | Recipient is solely responsible for determining the appropriateness of using
141 | and distributing the Program and assumes all risks associated with its
142 | exercise of rights under this Agreement , including but not limited to the
143 | risks and costs of program errors, compliance with applicable laws, damage to
144 | or loss of data, programs or equipment, and unavailability or interruption of
145 | operations.
146 |
147 | 6. DISCLAIMER OF LIABILITY
148 |
149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
156 | OF SUCH DAMAGES.
157 |
158 | 7. GENERAL
159 |
160 | If any provision of this Agreement is invalid or unenforceable under
161 | applicable law, it shall not affect the validity or enforceability of the
162 | remainder of the terms of this Agreement, and without further action by the
163 | parties hereto, such provision shall be reformed to the minimum extent
164 | necessary to make such provision valid and enforceable.
165 |
166 | If Recipient institutes patent litigation against any entity (including a
167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
168 | (excluding combinations of the Program with other software or hardware)
169 | infringes such Recipient's patent(s), then such Recipient's rights granted
170 | under Section 2(b) shall terminate as of the date such litigation is filed.
171 |
172 | All Recipient's rights under this Agreement shall terminate if it fails to
173 | comply with any of the material terms or conditions of this Agreement and does
174 | not cure such failure in a reasonable period of time after becoming aware of
175 | such noncompliance. If all Recipient's rights under this Agreement terminate,
176 | Recipient agrees to cease use and distribution of the Program as soon as
177 | reasonably practicable. However, Recipient's obligations under this Agreement
178 | and any licenses granted by Recipient relating to the Program shall continue
179 | and survive.
180 |
181 | Everyone is permitted to copy and distribute copies of this Agreement, but in
182 | order to avoid inconsistency the Agreement is copyrighted and may only be
183 | modified in the following manner. The Agreement Steward reserves the right to
184 | publish new versions (including revisions) of this Agreement from time to
185 | time. No one other than the Agreement Steward has the right to modify this
186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The
187 | Eclipse Foundation may assign the responsibility to serve as the Agreement
188 | Steward to a suitable separate entity. Each new version of the Agreement will
189 | be given a distinguishing version number. The Program (including
190 | Contributions) may always be distributed subject to the version of the
191 | Agreement under which it was received. In addition, after a new version of the
192 | Agreement is published, Contributor may elect to distribute the Program
193 | (including its Contributions) under the new version. Except as expressly
194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
195 | licenses to the intellectual property of any Contributor under this Agreement,
196 | whether expressly, by implication, estoppel or otherwise. All rights in the
197 | Program not expressly granted under this Agreement are reserved.
198 |
199 | This Agreement is governed by the laws of the State of New York and the
200 | intellectual property laws of the United States of America. No party to this
201 | Agreement will bring a legal action under this Agreement more than one year
202 | after the cause of action arose. Each party waives its rights to a jury trial in
203 | any resulting litigation.
204 |
205 |
206 |
--------------------------------------------------------------------------------
/src/test/clojure/clojure/tools/build/tasks/test_uber.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.test-uber
10 | (:require
11 | [clojure.set :as set]
12 | [clojure.string :as str]
13 | [clojure.test :refer :all]
14 | [clojure.java.io :as jio]
15 | [clojure.tools.build.api :as api]
16 | [clojure.tools.build.tasks.uber :as uber]
17 | [clojure.tools.build.test-util :refer :all]
18 | [clojure.tools.build.util.zip :as zip]
19 | [clojure.tools.build.tasks.test-jar :as test-jar])
20 | (:import
21 | [clojure.lang ExceptionInfo]
22 | [java.io ByteArrayInputStream]))
23 |
24 | (defn- string->stream
25 | [^String s]
26 | (ByteArrayInputStream. (.getBytes s "UTF-8")))
27 |
28 | (deftest string-stream-rt
29 | (are [s] (= s (#'uber/stream->string (string->stream s)))
30 | ""
31 | "abc"))
32 |
33 | (deftest test-uber
34 | (let [uber-path "target/p1-uber.jar"]
35 | (with-test-dir "test-data/p1"
36 | (api/set-project-root! (.getAbsolutePath *test-dir*))
37 | (api/javac {:class-dir "target/classes"
38 | :src-dirs ["java"]})
39 | (api/copy-dir {:target-dir "target/classes"
40 | :src-dirs ["src"]})
41 | (api/uber {:class-dir "target/classes"
42 | :basis (api/create-basis nil)
43 | :uber-file uber-path
44 | :main 'foo.bar})
45 | (let [uf (jio/file (project-path uber-path))]
46 | (is (true? (.exists uf)))
47 | (is (set/subset?
48 | #{"META-INF/MANIFEST.MF" "foo/" "foo/bar.clj" "foo/Demo2.class" "foo/Demo1.class"}
49 | (set (map :name (zip/list-zip (project-path uber-path))))))
50 | (is (str/includes? (test-jar/slurp-manifest uf) "Main-Class: foo.bar"))))))
51 |
52 | (deftest test-custom-manifest
53 | (let [uber-path "target/p1-uber.jar"]
54 | (with-test-dir "test-data/p1"
55 | (api/set-project-root! (.getAbsolutePath *test-dir*))
56 | (api/javac {:class-dir "target/classes"
57 | :src-dirs ["java"]})
58 | (api/copy-dir {:target-dir "target/classes"
59 | :src-dirs ["src"]})
60 | (api/uber {:class-dir "target/classes"
61 | :uber-file uber-path
62 | :main 'foo.bar
63 | :manifest {"Main-Class" "baz" ;; overrides :main
64 | 'Custom-Thing 100}}) ;; stringify kvs
65 | (let [uf (jio/file (project-path uber-path))]
66 | (is (true? (.exists uf)))
67 | (is (= #{"META-INF/MANIFEST.MF" "foo/" "foo/bar.clj" "foo/Demo2.class" "foo/Demo1.class"}
68 | (set (map :name (zip/list-zip (project-path uber-path))))))
69 | (let [manifest-out (test-jar/slurp-manifest uf)]
70 | (is (str/includes? manifest-out "Main-Class: baz"))
71 | (is (str/includes? manifest-out "Custom-Thing: 100")))))))
72 |
73 | (deftest test-conflicts
74 | (with-test-dir "test-data/uber-conflict"
75 | (api/set-project-root! (.getAbsolutePath *test-dir*))
76 |
77 | ;; make "jars"
78 | (doseq [j ["j1" "j2" "j3"]]
79 | (let [classes (format "target/%s/classes" j)
80 | jar-file (format "target/%s.jar" j)]
81 | (api/copy-dir {:target-dir classes :src-dirs [j]})
82 | (api/jar {:class-dir classes :jar-file jar-file})))
83 |
84 | ;; uber including j1, j2, j3
85 | (api/uber {:class-dir "target/classes"
86 | :basis (api/create-basis {:root nil
87 | :project {:deps {'dummy/j1 {:local/root "target/j1.jar"}
88 | 'dummy/j2 {:local/root "target/j2.jar"}
89 | 'dummy/j3 {:local/root "target/j3.jar"}}}})
90 | :uber-file "target/conflict.jar"
91 | :conflict-handlers {"ignore.txt" :ignore
92 | "overwrite.txt" :overwrite
93 | "append.txt" :append}})
94 |
95 | ;; unzip
96 | (api/unzip {:zip-file "target/conflict.jar" :target-dir "target/unzip"})
97 |
98 | ;; non-conflicting files are combined, conflicting files are reconciled
99 | (let [fs (map :name (zip/list-zip (project-path "target/conflict.jar")))]
100 | (is
101 | (set/subset?
102 | #{"META-INF/LICENSE.txt" "META-INF/MANIFEST.MF"
103 | "data_readers.clj"
104 | "my/j1.txt" "my/j2.txt"
105 | "ignore.txt" "overwrite.txt" "append.txt"}
106 | (set fs))))
107 |
108 | ;; data_readers.clj merge
109 | (is (= '{j1a my.foo/j1a-reader, j1b my.bar/j1b-reader,
110 | j2a my.foo/j2a-reader, j2b my.bar/j2b-reader}
111 | (read-string (slurp (project-path "target/unzip/data_readers.clj")))))
112 |
113 | ;; data_readers.cljc merge
114 | (is (= {'j1a (reader-conditional '(:cljs my.cljs.foo/j1a-reader :clj my.clj.foo/j1a-reader) false)
115 | 'j1b (reader-conditional '(:cljs my.cljs.foo/j1b-reader :clj my.clj.foo/j1b-reader) false)
116 | 'j2a (reader-conditional '(:cljs my.cljs.foo/j2a-reader :clj my.clj.foo/j2a-reader) false)
117 | 'j2b (reader-conditional '(:cljs my.cljs.foo/j2b-reader :clj my.clj.foo/j2b-reader) false)}
118 | (read-string {:read-cond :preserve :features #{:clj}}
119 | (slurp (project-path "target/unzip/data_readers.cljc")))))
120 |
121 | ;; ignore files ignore, so first one wins
122 | (is (= (slurp (project-path "j1/ignore.txt"))
123 | (slurp (project-path "target/unzip/ignore.txt"))))
124 |
125 | ;; overwrite files overwrite, so last wins
126 | (is (= (slurp (project-path "j2/overwrite.txt"))
127 | (slurp (project-path "target/unzip/overwrite.txt"))))
128 |
129 | ;; append files append
130 | (is (= (str (slurp (project-path "j1/append.txt")) "\n"
131 | (slurp (project-path "j2/append.txt")))
132 | (slurp (project-path "target/unzip/append.txt"))))
133 |
134 | ;; LICENSE files append but no dupes - include j1 and j2, but not j3 (dupe of j1)
135 | (is (= (str (slurp (project-path "j1/META-INF/LICENSE.txt")) "\n"
136 | (slurp (project-path "j2/META-INF/LICENSE.txt")))
137 | (slurp (project-path "target/unzip/META-INF/LICENSE.txt"))))))
138 |
139 | (deftest test-conflicts-but-files
140 | (with-test-dir "test-data/uber-conflict"
141 | (api/set-project-root! (.getAbsolutePath *test-dir*))
142 |
143 | ;; make dirs
144 | (doseq [j ["j1" "j2" "j3"]]
145 | (let [classes (format "target/%s/classes" j)]
146 | (api/copy-dir {:target-dir classes :src-dirs [j]})
147 | (spit (project-path (format "target/%s/classes/deps.edn" j)) "{:paths [\".\"]}")))
148 |
149 | ;; uber including j1, j2, j3 as local dirs
150 | (api/uber {:class-dir "target/classes"
151 | :basis (api/create-basis {:root nil
152 | :project {:deps {'dummy/j1 {:local/root "target/j1/classes"}
153 | 'dummy/j2 {:local/root "target/j2/classes"}
154 | 'dummy/j3 {:local/root "target/j3/classes"}}}})
155 | :uber-file "target/conflict.jar"
156 | :conflict-handlers {"ignore.txt" :ignore
157 | "overwrite.txt" :overwrite
158 | "append.txt" :append}})
159 |
160 | ;; unzip
161 | (api/unzip {:zip-file "target/conflict.jar" :target-dir "target/unzip"})
162 |
163 | ;; non-conflicting files are combined, conflicting files are reconciled
164 | (let [fs (map :name (zip/list-zip (project-path "target/conflict.jar")))]
165 | (is
166 | (set/subset?
167 | #{"META-INF/LICENSE.txt" "META-INF/MANIFEST.MF"
168 | "data_readers.clj"
169 | "my/j1.txt" "my/j2.txt"
170 | "ignore.txt" "overwrite.txt" "append.txt"}
171 | (set fs))))
172 |
173 | ;; data_readers.clj merge
174 | (is (= '{j1a my.foo/j1a-reader, j1b my.bar/j1b-reader,
175 | j2a my.foo/j2a-reader, j2b my.bar/j2b-reader}
176 | (read-string (slurp (project-path "target/unzip/data_readers.clj")))))
177 |
178 | ;; data_readers.cljc merge
179 | (is (= {'j1a (reader-conditional '(:cljs my.cljs.foo/j1a-reader :clj my.clj.foo/j1a-reader) false)
180 | 'j1b (reader-conditional '(:cljs my.cljs.foo/j1b-reader :clj my.clj.foo/j1b-reader) false)
181 | 'j2a (reader-conditional '(:cljs my.cljs.foo/j2a-reader :clj my.clj.foo/j2a-reader) false)
182 | 'j2b (reader-conditional '(:cljs my.cljs.foo/j2b-reader :clj my.clj.foo/j2b-reader) false)}
183 | (read-string {:read-cond :preserve :features #{:clj}}
184 | (slurp (project-path "target/unzip/data_readers.cljc")))))
185 |
186 | ;; ignore files ignore, so first one wins
187 | (is (= (slurp (project-path "j1/ignore.txt"))
188 | (slurp (project-path "target/unzip/ignore.txt"))))
189 |
190 | ;; overwrite files overwrite, so last wins
191 | (is (= (slurp (project-path "j2/overwrite.txt"))
192 | (slurp (project-path "target/unzip/overwrite.txt"))))
193 |
194 | ;; append files append
195 | (is (= (str (slurp (project-path "j1/append.txt")) "\n"
196 | (slurp (project-path "j2/append.txt")))
197 | (slurp (project-path "target/unzip/append.txt"))))
198 |
199 | ;; LICENSE files append but no dupes - include j1 and j2, but not j3 (dupe of j1)
200 | (is (= (str (slurp (project-path "j1/META-INF/LICENSE.txt")) "\n"
201 | (slurp (project-path "j2/META-INF/LICENSE.txt")))
202 | (slurp (project-path "target/unzip/META-INF/LICENSE.txt"))))))
203 |
204 | (deftest test-case-sensitive-dir-file-collision
205 | (with-test-dir "test-data/case-sensitive-collision"
206 | (api/set-project-root! (.getAbsolutePath *test-dir*))
207 |
208 | ;; make "jars"
209 | (doseq [j ["j1" "j2"]]
210 | (let [classes (format "target/%s/classes" j)
211 | jar-file (format "target/%s.jar" j)]
212 | (api/copy-dir {:target-dir classes :src-dirs [j]})
213 | (api/jar {:class-dir classes :jar-file jar-file})))
214 |
215 | ;; uber including j1, j2 - should fail with conflict
216 | (let [basis (api/create-basis {:root nil
217 | :project {:deps {'dummy/j1 {:local/root "target/j1.jar"}
218 | 'dummy/j2 {:local/root "target/j2.jar"}}}})]
219 | (try
220 | (api/uber {:class-dir "target/classes", :basis basis, :uber-file "target/collision.jar"})
221 | (catch ExceptionInfo ex
222 | (= "Cannot write foo/hi.txt from dummy/j2 as parent dir is a file from another lib. One of them must be excluded."
223 | (ex-message ex))))
224 |
225 | ;; uber including j1, j2 but excluding one of the conflicts
226 | (api/uber {:class-dir "target/classes", :basis basis, :uber-file "target/collision.jar"
227 | :exclude ["FOO"]})
228 |
229 | ;; after exclusion, only foo/hi.txt
230 | (let [fs (map :name (zip/list-zip (project-path "target/collision.jar")))]
231 | (is (= #{"META-INF/MANIFEST.MF" "foo/" "foo/hi.txt"} (set fs)))))))
232 |
233 | ;; TBUILD-35 - it is rare but possible for a jar to contain a / dir entry
234 | (deftest test-bad-zip-with-root-dir
235 | (with-test-dir "test-data/bad-zip"
236 | (api/set-project-root! (.getAbsolutePath *test-dir*))
237 | (let [basis (api/create-basis {:root nil})]
238 | (api/uber {:class-dir "target/classes" :basis basis, :uber-file "target/out.jar"})
239 | (.exists (jio/file (api/resolve-path "target/out.jar"))))))
240 |
241 | (comment
242 | (test-conflicts)
243 | (test-conflicts-but-files)
244 | (test-case-sensitive-dir-file-collision)
245 | (run-tests)
246 | )
247 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/build/tasks/uber.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.build.tasks.uber
10 | (:require
11 | [clojure.java.io :as jio]
12 | [clojure.pprint :as pprint]
13 | [clojure.set :as set]
14 | [clojure.string :as str]
15 | [clojure.tools.build.api :as api]
16 | [clojure.tools.build.util.file :as file]
17 | [clojure.tools.build.util.zip :as zip])
18 | (:import
19 | [java.io File InputStream IOException OutputStream ByteArrayOutputStream]
20 | [java.nio.file Files]
21 | [java.nio.file.attribute FileAttribute FileTime]
22 | [java.util.jar JarEntry JarInputStream JarOutputStream Manifest]))
23 |
24 | (set! *warn-on-reflection* true)
25 |
26 | (def ^:private uber-exclusions
27 | [#"project.clj"
28 | #"META-INF/.*\.(?:SF|RSA|DSA|MF)"
29 | #"module-info\.class"
30 | #"(.*/)?\.DS_Store" ;; Mac metadata
31 | #".+~" ;; emacs backup files
32 | #".#.*" ;; emacs
33 | #"(.*/)?\.keep" ;; convention in dirs to keep that are empty
34 | #".*\.pom"
35 | #"(?i)META-INF/(?:INDEX\.LIST|DEPENDENCIES)(?:\.txt)?"])
36 |
37 | (defn- exclude-from-uber?
38 | [exclude-patterns ^String path]
39 | (loop [[re & res] exclude-patterns]
40 | (if re
41 | (if (re-matches re path)
42 | true
43 | (recur res))
44 | false)))
45 |
46 | (defn- copy-stream!
47 | "Copy input stream to output stream using buffer.
48 | Caller is responsible for passing buffered streams and closing streams."
49 | [^InputStream is ^OutputStream os ^bytes buffer]
50 | (loop []
51 | (let [size (.read is buffer)]
52 | (if (pos? size)
53 | (do
54 | (.write os buffer 0 size)
55 | (recur))
56 | (.close os)))))
57 |
58 | (defn- stream->string
59 | [^InputStream is]
60 | (let [baos (ByteArrayOutputStream. 4096)
61 | _ (copy-stream! is baos (byte-array 4096))]
62 | (.toString baos "UTF-8")))
63 |
64 | (defn conflict-overwrite
65 | [{:keys [path in]}]
66 | {:write {path {:stream in}}})
67 |
68 | (defn- conflict-append
69 | [{:keys [path in]}]
70 | {:write {path {:string (str "\n" (stream->string in)), :append true}}})
71 |
72 | (defn- conflict-append-dedupe
73 | [{:keys [path in ^File existing state] :as _params}]
74 | (let [existing-content (slurp existing)
75 | existing-lower (str/lower-case existing-content)
76 | new-content (stream->string in)
77 | new-content-lower (str/lower-case new-content)
78 | seen (or (get-in state [:append-dedupe path]) #{existing-lower})]
79 | (if (contains? seen new-content-lower)
80 | ;; already seen
81 | {:state (assoc-in state [:append-dedupe path] seen)}
82 | ;; record and append
83 | {:state (assoc-in state [:append-dedupe path] (conj seen new-content))
84 | :write {path {:string (str "\n" new-content), :append true}}})))
85 |
86 | (defn conflict-data-readers
87 | [{:keys [path in ^File existing]}]
88 | (binding [*read-eval* false]
89 | (let [existing-str (slurp existing)
90 | existing-reader-fns (read-string
91 | {:read-cond :preserve :features #{:clj}}
92 | existing-str)
93 | append-reader-fns (read-string
94 | {:read-cond :preserve :features #{:clj}}
95 | (stream->string in))
96 | reader-str (with-out-str (pprint/pprint (merge existing-reader-fns append-reader-fns)))]
97 | {:write {path {:string reader-str}}})))
98 |
99 | (defn- conflict-warn
100 | [{:keys [path lib]}]
101 | (println "Conflicting path at" path "from" lib))
102 |
103 | (defn- conflict-error
104 | [{:keys [path lib]}]
105 | (throw (ex-info (str "Conflicting path at " path " from " lib) {})))
106 |
107 | (defn- handler-emit
108 | [^FileTime last-modified-time buffer out-dir path write-spec]
109 | (let [{:keys [string stream append] :or {append false}} write-spec
110 | out-file (jio/file out-dir path)]
111 | (if string
112 | (spit out-file string :append ^boolean append)
113 | (copy-stream! ^InputStream stream (jio/output-stream out-file :append append) buffer))
114 | (Files/setLastModifiedTime (.toPath out-file) last-modified-time)))
115 |
116 | (defn- handle-conflict
117 | [handlers last-modified-time buffer out-dir {:keys [state path] :as handler-params}]
118 | (let [use-handler (loop [[[re handler] & hs] (dissoc handlers :default)]
119 | (if re
120 | (if (re-matches re path)
121 | handler
122 | (recur hs))
123 | (:default handlers)))]
124 | (if use-handler
125 | (let [{new-state :state, write :write} (use-handler handler-params)]
126 | (when write
127 | (doseq [[path write-spec] write]
128 | (handler-emit last-modified-time buffer out-dir path write-spec)))
129 | (or new-state state))
130 | (throw (ex-info (format "No handler found for conflict at %s" path) {})))))
131 |
132 | (defn- ensure-dir
133 | "Returns true if parent dir exists, false if exists but is not a file,
134 | and throws if it cannot be created."
135 | [^File parent ^File child]
136 | (if (.exists parent)
137 | (.isDirectory parent)
138 | (if (jio/make-parents child)
139 | true
140 | (throw (ex-info (str "Unable to create parent dirs for: " (.toString child)) {})))))
141 |
142 | (defn- explode1
143 | "Given one entry/src file, copy to target pursuant to excludes and handlers.
144 | Returns possibly updated state for further exploding."
145 | [^InputStream is ^String path dir? ^FileTime last-modified-time
146 | ^File out-file lib {:keys [out-dir buffer exclude handlers] :as context} state]
147 | (cond
148 | ;; excluded or directory - do nothing
149 | (or (exclude-from-uber? exclude path) dir?)
150 | state
151 |
152 | ;; conflict, same file from multiple sources - handle
153 | (.exists out-file)
154 | (handle-conflict handlers last-modified-time buffer out-dir
155 | {:lib lib, :path path, :in is, :existing out-file, :state state})
156 |
157 | ;; write new file, parent dir exists for writing
158 | (ensure-dir (.getParentFile out-file) out-file)
159 | (do
160 | (copy-stream! ^InputStream is (jio/output-stream out-file) buffer)
161 | (Files/setLastModifiedTime (.toPath out-file) last-modified-time)
162 | state)
163 |
164 | :parent-dir-is-a-file
165 | (throw (ex-info (format "Cannot write %s from %s as parent dir is a file from another lib. One of them must be excluded."
166 | path lib) {}))))
167 |
168 | (defn- explode
169 | [^File lib-file lib {:keys [out-dir buffer exclude handlers] :as context} state]
170 | (cond
171 | (not (.exists lib-file))
172 | state
173 |
174 | (str/ends-with? (.getPath lib-file) ".jar")
175 | (with-open [jis (JarInputStream. (jio/input-stream lib-file))]
176 | (loop [the-state state]
177 | (if-let [entry (.getNextJarEntry jis)]
178 | (let [path (.getName entry)
179 | ;; should rarely happen (except /), but chop to make relative:
180 | path (if (str/starts-with? path "/") (subs path 1) path)
181 | out-file (jio/file out-dir path)]
182 | (recur
183 | (explode1 jis path (.isDirectory entry) (.getLastModifiedTime ^JarEntry entry)
184 | out-file lib context the-state)))
185 | the-state)))
186 |
187 | (.isDirectory lib-file)
188 | (let [source-dir (.getAbsoluteFile lib-file)
189 | source-path (.toPath source-dir)
190 | fs (file/collect-files source-dir :dirs true)]
191 | (loop [[^File f & restf] fs, the-state state]
192 | (if f
193 | (let [is (when (.isFile f)
194 | (try
195 | (jio/input-stream f)
196 | (catch IOException e
197 | (throw (ex-info (str "Uber task found file but can't read its content in " lib " at path " (.getPath f))
198 | {:path (.getPath f)} e)))))
199 | new-state (try
200 | (let [path (str/replace (.toString (.relativize source-path (.toPath f))) \\ \/)
201 | source-time (FileTime/fromMillis (.lastModified f))
202 | out-file (jio/file out-dir path)]
203 | (explode1 is path (.isDirectory f) source-time out-file lib context the-state))
204 | (finally
205 | (when is (.close ^InputStream is))))]
206 | (recur restf new-state))
207 | the-state)))
208 |
209 | :else
210 | (throw (ex-info (format "Unexpected lib file: %s" (.toString lib-file)) {}))))
211 |
212 | (defn- remove-optional
213 | "Remove optional libs and their transitive dependencies from the lib tree.
214 | Only remove transitive if all dependents are optional."
215 | [libs]
216 | (let [by-opt (group-by (fn [[_lib coord]] (boolean (:optional coord))) libs)
217 | optional (apply conj {} (get by-opt true))]
218 | (if (seq optional)
219 | (loop [req (get by-opt false)
220 | opt optional]
221 | (let [under-opts (group-by (fn [[_lib {:keys [dependents]}]]
222 | (boolean
223 | (and (seq dependents)
224 | (set/subset? (set dependents) (set (keys opt))))))
225 | req)
226 | trans-opt (get under-opts true)]
227 | (if (seq trans-opt)
228 | (recur (get under-opts false) (into opt trans-opt))
229 | (apply conj {} req))))
230 | libs)))
231 |
232 | (defn- built-ins
233 | [kw]
234 | (or
235 | (get {:ignore (fn [_])
236 | :overwrite conflict-overwrite
237 | :append conflict-append
238 | :append-dedupe conflict-append-dedupe
239 | :data-readers conflict-data-readers
240 | :warn conflict-warn
241 | :error conflict-error}
242 | kw)
243 | (throw (ex-info (str "Invalid handler: " kw) {}))))
244 |
245 | (defn- prep-handler
246 | "Convert user handler to fn"
247 | [handler]
248 | (cond
249 | (keyword? handler) (built-ins handler)
250 | (symbol? handler) (deref (requiring-resolve handler))
251 | (ifn? handler) handler
252 | :else (throw (ex-info (str "Invalid handler: " handler) {}))))
253 |
254 | (def ^:private default-handlers
255 | {"^data_readers.clj[c]?$" :data-readers
256 | "^META-INF/services/.*" :append
257 | "(?i)^(META-INF/)?(COPYRIGHT|NOTICE|LICENSE)(\\.(txt|md))?$" :append-dedupe
258 | :default :ignore})
259 |
260 | (defn- prep-handlers
261 | "Transform user handler map into a map of re->fn"
262 | [handlers]
263 | (reduce-kv
264 | (fn [m pattern handler]
265 | (assoc m (if (= pattern :default) :default (re-pattern pattern))
266 | (prep-handler handler)))
267 | {} (merge default-handlers handlers)))
268 |
269 | (defn uber
270 | [{mf-attrs :manifest, :keys [basis class-dir uber-file main exclude conflict-handlers]}]
271 | (let [working-dir (.toFile (Files/createTempDirectory "uber" (into-array FileAttribute [])))
272 | context {:out-dir working-dir
273 | :buffer (byte-array 4096)
274 | :handlers (prep-handlers conflict-handlers)
275 | :exclude (map re-pattern (into uber-exclusions exclude))}]
276 | (try
277 | (let [{:keys [libs]} basis
278 | compile-dir (api/resolve-path class-dir)
279 | manifest (Manifest.)
280 | uber-file (api/resolve-path uber-file)
281 | mf-attr-strs (reduce-kv (fn [m k v] (assoc m (str k) (str v))) nil mf-attrs)]
282 | (reduce
283 | (fn [state [lib coord]]
284 | (reduce
285 | (fn [state path] (explode (jio/file path) lib context state))
286 | state (:paths coord)))
287 | nil ;; initial state, usable by handlers if needed
288 | (assoc (remove-optional libs) nil {:paths [compile-dir]}))
289 | (zip/fill-manifest! manifest
290 | (merge
291 | (cond->
292 | {"Manifest-Version" "1.0"
293 | "Created-By" "org.clojure/tools.build"
294 | "Build-Jdk-Spec" (System/getProperty "java.specification.version")}
295 | main (assoc "Main-Class" (str/replace (str main) \- \_))
296 | (.exists (jio/file working-dir "META-INF" "versions")) (assoc "Multi-Release" "true"))
297 | mf-attr-strs))
298 | (file/ensure-dir (.getParent uber-file))
299 | (with-open [jos (JarOutputStream. (jio/output-stream uber-file) manifest)]
300 | (zip/copy-to-zip jos working-dir)))
301 | (finally
302 | (file/delete working-dir)))))
303 |
--------------------------------------------------------------------------------
/epl-v10.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Eclipse Public License - Version 1.0
8 |
25 |
26 |
27 |
28 |
29 |
30 |
Eclipse Public License - v 1.0
31 |
32 |
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
33 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
34 | DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
35 | AGREEMENT.
36 |
37 |
1. DEFINITIONS
38 |
39 |
"Contribution" means:
40 |
41 |
a) in the case of the initial Contributor, the initial
42 | code and documentation distributed under this Agreement, and
43 |
b) in the case of each subsequent Contributor:
44 |
i) changes to the Program, and
45 |
ii) additions to the Program;
46 |
where such changes and/or additions to the Program
47 | originate from and are distributed by that particular Contributor. A
48 | Contribution 'originates' from a Contributor if it was added to the
49 | Program by such Contributor itself or anyone acting on such
50 | Contributor's behalf. Contributions do not include additions to the
51 | Program which: (i) are separate modules of software distributed in
52 | conjunction with the Program under their own license agreement, and (ii)
53 | are not derivative works of the Program.
54 |
55 |
"Contributor" means any person or entity that distributes
56 | the Program.
57 |
58 |
"Licensed Patents" mean patent claims licensable by a
59 | Contributor which are necessarily infringed by the use or sale of its
60 | Contribution alone or when combined with the Program.
61 |
62 |
"Program" means the Contributions distributed in accordance
63 | with this Agreement.
64 |
65 |
"Recipient" means anyone who receives the Program under
66 | this Agreement, including all Contributors.
67 |
68 |
2. GRANT OF RIGHTS
69 |
70 |
a) Subject to the terms of this Agreement, each
71 | Contributor hereby grants Recipient a non-exclusive, worldwide,
72 | royalty-free copyright license to reproduce, prepare derivative works
73 | of, publicly display, publicly perform, distribute and sublicense the
74 | Contribution of such Contributor, if any, and such derivative works, in
75 | source code and object code form.
76 |
77 |
b) Subject to the terms of this Agreement, each
78 | Contributor hereby grants Recipient a non-exclusive, worldwide,
79 | royalty-free patent license under Licensed Patents to make, use, sell,
80 | offer to sell, import and otherwise transfer the Contribution of such
81 | Contributor, if any, in source code and object code form. This patent
82 | license shall apply to the combination of the Contribution and the
83 | Program if, at the time the Contribution is added by the Contributor,
84 | such addition of the Contribution causes such combination to be covered
85 | by the Licensed Patents. The patent license shall not apply to any other
86 | combinations which include the Contribution. No hardware per se is
87 | licensed hereunder.
88 |
89 |
c) Recipient understands that although each Contributor
90 | grants the licenses to its Contributions set forth herein, no assurances
91 | are provided by any Contributor that the Program does not infringe the
92 | patent or other intellectual property rights of any other entity. Each
93 | Contributor disclaims any liability to Recipient for claims brought by
94 | any other entity based on infringement of intellectual property rights
95 | or otherwise. As a condition to exercising the rights and licenses
96 | granted hereunder, each Recipient hereby assumes sole responsibility to
97 | secure any other intellectual property rights needed, if any. For
98 | example, if a third party patent license is required to allow Recipient
99 | to distribute the Program, it is Recipient's responsibility to acquire
100 | that license before distributing the Program.
101 |
102 |
d) Each Contributor represents that to its knowledge it
103 | has sufficient copyright rights in its Contribution, if any, to grant
104 | the copyright license set forth in this Agreement.
105 |
106 |
3. REQUIREMENTS
107 |
108 |
A Contributor may choose to distribute the Program in object code
109 | form under its own license agreement, provided that:
110 |
111 |
a) it complies with the terms and conditions of this
112 | Agreement; and
113 |
114 |
b) its license agreement:
115 |
116 |
i) effectively disclaims on behalf of all Contributors
117 | all warranties and conditions, express and implied, including warranties
118 | or conditions of title and non-infringement, and implied warranties or
119 | conditions of merchantability and fitness for a particular purpose;
120 |
121 |
ii) effectively excludes on behalf of all Contributors
122 | all liability for damages, including direct, indirect, special,
123 | incidental and consequential damages, such as lost profits;
124 |
125 |
iii) states that any provisions which differ from this
126 | Agreement are offered by that Contributor alone and not by any other
127 | party; and
128 |
129 |
iv) states that source code for the Program is available
130 | from such Contributor, and informs licensees how to obtain it in a
131 | reasonable manner on or through a medium customarily used for software
132 | exchange.
133 |
134 |
When the Program is made available in source code form:
135 |
136 |
a) it must be made available under this Agreement; and
137 |
138 |
b) a copy of this Agreement must be included with each
139 | copy of the Program.
140 |
141 |
Contributors may not remove or alter any copyright notices contained
142 | within the Program.
143 |
144 |
Each Contributor must identify itself as the originator of its
145 | Contribution, if any, in a manner that reasonably allows subsequent
146 | Recipients to identify the originator of the Contribution.
147 |
148 |
4. COMMERCIAL DISTRIBUTION
149 |
150 |
Commercial distributors of software may accept certain
151 | responsibilities with respect to end users, business partners and the
152 | like. While this license is intended to facilitate the commercial use of
153 | the Program, the Contributor who includes the Program in a commercial
154 | product offering should do so in a manner which does not create
155 | potential liability for other Contributors. Therefore, if a Contributor
156 | includes the Program in a commercial product offering, such Contributor
157 | ("Commercial Contributor") hereby agrees to defend and
158 | indemnify every other Contributor ("Indemnified Contributor")
159 | against any losses, damages and costs (collectively "Losses")
160 | arising from claims, lawsuits and other legal actions brought by a third
161 | party against the Indemnified Contributor to the extent caused by the
162 | acts or omissions of such Commercial Contributor in connection with its
163 | distribution of the Program in a commercial product offering. The
164 | obligations in this section do not apply to any claims or Losses
165 | relating to any actual or alleged intellectual property infringement. In
166 | order to qualify, an Indemnified Contributor must: a) promptly notify
167 | the Commercial Contributor in writing of such claim, and b) allow the
168 | Commercial Contributor to control, and cooperate with the Commercial
169 | Contributor in, the defense and any related settlement negotiations. The
170 | Indemnified Contributor may participate in any such claim at its own
171 | expense.
172 |
173 |
For example, a Contributor might include the Program in a commercial
174 | product offering, Product X. That Contributor is then a Commercial
175 | Contributor. If that Commercial Contributor then makes performance
176 | claims, or offers warranties related to Product X, those performance
177 | claims and warranties are such Commercial Contributor's responsibility
178 | alone. Under this section, the Commercial Contributor would have to
179 | defend claims against the other Contributors related to those
180 | performance claims and warranties, and if a court requires any other
181 | Contributor to pay any damages as a result, the Commercial Contributor
182 | must pay those damages.
183 |
184 |
5. NO WARRANTY
185 |
186 |
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
187 | PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
188 | OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
189 | ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
190 | OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
191 | responsible for determining the appropriateness of using and
192 | distributing the Program and assumes all risks associated with its
193 | exercise of rights under this Agreement , including but not limited to
194 | the risks and costs of program errors, compliance with applicable laws,
195 | damage to or loss of data, programs or equipment, and unavailability or
196 | interruption of operations.
197 |
198 |
6. DISCLAIMER OF LIABILITY
199 |
200 |
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
201 | NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
202 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
203 | WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
204 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
205 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
206 | DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
207 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
208 |
209 |
7. GENERAL
210 |
211 |
If any provision of this Agreement is invalid or unenforceable under
212 | applicable law, it shall not affect the validity or enforceability of
213 | the remainder of the terms of this Agreement, and without further action
214 | by the parties hereto, such provision shall be reformed to the minimum
215 | extent necessary to make such provision valid and enforceable.
216 |
217 |
If Recipient institutes patent litigation against any entity
218 | (including a cross-claim or counterclaim in a lawsuit) alleging that the
219 | Program itself (excluding combinations of the Program with other
220 | software or hardware) infringes such Recipient's patent(s), then such
221 | Recipient's rights granted under Section 2(b) shall terminate as of the
222 | date such litigation is filed.
223 |
224 |
All Recipient's rights under this Agreement shall terminate if it
225 | fails to comply with any of the material terms or conditions of this
226 | Agreement and does not cure such failure in a reasonable period of time
227 | after becoming aware of such noncompliance. If all Recipient's rights
228 | under this Agreement terminate, Recipient agrees to cease use and
229 | distribution of the Program as soon as reasonably practicable. However,
230 | Recipient's obligations under this Agreement and any licenses granted by
231 | Recipient relating to the Program shall continue and survive.
232 |
233 |
Everyone is permitted to copy and distribute copies of this
234 | Agreement, but in order to avoid inconsistency the Agreement is
235 | copyrighted and may only be modified in the following manner. The
236 | Agreement Steward reserves the right to publish new versions (including
237 | revisions) of this Agreement from time to time. No one other than the
238 | Agreement Steward has the right to modify this Agreement. The Eclipse
239 | Foundation is the initial Agreement Steward. The Eclipse Foundation may
240 | assign the responsibility to serve as the Agreement Steward to a
241 | suitable separate entity. Each new version of the Agreement will be
242 | given a distinguishing version number. The Program (including
243 | Contributions) may always be distributed subject to the version of the
244 | Agreement under which it was received. In addition, after a new version
245 | of the Agreement is published, Contributor may elect to distribute the
246 | Program (including its Contributions) under the new version. Except as
247 | expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
248 | rights or licenses to the intellectual property of any Contributor under
249 | this Agreement, whether expressly, by implication, estoppel or
250 | otherwise. All rights in the Program not expressly granted under this
251 | Agreement are reserved.
252 |
253 |
This Agreement is governed by the laws of the State of New York and
254 | the intellectual property laws of the United States of America. No party
255 | to this Agreement will bring a legal action under this Agreement more
256 | than one year after the cause of action arose. Each party waives its
257 | rights to a jury trial in any resulting litigation.
Project root path, defaults to current directory.
4 | Use `resolve-path` to resolve relative paths in terms of the *project-root*.
5 | Use `set-project-root!` to override the default for all tasks.
compile-clj
(compile-clj params)
Compile Clojure source to classes in :class-dir.
6 |
7 | Clojure source files are found in :basis :paths by default, or override with :src-dirs.
8 |
9 | Namespaces and order of compilation are one of:
10 | * :ns-compile - compile these namespaces, in this order
11 | * :sort - find all namespaces in source files and use either :topo (default)
12 | or :bfs to order them for compilation
13 |
14 | Options:
15 | :basis - required, basis to use when compiling
16 | :class-dir - required, dir to write classes, will be created if needed
17 | :src-dirs - coll of Clojure source dirs, used to find all Clojure nses to compile
18 | :ns-compile - coll of specific namespace symbols to compile
19 | :sort - :topo (default) or :bfs for breadth-first search
20 | :compile-opts - map of Clojure compiler options:
21 | {:disable-locals-clearing false
22 | :elide-meta [:doc :file :line ...]
23 | :direct-linking false}
24 | :bindings - map of Var to value to be set during compilation, for example:
25 | {#'clojure.core/*assert* false
26 | #'clojure.core/*warn-on-reflection* true}
27 | :filter-nses - coll of symbols representing a namespace prefix to include
28 |
29 | Additional options flow to the forked process doing the compile:
30 | :java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
31 | :java-opts - coll of string jvm opts
32 | :use-cp-file - one of:
33 | :auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
34 | :always - always write classpath to temp file and include
35 | :never - never write classpath to temp file (pass on command line)
36 | :out - one of :inherit :capture :write :append :ignore
37 | :err - one of :inherit :capture :write :append :ignore
38 | :out-file - file path to write if :out is :write or :append
39 | :err-file - file path to write if :err is :write or :append
40 |
41 | Returns nil, or if needed a map with keys:
42 | :out captured-out
43 | :err captured-err
copy-dir
(copy-dir params)
Copy the contents of the src-dirs to the target-dir, optionally do text replacement.
44 | Returns nil.
45 |
46 | Globs are wildcard patterns for specifying sets of files in a directory
47 | tree, as specified in the glob syntax of java.nio.file.FileSystem:
48 | https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)
49 |
50 | Options:
51 | :target-dir - required, dir to write files, will be created if it doesn't exist
52 | :src-dirs - required, coll of dirs to copy from
53 | :include - glob of files to include, default = "**"
54 | :ignores - collection of ignore regex patterns (applied only to file names),
55 | see clojure.tools.build.tasks.copy/default-ignores for defaults
56 | :replace - map of source to replacement string in files
57 | :non-replaced-exts - coll of extensions to skip when replacing (still copied)
58 | default = ["jpg" "jpeg" "png" "gif" "bmp"]
copy-file
(copy-file {:keys [src target], :as params})
Copy one file from source to target, creating target dirs if needed.
59 | Returns nil.
60 |
61 | Options:
62 | :src - required, source path
63 | :target - required, target path
create-basis
(create-basis)(create-basis params)
Create a basis from a set of deps sources and a set of aliases. By default, use
64 | root, user, and project deps and no aliases (essentially the same classpath you
65 | get by default from the Clojure CLI).
66 |
67 | Each dep source value can be :standard, a string path, a deps edn map, or nil.
68 | Sources are merged in the order - :root, :user, :project, :extra.
69 |
70 | Options (note, paths resolved via *project-root*):
71 | :dir - directory root path, defaults to current directory
72 | :root - dep source, default = :standard
73 | :user - dep source, default = nil (for reproducibility, not included)
74 | :project - dep source, default = :standard ("./deps.edn")
75 | :extra - dep source, default = nil
76 | :aliases - coll of aliases of argmaps to apply to subprocesses
77 |
78 | Returns a runtime basis, which is the initial merged deps edn map plus these keys:
79 | :resolve-args - the resolve args passed in, if any
80 | :classpath-args - the classpath args passed in, if any
81 | :libs - lib map, per resolve-deps
82 | :classpath - classpath map per make-classpath-map
83 | :classpath-roots - vector of paths in classpath order
delete
(delete {:keys [path], :as params})
Delete file or directory recursively, if it exists. Returns nil.
84 |
85 | Options:
86 | :path - required, path to file or directory
Shells out to git and returns count of commits on this branch:
87 | git rev-list HEAD --count
88 |
89 | Options:
90 | :dir - dir to invoke this command from, default = current directory
91 | :git-command - git command to use, default = "git"
92 | :path - path to count commits for relative to dir
git-process
(git-process params)
Run git process in the specified dir using git-command with git-args (which should not
93 | start with "git"). git-args may either be a string (split on whitespace) or a vector
94 | of strings. By default, stdout is captured, trimmed, and returned.
95 |
96 | Options:
97 | :dir - dir to invoke this command from, default = current directory
98 | :git-command - git command to use, default = "git"
99 | :git-args - required, coll of git-arg strings forming a command line OR
100 | a string (do not use if args may have embedded spaces)
101 | :capture - :out (default) or :err, else nothing
102 |
103 | Examples:
104 | (api/git-process {:git-args "rev-list HEAD --count"})
105 | (api/git-process {:git-args "branch --show-current"})
106 | (api/git-process {:git-args "rev-parse --short HEAD"})
107 | (api/git-process {:git-args "push", :capture nil})
install
(install params)
Install pom and jar to local Maven repo.
108 | Returns nil.
109 |
110 | Options:
111 | :basis - required, used for :mvn/local-repo
112 | :lib - required, lib symbol
113 | :classifier - classifier string, if needed
114 | :version - required, string version
115 | :jar-file - required, path to jar file
116 | :class-dir - required, used to find the pom file
jar
(jar params)
Create jar file containing contents of class-dir. Use main in the manifest
117 | if provided. Returns nil.
118 |
119 | Options:
120 | :class-dir - required, dir to include in jar
121 | :jar-file - required, jar to write
122 | :main - main class symbol
123 | :manifest - map of manifest attributes, merged last over defaults+:main
java-command
(java-command params)
Create Java command line args. The classpath will be the combination of
124 | :cp followed by the classpath from the basis, both are optional.
125 |
126 | Note that 'java-command' will NOT resolve any relative paths from basis
127 | or cp in terms of *project-root*, you will get a classpath with the same
128 | relative paths. 'process' (if run with this output), will run in the
129 | context of the *project-root* directory.
130 |
131 | Options:
132 | :java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
133 | :cp - coll of string classpath entries, used first (if provided)
134 | :basis - runtime basis used for classpath and jvm opts from aliases, used last (if provided)
135 | :java-opts - coll of string jvm opts
136 | :main - required, main class symbol
137 | :main-args - coll of main class args
138 | :use-cp-file - one of:
139 | :auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
140 | :always - always write classpath to temp file and include
141 | :never - never write classpath to temp file (pass on command line)
142 |
143 | Returns map suitable for passing to 'process' with keys:
144 | :command-args - coll of command arg strings
javac
(javac params)
Compile Java source to classes. Returns nil.
145 |
146 | Options:
147 | :src-dirs - required, coll of Java source dirs
148 | :class-dir - required, dir to write classes, will be created if needed
149 | :basis - classpath basis to use when compiling
150 | :javac-opts - coll of string opts, like ["-source" "8" "-target" "8"]
pom-path
(pom-path params)
Calculate path to pom.xml in jar meta (same path used by write-pom).
151 | Relative path in jar is:
152 | META-INF/maven/<groupId>/<artifactId>/pom.xml
153 |
154 | If :class-dir provided, return path will start with resolved class-dir
155 | (which may be either absolute or relative), otherwise just relative
156 | path in jar.
157 |
158 | Options:
159 | :lib - required, used to form the relative path in jar to pom.xml
160 | :class-dir - optional, if provided will be resolved and form the root of the path
process
(process params)
Exec the command made from command-args, redirect out and err as directed,
161 | and return {:exit exit-code, :out captured-out, :err captured-err}.
162 |
163 | Options:
164 | :command-args - required, coll of string args
165 | :dir - directory to run the command from, default *project-root*
166 | :out - one of :inherit :capture :write :append :ignore
167 | :err - one of :inherit :capture :write :append :ignore
168 | :out-file - file path to write if :out is :write or :append
169 | :err-file - file path to write if :err is :write or :append
170 | :env - map of environment variables to set
171 |
172 | The :out and :err input flags take one of the following options:
173 | :inherit - inherit the stream and write the subprocess io to this process's stream (default)
174 | :capture - capture the stream to a string and return it
175 | :write - write to :out-file or :err-file
176 | :append - append to :out-file or :err-file
177 | :ignore - ignore the stream
resolve-path
(resolve-path path)
If path is absolute or root-path is nil then return path,
178 | otherwise resolve relative to *project-root*.
set-project-root!
(set-project-root! root)
Set *project-root* dir (default is ".")
179 |
uber
(uber params)
Create uberjar file. An uberjar is a self-contained jar file containing
180 | both the project contents AND the contents of all dependencies.
181 |
182 | The project contents are represented by the class-dir. Use other tasks to
183 | put Clojure source, class files, a pom file, or other resources in the
184 | class-dir. In particular, see the copy-dir, write-pom, compile-clj, and
185 | javac tasks.
186 |
187 | The dependencies are pulled from the basis. All transitive deps will be
188 | included. Dependency jars are expanded for inclusion in the uberjar.
189 | Use :exclude to exclude specific paths from the expanded deps. Use
190 | conflict-handlers to handle conflicts that may occur if two dependency
191 | jar files include a file at the same path. See below for more detail.
192 |
193 | If a main class or manifest are provided, those are put in the uberjar
194 | META-INF/MANIFEST.MF file. Providing a main allows the jar to be
195 | invoked with java -jar.
196 |
197 | Returns nil.
198 |
199 | Options:
200 | :uber-file - required, uber jar file to create
201 | :class-dir - required, local class dir to include
202 | :basis - used to pull dep jars
203 | :main - main class symbol
204 | :manifest - map of manifest attributes, merged last over defaults + :main
205 | :exclude - coll of string patterns (regex) to exclude from deps
206 | :conflict-handlers - map of string pattern (regex) to built-in handlers,
207 | symbols to eval, or function instances
208 |
209 | When combining jar files into an uber jar, multiple jars may contain a file
210 | at the same path. The conflict handlers are a map of string regex pattern
211 | to:
212 | a keyword (to use a built-in handler) or
213 | a symbol (to resolve and invoke) or
214 | a function instance
215 | The special key `:default` specifies the default behavior if not matched.
216 |
217 | Conflict handler signature (fn [params]) => effect-map:
218 | params:
219 | :path - String, path in uber jar, matched by regex
220 | :in - InputStream to incoming file (see stream->string if needed)
221 | :existing - File, existing File at path
222 | :lib - symbol, lib source for incoming conflict
223 | :state - map, available for retaining state during uberjar process
224 |
225 | Handler should return effect-map with optional keys:
226 | :state - updated state map
227 | :write - map of string path to map of :string (string) or
228 | :stream (InputStream) to write and optional :append
229 | flag. Omit if no files to write.
230 |
231 | Available built-in conflict handlers:
232 | :ignore - don't do anything (default)
233 | :overwrite - overwrite (replaces prior file)
234 | :append - append the file with a blank line separator
235 | :append-dedupe - append the file but dedupe appended sections
236 | :data-readers - merge data_readers.clj
237 | :warn - print a warning
238 | :error - throw an error
239 |
240 | Default conflict handlers map:
241 | {"^data_readers.clj[c]?$" :data-readers
242 | "^META-INF/services/.*" :append
243 | "(?i)^(META-INF/)?(COPYRIGHT|NOTICE|LICENSE)(\\.(txt|md))?$" :append-dedupe
244 | :default :ignore}
unzip
(unzip params)
Unzip zip file to target-dir. Returns nil.
245 |
246 | Options:
247 | :zip-file - required, zip file to unzip
248 | :target-dir - required, directory to unzip in
with-project-root
macro
(with-project-root path & forms)
Execute forms in a bound project path (string) other than the default (".")
249 |
Writes a file at path, will create parent dirs if needed. Returns nil.
250 | File contents may be specified either with :content (for data, that
251 | will be pr-str'ed) or with :string for the string to write. If
252 | neither is specified, an empty file is created (like touch).
253 |
254 | Options:
255 | :path - required, file path
256 | :content - val to write, will pr-str
257 | :string - string to write
258 | :opts - coll of writer opts like :append and :encoding (per clojure.java.io)
write-pom
(write-pom params)
Write pom.xml and pom.properties files to the class dir under
259 | META-INF/maven/group-id/artifact-id/ (where Maven typically writes
260 | these files), or to target (exactly one of :class-dir and :target must
261 | be provided).
262 |
263 | Optionally use :src-pom to provide a pom template (or a default will
264 | be generated from the provided attributes). The pom deps, dirs, and
265 | repos from the basis will replace those sections of the template. Note
266 | that the :src-pom template is not validated and should contain required
267 | elements such as modelVersion.
268 |
269 | If a repos map is provided it supersedes the repos in the basis.
270 |
271 | Returns nil.
272 |
273 | Options:
274 | :basis - required, used to pull deps, repos
275 | :src-pom - source pom.xml to synchronize from, default = "./pom.xml"
276 | may be :none to ignore any existing pom.xml file
277 | :class-dir - root dir for writing pom files, created if needed
278 | :target - file path to write pom if no :class-dir specified
279 | :lib - required, project lib symbol
280 | :version - required, project version
281 | :scm - map of scm properties to write in pom
282 | keys: :connection, :developerConnection, :tag, :url
283 | See: https://maven.apache.org/pom.html#SCM for details
284 | :src-dirs - coll of src dirs
285 | :resource-dirs - coll of resource dirs
286 | :repos - map of repo name to repo config, replaces repos from deps.edn
287 | :pom-data - vector of hiccup-style extra pom top elements to include when
288 | :src-pom is :none or the source pom.xml does not exist:
289 | [[:licenses
290 | [:license
291 | [:name "Eclipse Public License 1.0"]
292 | [:url "https://opensource.org/license/epl-1-0/";]
293 | [:distribution "repo"]]]
294 | [:organization "Super Corp"]]
295 | The pom-data MUST NOT include:
296 | :modelVersion, :packaging, :groupId, :artifactId, :version, :name,
297 | :deps, :repositories, :build, or :scm
zip
(zip params)
Create zip file containing contents of src dirs. Returns nil.
298 |
299 | Options:
300 | :src-dirs - required, coll of source directories to include in zip
301 | :zip-file - required, zip file to create