-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathbuild
More file actions
executable file
·330 lines (294 loc) · 10 KB
/
build
File metadata and controls
executable file
·330 lines (294 loc) · 10 KB
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#!/bin/bash
set -e
cd "$(dirname "$0")"
#
# This script builds the neko base image and all the applications
#
# disable buildx because of https://github.com/docker/buildx/issues/847
# if you want to use buildx, set USE_BUILDX=1
if [ -z "$USE_BUILDX" ]; then
USE_BUILDX=0
fi
# check if docker buildx is available, its not docker-buildx command but rather subcommand of docker
#if [ -z "$USE_BUILDX" ] && [ -x "$(command -v docker)" ]; then
# if docker buildx version >/dev/null 2>&1; then
# USE_BUILDX=1
# fi
#fi
function log() {
echo "$(date +'%Y-%m-%d %H:%M:%S') - [NEKO] - $1" > /dev/stderr
}
function help() {
echo "Usage: $0 [options] [image]"
echo
echo "Options:"
echo " -p, --platform : The platform (default: system architecture)"
echo " -r, --repository : The repository prefix (default: ghcr.io/m1k1o/neko)"
echo " -t, --tag : The image tag, can be specified multiple times, if not specified"
echo " uses 'latest' and if available, current git semver tag (v*.*.*)"
echo " -f, --flavor : The flavor, if not specified, builds without flavor"
echo " -b, --base_image : The base image name (default: <repository>[<flavor>-]base:<tag>)"
echo " -a, --application : The app to build, if not specified, builds the base image"
echo " -y, --yes : Skip confirmation prompts"
echo " --no-cache : Build without docker cache"
echo " --push : Push the image to the registry after building"
echo " -h, --help : Show this help message"
echo
echo "Positional arguments:"
echo " <image> : The image name, if not specified, uses the full image name"
echo " in the format <repository>/<flavor>-<application>:<tag>"
echo " Example: ghcr.io/m1k1o/neko/nvidia-firefox:latest"
echo " You can override any of the above options by specifying them"
echo " after the image name."
echo
echo "Environment variables:"
echo " USE_BUILDX : Set to 1 to use docker buildx instead of docker build"
echo " (default: 0)"
echo " CLIENT_DIST : The client dist file to use, if not specified, builds them"
echo " from the source code."
echo " (options) : Options can be specified as environment variables, for example:"
echo " PLATFORM=linux/arm64 $0 --repository ghcr.io/m1k1o/neko"
}
FULL_IMAGE=""
while [[ "$#" -gt 0 ]]; do
case $1 in
--platform|-p) PLATFORM="$2"; shift ;;
--repository|-r) REPOSITORY="$2"; shift ;;
--tag|-t) TAGS+=("$2"); TAG="$2"; shift ;;
--flavor|-f) FLAVOR="$2"; shift ;;
--base_image|-b) BASE_IMAGE="$2"; shift ;;
--application|-a) APPLICATION="$2"; shift ;;
--yes|-y) YES=1 ;;
--no-cache) NO_CACHE=1 ;;
--push) PUSH=1 ;;
--help|-h) help; exit 0 ;;
-*) log "Unknown parameter passed: $1"; help; exit 1 ;;
*)
if [ -z "$FULL_IMAGE" ]; then
FULL_IMAGE="$1"
# extracts image, flavor, app and tag from the full image name
# example:
# ghcr.io/m1k1o/neko/nvidia-firefox:latest
# will be split into:
# REPOSITORY=ghcr.io/m1k1o/neko
# FLAVOR=nvidia
# APPLICATION=firefox
# TAG=latest
# remove the tag from the image name
if [[ "$FULL_IMAGE" == *":"* ]]; then
# removes everything before the last :
TAG="${FULL_IMAGE##*:}" # will be latest
TAGS+=("$TAG")
# removes everything after the last :
FULL_IMAGE="${FULL_IMAGE%:*}" # will be ghcr.io/m1k1o/neko/nvidia-firefox
fi
# extract the image name and save the rest to REPOSITORY
if [[ "$FULL_IMAGE" == *"/"* ]]; then
# removes everything after the last /
REPOSITORY="${FULL_IMAGE%/*}" # will be ghcr.io/m1k1o/neko
# removes everything before the last /
FULL_IMAGE="${FULL_IMAGE##*/}" # will be nvidia-firefox
fi
# extract the flavor and application name
if [[ "$FULL_IMAGE" == *"-"* ]]; then
# removes everything after the last -
FLAVOR="${FULL_IMAGE%-*}" # will be nvidia
# removes everything before the last -
APPLICATION="${FULL_IMAGE#*-}" # will be firefox
else
# no flavor specified so use the full image name as application name
APPLICATION="$FULL_IMAGE" # will be firefox
fi
# if application name is base, set it to empty
if [ "$APPLICATION" == "base" ]; then
APPLICATION=""
fi
else
log "Unknown positional argument: $1"
help
exit 1
fi
;;
esac
shift
done
function prompt() {
if [ ! -z "$YES" ]; then
return 0
fi
local OK=""
while [ -z "$OK" ]; do
read -p "$1 (yes/no) " REPLY
case "$REPLY" in
yes|YES|y|Y)
OK=1
;;
no|NO|n|N)
log "Aborting build."
exit 1
;;
*)
log "Please answer 'yes' or 'no'."
;;
esac
done
}
function build_image() {
# first argument is the image name, rest are the build args
local APPLICATION_IMAGE="$1"
shift
# get list of tags in full format: <image>:<tag>
local IMAGE_NO_TAG="${APPLICATION_IMAGE%:*}"
local FULL_TAGS=()
for T in "${TAGS[@]}"; do
FULL_TAGS+=("$IMAGE_NO_TAG:$T")
done
if [ -z "$USE_BUILDX" ] || [ "$USE_BUILDX" != "1" ]; then
# if buildx is not available, use docker build
docker build \
--platform $PLATFORM \
$NO_CACHE \
-t $APPLICATION_IMAGE \
$@
# tag and push the image to the registry
for T in $FULL_TAGS; do
# do not tag if the tag is the same as the image tag
if [ "$T" != "$APPLICATION_IMAGE" ]; then
log "Tagging $APPLICATION_IMAGE as $T"
docker tag "$APPLICATION_IMAGE" "$T"
fi
# if push is enabled, push the image to the registry
if [ ! -z "$PUSH" ]; then
log "Pushing $T to registry"
docker push "$T"
fi
done
else
# create cmd for buildx, repeat --tag for each tag
local CMD=""
for T in $FULL_TAGS; do
CMD+="--tag $T "
done
# if push is enabled, add --push
if [ ! -z "$PUSH" ]; then
CMD+="--push "
fi
# if no cache is enabled, add --no-cache
if [ ! -z "$NO_CACHE" ]; then
CMD+="--no-cache "
fi
# buildx build command
docker buildx build \
--platform $PLATFORM \
--load --pull $CMD \
$@
fi
}
# --------------------------------------------------------------------
if [ -z "$USE_BUILDX" ] || [ "$USE_BUILDX" != "1" ]; then
log "Using docker build"
else
log "Using docker buildx"
fi
if [ -z "$PLATFORM" ]; then
# use system architecture if not specified
UNAME="$(uname -m)"
if [ "$UNAME" == "x86_64" ]; then
PLATFORM="linux/amd64"
elif [ "$UNAME" == "aarch64" ] || [ "$UNAME" == "arm64" ]; then
PLATFORM="linux/arm64"
elif [ "$UNAME" == "armv7l" ]; then
PLATFORM="linux/arm/v7"
else
log "Unknown architecture: $UNAME"
exit 1
fi
fi
log "Using platform: $PLATFORM"
if [ -z "$REPOSITORY" ]; then
REPOSITORY="ghcr.io/m1k1o/neko"
fi
log "Using repository: $REPOSITORY"
if [ -z "$TAG" ]; then
# if git is available, use the latest tag from git
if [ -d ".git" ] && [ -x "$(command -v git)" ]; then
# get the latest version tag from git (v*.*.*)
GIT_VER=$(git describe --tags --exact-match --match "v*.*.*" 2>/dev/null || true)
if [ ! -z "$GIT_VER" ]; then
# split to major, minor and patch
IFS='.' read -r MAJOR MINOR PATCH <<< "${GIT_VER#v}"
# append MAJOR.MINOR.PATCH, MAJOR.MINOR and MAJOR to the tags
TAGS=("$MAJOR.$MINOR.$PATCH" "$MAJOR.$MINOR" "$MAJOR")
#else
# # if no version tag is found, use the latest commit hash
# GIT_VER=$(git rev-parse HEAD
# TAGS=("sha-$GIT_VER")
fi
fi
TAG="latest"
TAGS=("$TAG" "${TAGS[@]}")
fi
for T in "${TAGS[@]}"; do
log "Using tag: $T"
done
if [ -z "$FLAVOR" ]; then
log "No flavor specified, building without flavor"
else
log "Using flavor: $FLAVOR"
fi
if [ -z "$BASE_IMAGE" ]; then
if [ -z "$FLAVOR" ]; then
BASE_IMAGE="$REPOSITORY/base:$TAG"
else
BASE_IMAGE="$REPOSITORY/$FLAVOR-base:$TAG"
fi
fi
if [ ! -z "$NO_CACHE" ] && [ "$NO_CACHE" != "0" ]; then
NO_CACHE="--no-cache"
log "Building without cache"
else
NO_CACHE=""
fi
# --------------------------------------------------------------------
if [ ! -z "$APPLICATION" ]; then
log "Building application: $APPLICATION"
log "Using base image: $BASE_IMAGE"
# check if application directory exists
APPLICATION_DIR="apps/$APPLICATION"
if [ ! -d "$APPLICATION_DIR" ]; then
log "Application directory $APPLICATION_DIR does not exist."
exit 1
fi
# flavor is specified, append it to the image name and Dockerfile
APPLICATION_IMAGE="$REPOSITORY/$APPLICATION:$TAG"
APPLICATION_DOCKERFILE="apps/$APPLICATION/Dockerfile"
if [ ! -z "$FLAVOR" ]; then
APPLICATION_IMAGE="$REPOSITORY/$FLAVOR-$APPLICATION"
# if application flavor is specified and Dockerfile exists, use it
if [ -f "$APPLICATION_DIR/Dockerfile.$FLAVOR" ]; then
APPLICATION_DOCKERFILE="$APPLICATION_DIR/Dockerfile.$FLAVOR"
fi
fi
prompt "Are you sure you want to build $APPLICATION_IMAGE from $APPLICATION_DOCKERFILE?"
log "Building $APPLICATION_IMAGE image from $APPLICATION_DOCKERFILE"
build_image $APPLICATION_IMAGE \
--build-arg="BASE_IMAGE=$BASE_IMAGE" \
-f $APPLICATION_DOCKERFILE \
$APPLICATION_DIR
exit 0
fi
# --------------------------------------------------------------------
prompt "Are you sure you want to build $BASE_IMAGE?"
RUNTIME_DOCKERFILE="Dockerfile"
if [ ! -z "$FLAVOR" ] && [ -f "runtime/Dockerfile.$FLAVOR" ]; then
RUNTIME_DOCKERFILE="Dockerfile.$FLAVOR"
fi
log "Building base image: $BASE_IMAGE"
docker run --rm -i \
-v "$(pwd)":/src \
-e "RUNTIME_DOCKERFILE=$RUNTIME_DOCKERFILE" \
--workdir /src \
--entrypoint go \
golang:1.24-bullseye \
run utils/docker/main.go \
-i Dockerfile.tmpl -client "$CLIENT_DIST" | build_image $BASE_IMAGE -f - .