-
Notifications
You must be signed in to change notification settings - Fork 60
/
generate.sh
executable file
·201 lines (188 loc) · 6.23 KB
/
generate.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env bash
set -Eeuo pipefail
image="${GITHUB_REPOSITORY##*/}" # "python", "golang", etc
[ -n "${GENERATE_STACKBREW_LIBRARY:-}" ] || [ -x ./generate-stackbrew-library.sh ] # sanity check
tmp="$(mktemp -d)"
trap "$(printf 'rm -rf %q' "$tmp")" EXIT
if ! command -v bashbrew &> /dev/null; then
dir="$(readlink -f "$BASH_SOURCE")"
dir="$(dirname "$dir")"
dir="$(cd "$dir/../.." && pwd -P)"
if [ ! -x "$dir/bin/bashbrew" ]; then
echo >&2 'Building bashbrew ...'
"$dir/bashbrew.sh" --version > /dev/null
"$dir/bin/bashbrew" --version >&2
fi
export PATH="$dir/bin:$PATH"
bashbrew --version > /dev/null
fi
mkdir "$tmp/library"
export BASHBREW_LIBRARY="$tmp/library"
eval "${GENERATE_STACKBREW_LIBRARY:-./generate-stackbrew-library.sh}" > "$BASHBREW_LIBRARY/$image"
# if we don't appear to be able to fetch the listed commits, they might live in a PR branch, so we should force them into the Bashbrew cache directly to allow it to do what it needs
if ! bashbrew from "$image" &> /dev/null; then
bashbrewGit="${BASHBREW_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/bashbrew}/git"
if [ ! -d "$bashbrewGit" ]; then
# if we're here, it's because "bashbrew from" failed so our cache directory might not have been created
bashbrew from https://github.com/docker-library/official-images/raw/HEAD/library/hello-world:latest > /dev/null
fi
git -C "$bashbrewGit" fetch --quiet --update-shallow "$PWD" HEAD > /dev/null
bashbrew from "$image" > /dev/null
fi
tags="$(bashbrew list --build-order --uniq "$image")"
# see https://github.com/docker-library/python/commit/6b513483afccbfe23520b1f788978913e025120a for the ideal of what this would be (minimal YAML in all 30+ repos, shared shell script that outputs fully dynamic steps list), if GitHub Actions were to support a fully dynamic steps list
order=()
declare -A metas=()
for tag in $tags; do
echo >&2 "Processing $tag ..."
bashbrewImage="${tag##*/}" # account for BASHBREW_NAMESPACE being set
meta="$(
bashbrew cat --format '
{{- $e := .TagEntry -}}
{{- $arch := $e.HasArchitecture arch | ternary arch ($e.Architectures | first) -}}
{{- "{" -}}
"name": {{- json ($e.Tags | first) -}},
"tags": {{- json ($.Tags namespace false $e) -}},
"directory": {{- json ($e.ArchDirectory $arch) -}},
"file": {{- json ($e.ArchFile $arch) -}},
"constraints": {{- json $e.Constraints -}},
"froms": {{- json ($.ArchDockerFroms $arch $e) -}}
{{- "}" -}}
' "$bashbrewImage" | jq -c '
{
name: .name,
os: (
if (.constraints | contains(["windowsservercore-ltsc2022"])) or (.constraints | contains(["nanoserver-ltsc2022"])) then
"windows-2022"
elif (.constraints | contains(["windowsservercore-1809"])) or (.constraints | contains(["nanoserver-1809"])) then
"windows-2019"
elif .constraints == [] or .constraints == ["!aufs"] then
"ubuntu-latest"
else
# use an intentionally invalid value so that GitHub chokes and we notice something is wrong
"invalid-or-unknown"
end
),
meta: { entries: [ . ] },
runs: {
build: (
[
"docker build"
]
+ (
.tags
| map(
"--tag " + (. | @sh)
)
)
+ if .file != "Dockerfile" then
[ "--file", ((.directory + "/" + .file) | @sh) ]
else
[]
end
+ [
(.directory | @sh)
]
| join(" ")
),
history: ("docker history " + (.tags[0] | @sh)),
test: ("~/oi/test/run.sh " + (.tags[0] | @sh)),
},
}
'
)"
parent="$(bashbrew parents "$bashbrewImage" | tail -1)" # if there ever exists an image with TWO parents in the same repo, this will break :)
if [ -n "$parent" ]; then
parentBashbrewImage="${parent##*/}" # account for BASHBREW_NAMESPACE being set
parent="$(bashbrew list --uniq "$parentBashbrewImage")" # normalize
parentMeta="${metas["$parent"]}"
parentMeta="$(jq -c --argjson meta "$meta" '
. + {
name: (.name + ", " + $meta.name),
os: (if .os == $meta.os then .os else "invalid-os-chain--" + .os + "+" + $meta.os end),
meta: { entries: (.meta.entries + $meta.meta.entries) },
runs: (
.runs
| to_entries
| map(
.value += "\n" + $meta.runs[.key]
)
| from_entries
),
}
' <<<"$parentMeta")"
metas["$parent"]="$parentMeta"
else
metas["$tag"]="$meta"
order+=( "$tag" )
fi
done
strategy="$(
for tag in "${order[@]}"; do
jq -c '
.meta += {
froms: (
[ .meta.entries[].froms[] ]
- [ .meta.entries[].tags[] ]
| unique
),
dockerfiles: [
.meta.entries[]
| .directory + "/" + .file
],
}
| .runs += {
prepare: ([
(
if .os | startswith("windows-") then
"# enable symlinks on Windows (https://git-scm.com/docs/git-config#Documentation/git-config.txt-coresymlinks)",
"git config --global core.symlinks true",
"# ... make sure they are *real* symlinks (https://github.com/git-for-windows/git/pull/156)",
"export MSYS=winsymlinks:nativestrict",
"# make sure line endings get checked out as-is",
"git config --global core.autocrlf false"
else
empty
end
),
"git clone --depth 1 https://github.com/docker-library/official-images.git -b master ~/oi",
"# create a dummy empty image/layer so we can --filter since= later to get a meaningful image list",
"{ echo FROM " + (
if .os | startswith("windows-") then
"mcr.microsoft.com/windows/servercore:ltsc" + (.os | ltrimstr("windows-"))
else
"busybox:latest"
end
) + "; echo RUN :; } | docker build --no-cache --tag image-list-marker -",
(
if (env.BASHBREW_GENERATE_SKIP_PGP_PROXY) or (.os | startswith("windows-")) then
empty
else
(
"# PGP Happy Eyeballs",
"git clone --depth 1 https://github.com/tianon/pgp-happy-eyeballs.git ~/phe",
"~/phe/hack-my-builds.sh",
"rm -rf ~/phe"
)
end
)
] | join("\n")),
pull: ([ .meta.froms[] | select(. != "scratch") | "docker pull " + @sh ] | join("\n")),
# build
# history
# test
images: "docker image ls --filter since=image-list-marker",
}
' <<<"${metas["$tag"]}"
done | jq -cs '
{
"fail-fast": false,
matrix: { include: . },
}
'
)"
if [ -t 1 ]; then
jq <<<"$strategy"
else
cat <<<"$strategy"
fi