Skip to content

Commit 8a4c8da

Browse files
committed
Refactor / reorganize & fix architecture exclusion
1 parent fcf6cd5 commit 8a4c8da

File tree

7 files changed

+287
-239
lines changed

7 files changed

+287
-239
lines changed

src/docker_clojure/config.clj

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,9 @@
5555
"debian" #{:debian-slim/bookworm-slim :debian/bookworm
5656
:debian-slim/bullseye-slim :debian/bullseye}})
5757

58-
(def default-architectures
58+
(def architectures
5959
#{"amd64" "arm64v8"})
6060

61-
(def distro-architectures
62-
"Map of distro types to architectures it supports if different from
63-
default-architectures."
64-
{:alpine #{"amd64"}})
65-
6661
(def default-distros
6762
"The default distro to use for tags that don't specify one, keyed by jdk-version.
6863
:default is a fallback for jdk versions not o/w specified."
@@ -84,12 +79,13 @@
8479
"1.12.0.1530" "2a113e3a4f1005e05f4d6a6dee24ca317b0115cdd7e6ca6155a76f5ffa5ba35b"}})
8580

8681
(def exclusions ; don't build these for whatever reason(s)
87-
#{; no more jammy builds for JDK 23+
82+
#{;; No more jammy builds for JDK 23+
8883
{:jdk-version #(>= % 23)
8984
:distro :ubuntu/jammy}
90-
;; commented out example
91-
#_{:jdk-version 8
92-
:distro :alpine/alpine}})
85+
;; No upstream ARM alpine images available before JDK 21
86+
{:jdk-version #(< % 21)
87+
:architecture "arm64v8"
88+
:distro :alpine/alpine}})
9389

9490
(def maintainers
9591
["Paul Lam <[email protected]> (@Quantisan)"

src/docker_clojure/core.clj

Lines changed: 29 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,51 @@
11
(ns docker-clojure.core
22
(:require
3+
[clojure.core.async :refer [<!! chan pipeline-blocking to-chan!] :as async]
4+
[clojure.edn :as edn]
35
[clojure.java.io :as io]
4-
[clojure.java.shell :refer [sh with-sh-dir]]
5-
[clojure.math.combinatorics :as combo]
6+
[clojure.java.shell :refer [sh]]
67
[clojure.spec.alpha :as s]
78
[clojure.string :as str]
8-
[clojure.core.async :refer [<!! chan to-chan! pipeline-blocking] :as async]
99
[docker-clojure.config :as cfg]
10+
[docker-clojure.docker :as docker]
1011
[docker-clojure.dockerfile :as df]
11-
[docker-clojure.manifest :as manifest]
12-
[docker-clojure.util :refer [get-or-default default-docker-tag
13-
full-docker-tag]]
1412
[docker-clojure.log :refer [log] :as logger]
15-
[clojure.edn :as edn]))
16-
17-
(defn exclude-variant?
18-
"Returns true if the map `variant` contains every key-value pair in the map
19-
`exclusion`. `variant` may contain additional keys that are not in
20-
`exclusion`. Some values of `exclusion` can also be a predicate of one
21-
argument which is then tested against the respective value from `variant`.
22-
Returns false if any of the keys in `exclusions` are missing from `variant` or
23-
have different values, or the predicate value returned false."
24-
[variant exclusion]
25-
(every? (fn [[k v]]
26-
(if (fn? v)
27-
(v (get variant k))
28-
(= v (get variant k))))
29-
exclusion))
30-
31-
(defn base-image-tag
32-
[base-image jdk-version distro]
33-
(str base-image ":"
34-
(case base-image
35-
"eclipse-temurin" (str jdk-version "-jdk-")
36-
"debian" ""
37-
"-")
38-
(name distro)))
13+
[docker-clojure.manifest :as manifest]
14+
[docker-clojure.util :refer [get-or-default]]
15+
[docker-clojure.variant :as variant]))
3916

4017
(defn exclude?
4118
"Returns true if `variant` matches one of `exclusions` elements (meaning
4219
`(contains-every-key-value? variant exclusion)` returns true)."
4320
[exclusions variant]
44-
(some (partial exclude-variant? variant) exclusions))
21+
(some (partial variant/exclude? variant) exclusions))
4522

4623
(s/def ::variant
4724
(s/keys :req-un [::cfg/jdk-version ::cfg/base-image ::cfg/base-image-tag
4825
::cfg/distro ::cfg/build-tool ::cfg/build-tool-version
4926
::cfg/maintainer ::cfg/docker-tag]
50-
:opt-un [::cfg/build-tool-versions ::cfg/architectures]))
51-
52-
(defn assoc-if
53-
[m pred k v]
54-
(if (pred)
55-
(assoc m k v)
56-
m))
57-
58-
(defn variant-map [[base-image jdk-version distro
59-
[build-tool build-tool-version]]]
60-
(let [variant-arch (get cfg/distro-architectures
61-
(-> distro namespace keyword))
62-
base {:jdk-version jdk-version
63-
:base-image base-image
64-
:base-image-tag (base-image-tag base-image
65-
jdk-version distro)
66-
:distro distro
67-
:build-tool build-tool
68-
:build-tool-version build-tool-version
69-
:maintainer (str/join " & " cfg/maintainers)}]
70-
(-> base
71-
(assoc :docker-tag (default-docker-tag base))
72-
(assoc-if #(nil? (:build-tool-version base)) :build-tool-versions
73-
cfg/build-tools)
74-
(assoc-if #(seq variant-arch) :architectures variant-arch))))
75-
76-
(defn pull-image [image]
77-
(sh "docker" "pull" image))
27+
:opt-un [::cfg/build-tool-versions ::cfg/architecture]))
7828

79-
(defn generate-dockerfile! [installer-hashes variant]
80-
(let [build-dir (df/build-dir variant)
81-
filename "Dockerfile"]
82-
(log "Generating" (str build-dir "/" filename))
83-
(df/write-file build-dir filename installer-hashes variant)
84-
(assoc variant
85-
:build-dir build-dir
86-
:dockerfile filename)))
87-
88-
(defn build-image
89-
[installer-hashes {:keys [docker-tag base-image architectures] :as variant}]
90-
(let [image-tag (str "clojure:" docker-tag)
91-
_ (log "Pulling base image" base-image)
92-
_ (pull-image base-image)
93-
94-
{:keys [dockerfile build-dir]}
95-
(generate-dockerfile! installer-hashes variant)
96-
97-
host-arch (let [jvm-arch (System/getProperty "os.arch")]
98-
(if (= "aarch64" jvm-arch)
99-
"arm64v8"
100-
jvm-arch))
101-
platform-flag (if (contains? (or architectures
102-
cfg/default-architectures)
103-
host-arch)
104-
nil
105-
(str "--platform=linux/" (first architectures)))
106-
107-
build-cmd (remove nil? ["docker" "buildx" "build" "--no-cache"
108-
"-t" image-tag platform-flag "--load"
109-
"-f" dockerfile "."])]
110-
(apply log "Running" build-cmd)
111-
(let [{:keys [out err exit]}
112-
(with-sh-dir build-dir (apply sh build-cmd))]
113-
(if (zero? exit)
114-
(log "Succeeded building" (str "clojure:" docker-tag))
115-
(log "ERROR building" (str "clojure:" docker-tag ":") err out))))
116-
(log)
117-
[::done variant])
118-
119-
(def latest-variant
29+
(def latest-variants
12030
"The latest variant is special because we include all 3 build tools via the
12131
[::all] value on the end."
122-
(list (-> cfg/base-images :default first)
123-
cfg/default-jdk-version
124-
(get-or-default cfg/default-distros cfg/default-jdk-version)
125-
[::all]))
126-
127-
(defn image-variant-combinations
128-
[base-images jdk-versions distros build-tools]
129-
(reduce
130-
(fn [variants jdk-version]
131-
(concat
132-
variants
133-
(let [jdk-base-images (get-or-default base-images jdk-version)]
134-
(loop [[bi & r] jdk-base-images
135-
acc #{}]
136-
(let [vs (combo/cartesian-product #{bi}
137-
#{jdk-version}
138-
(get-or-default distros bi)
139-
build-tools)
140-
acc' (concat acc vs)]
141-
(if (seq r)
142-
(recur r acc')
143-
acc'))))))
144-
#{} jdk-versions))
32+
(for [arch cfg/architectures]
33+
(list (-> cfg/base-images :default first)
34+
cfg/default-jdk-version
35+
(get-or-default cfg/default-distros cfg/default-jdk-version)
36+
[::all]
37+
arch)))
14538

14639
(defn image-variants
147-
[base-images jdk-versions distros build-tools]
40+
[base-images jdk-versions distros build-tools architectures]
14841
(into #{}
14942
(comp
150-
(map variant-map)
43+
(map variant/->map)
15144
(remove #(= ::s/invalid (s/conform ::variant %))))
152-
(conj
153-
(image-variant-combinations base-images jdk-versions distros
154-
build-tools)
155-
latest-variant)))
45+
(concat
46+
(variant/combinations base-images jdk-versions distros build-tools
47+
architectures)
48+
latest-variants)))
15649

15750
(defn rand-delay
15851
"Runs argument f w/ any supplied args after a random delay of 100-1000 ms"
@@ -164,31 +57,31 @@
16457
(defn build-images
16558
[parallelization installer-hashes variants]
16659
(log "Building images" parallelization "at a time")
167-
(let [variants-ch (to-chan! variants)
168-
builds-ch (chan parallelization)]
60+
(let [variants-ch (to-chan! variants)
61+
builds-ch (chan parallelization)]
16962
;; Kick off builds with a random delay so we don't have Docker race
17063
;; conditions (e.g. build container name collisions)
17164
(async/thread (pipeline-blocking parallelization builds-ch
172-
(map (partial rand-delay build-image
65+
(map (partial rand-delay docker/build-image
17366
installer-hashes))
17467
variants-ch))
17568
(while (<!! builds-ch))))
17669

17770
(defn generate-dockerfiles! [installer-hashes variants]
17871
(log "Generated" (count variants) "variants")
17972
(doseq [variant variants]
180-
(generate-dockerfile! installer-hashes variant)))
73+
(df/generate! installer-hashes variant)))
18174

18275
(defn valid-variants []
18376
(remove (partial exclude? cfg/exclusions)
18477
(image-variants cfg/base-images cfg/jdk-versions cfg/distros
185-
cfg/build-tools)))
78+
cfg/build-tools cfg/architectures)))
18679

18780
(defn generate-manifest! [variants args]
18881
(let [git-head (->> ["git" "rev-parse" "HEAD"] (apply sh) :out)
18982
target-file (or (first args) :stdout)
19083
manifest (manifest/generate {:maintainers cfg/maintainers
191-
:architectures cfg/default-architectures
84+
:architectures cfg/architectures
19285
:git-repo cfg/git-repo}
19386
git-head variants)]
19487
(log "Writing manifest of" (count variants) "variants to" target-file "...")
@@ -199,24 +92,6 @@
19992
(when (not= :stdout target-file)
20093
(.close output-writer)))))
20194

202-
(defn sort-variants
203-
[variants]
204-
(sort
205-
(fn [v1 v2]
206-
(cond
207-
(= "latest" (:docker-tag v1)) -1
208-
(= "latest" (:docker-tag v2)) 1
209-
:else (let [c (compare (:jdk-version v1) (:jdk-version v2))]
210-
(if (not= c 0)
211-
c
212-
(let [c (compare (full-docker-tag v1) (full-docker-tag v2))]
213-
(if (not= c 0)
214-
c
215-
(throw
216-
(ex-info "No two variants should have the same full Docker tag"
217-
{:v1 v1, :v2 v2}))))))))
218-
variants))
219-
22095
(defn generate-variants
22196
[args]
22297
; TODO: Maybe replace this with bb/cli
@@ -247,7 +122,7 @@
247122
(case cmd
248123
:clean (df/clean-all)
249124
:dockerfiles (generate-dockerfiles! cfg/installer-hashes variants)
250-
:manifest (-> variants sort-variants (generate-manifest! args))
125+
:manifest (generate-manifest! variants args)
251126
:build-images (build-images parallelization cfg/installer-hashes variants)))
252127
(logger/stop))
253128

0 commit comments

Comments
 (0)