-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsbox-build
More file actions
executable file
·395 lines (329 loc) · 9.86 KB
/
sbox-build
File metadata and controls
executable file
·395 lines (329 loc) · 9.86 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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#!/usr/bin/env bash
set -euo pipefail
LOCAL_IMAGE="sbox-win-docker"
REMOTE_IMAGE="ghcr.io/vincetheprogrammer/sbox-win-docker:main"
REPO_URL="https://github.com/vinceTheProgrammer/sbox-win-docker"
INSTALL_DOCS_URL="https://docs.docker.com/engine/install/"
DEFAULT_SRC_DIR="$HOME/.local/share/sbox-win-docker"
NO_PROMPT=0
FORCE_PULL=0
FORCE_REBUILD=0
DO_UPDATE=0
SRC_DIR="$DEFAULT_SRC_DIR"
DROP_SHELL=0
REPO_ROOT_NAME_OVERRIDE=""
usage() {
cat <<EOF
Usage: sbox-build [options]
Wrapper Options:
--pull Force pull the prebuilt image (even if local image exists)
--rebuild Force rebuild the image locally (uses local repo clone)
--update When rebuilding, git pull before building
--src-dir <dir> Override local repo directory (default: $DEFAULT_SRC_DIR)
--repo-root-name <n> Override detected repo root name (bypasses 'sbox-public' check)
--no-prompt Never prompt; fail if user interaction would be required
--shell Drop into an interactive bash shell inside the container
-h, --help Show this help message
Build Options:
--enable-codegen-patch Make future builds faster. Patches CodeGen.Targets before builds. Creates .sboxbuild_codegen_patch (experimental)
--enable-hash-cache Make change based building not rely on git commits. Creates .sboxbuild_cache (recommended)
--full Force full build
--no-auto-full Disable auto full-build detection for fresh clones
--test Run tests after build
--format Format the project
Examples:
sbox-build
sbox-build --pull
sbox-build --rebuild
sbox-build --enable-codegen-patch --enable-hash-cache
sbox-build --full --test --format
EOF
}
DOCKER_ARGS=()
# -----------------------------
# Parse args
# -----------------------------
while [[ $# -gt 0 ]]; do
case "$1" in
--pull)
FORCE_PULL=1
shift
;;
--rebuild)
FORCE_REBUILD=1
shift
;;
--update)
DO_UPDATE=1
shift
;;
--src-dir)
shift
if [[ $# -eq 0 ]]; then
echo "ERROR: --src-dir requires a path"
exit 1
fi
SRC_DIR="${1/#\~/$HOME}"
shift
;;
--repo-root-name=*)
REPO_ROOT_NAME_OVERRIDE="${1#--repo-root-name=}"
shift
;;
--repo-root-name)
shift
if [[ $# -eq 0 ]]; then
echo "ERROR: --repo-root-name requires a value"
exit 1
fi
REPO_ROOT_NAME_OVERRIDE="$1"
shift
;;
--no-prompt)
NO_PROMPT=1
shift
;;
--shell)
DROP_SHELL=1
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
DOCKER_ARGS+=("$@")
break
;;
*)
DOCKER_ARGS+=("$1")
shift
;;
esac
done
if [[ "$FORCE_PULL" -eq 1 && "$FORCE_REBUILD" -eq 1 ]]; then
echo "ERROR: Cannot use --pull and --rebuild at the same time."
exit 1
fi
# -----------------------------
# Prompt helpers
# -----------------------------
prompt_yes_no() {
local prompt="$1"
local default="${2:-Y}"
if [[ "$NO_PROMPT" -eq 1 ]]; then
echo "ERROR: --no-prompt set, but script needs input: $prompt"
exit 1
fi
local answer=""
read -rp "$prompt" answer
answer="${answer:-$default}"
if [[ "$answer" == "y" || "$answer" == "Y" ]]; then
return 0
fi
return 1
}
choose_src_dir_prompt() {
if [[ "$NO_PROMPT" -eq 1 ]]; then
return 0
fi
read -e -p "Repo location: " -i "$DEFAULT_SRC_DIR" SRC_DIR
SRC_DIR="${SRC_DIR/#\~/$HOME}"
}
# -----------------------------
# Docker sanity checks / setup
# -----------------------------
if ! command -v docker >/dev/null 2>&1; then
echo "ERROR: Docker is not installed."
echo "Install Docker here:"
echo "$INSTALL_DOCS_URL"
exit 1
fi
# Ensure docker group exists
if ! getent group docker >/dev/null 2>&1; then
echo "Docker group does not exist."
if ! prompt_yes_no "Create the docker group now? (Y/n): " "Y"; then
echo "ERROR: Docker group is required to continue."
exit 1
fi
sudo groupadd docker
fi
# Ensure user is in docker group
if ! id -nG "$USER" | tr ' ' '\n' | grep -qx docker; then
echo "User '$USER' is not in the docker group."
if ! prompt_yes_no "Add '$USER' to the docker group now? (Y/n): " "Y"; then
echo "ERROR: You must be in the docker group to continue."
exit 1
fi
sudo usermod -aG docker "$USER"
echo
echo "SUCCESS: Added '$USER' to docker group."
echo "You must log out and log back in (or reboot) for this to take effect."
echo "Then re-run: sbox-build"
exit 0
fi
# Now that permissions should be correct, check if docker daemon is running
if ! docker info >/dev/null 2>&1; then
echo "Docker is installed, but the Docker daemon doesn't seem to be running."
if ! prompt_yes_no "Start Docker now? (Y/n): " "Y"; then
echo "ERROR: Docker must be running to continue."
exit 1
fi
if command -v systemctl >/dev/null 2>&1; then
sudo systemctl start docker
elif command -v service >/dev/null 2>&1; then
sudo service docker start
else
echo "ERROR: Couldn't detect systemctl or service manager to start Docker."
echo "Please start Docker manually, then re-run this script."
exit 1
fi
docker info >/dev/null 2>&1 || {
echo "ERROR: Docker still isn't running after attempting to start it."
exit 1
}
fi
# -----------------------------
# Image handling
# -----------------------------
pull_image() {
echo "Pulling: $REMOTE_IMAGE"
docker pull "$REMOTE_IMAGE"
echo "Tagging as: $LOCAL_IMAGE"
docker tag "$REMOTE_IMAGE" "$LOCAL_IMAGE"
}
is_valid_sbox_win_docker_repo() {
if [[ ! -d "$SRC_DIR/.git" ]]; then
return 1
fi
# Must contain expected project files
if [[ ! -f "$SRC_DIR/Dockerfile" || ! -f "$SRC_DIR/sbox-build" ]]; then
return 1
fi
# Must have correct origin remote
local origin_url=""
origin_url="$(git -C "$SRC_DIR" remote get-url origin 2>/dev/null || true)"
if [[ "$origin_url" != *"vinceTheProgrammer/sbox-win-docker"* ]]; then
return 1
fi
return 0
}
ensure_repo_exists() {
if [[ -d "$SRC_DIR" ]]; then
if is_valid_sbox_win_docker_repo; then
return 0
fi
echo "ERROR: '$SRC_DIR' exists but does not appear to be the sbox-win-docker repo."
echo "Refusing to use it (prevents accidentally building unrelated Dockerfiles)."
echo
echo "Expected:"
echo " - Dockerfile"
echo " - sbox-build"
echo " - origin remote containing: vinceTheProgrammer/sbox-win-docker"
echo
echo "Fix options:"
echo " - choose another directory with --src-dir"
echo " - delete '$SRC_DIR' and re-run"
exit 1
fi
echo "Local build repo not found at: $SRC_DIR"
if [[ "$NO_PROMPT" -eq 1 ]]; then
echo "ERROR: --no-prompt set, cannot clone automatically."
echo "Clone manually with:"
echo " git clone $REPO_URL $SRC_DIR"
exit 1
fi
if ! prompt_yes_no "Clone sbox-win-docker repo into '$SRC_DIR'? (Y/n): " "Y"; then
echo "ERROR: Cannot rebuild without a local repo."
exit 1
fi
mkdir -p "$(dirname "$SRC_DIR")"
git clone "$REPO_URL" "$SRC_DIR"
}
build_image() {
if ! command -v git >/dev/null 2>&1; then
echo "ERROR: git is required to build locally but is not installed."
exit 1
fi
ensure_repo_exists
(
cd "$SRC_DIR"
if [[ "$DO_UPDATE" -eq 1 ]]; then
echo "Updating repo (git pull)..."
git pull
fi
echo "Building docker image '$LOCAL_IMAGE' from: $SRC_DIR"
docker build -t "$LOCAL_IMAGE" .
)
}
IMAGE_EXISTS=0
if docker image inspect "$LOCAL_IMAGE" >/dev/null 2>&1; then
IMAGE_EXISTS=1
fi
# If rebuilding and user didn't specify --src-dir explicitly, allow changing location
if [[ "$FORCE_REBUILD" -eq 1 && "$SRC_DIR" == "$DEFAULT_SRC_DIR" ]]; then
choose_src_dir_prompt
fi
if [[ "$FORCE_PULL" -eq 1 ]]; then
pull_image
elif [[ "$FORCE_REBUILD" -eq 1 ]]; then
build_image
elif [[ "$IMAGE_EXISTS" -eq 0 ]]; then
echo "Docker image '$LOCAL_IMAGE' is not present."
echo
echo "Recommended: Pull the prebuilt image (fastest)."
echo "Alternative: Build locally (for dev / customization)."
echo
if prompt_yes_no "Pull prebuilt image from Docker Hub? (Y/n): " "Y"; then
pull_image
else
choose_src_dir_prompt
build_image
fi
fi
# ----------------------------------------
# Strict check: must be inside sbox-public (or override)
# ----------------------------------------
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
if [[ -z "$REPO_ROOT" ]]; then
echo "ERROR: You must run this script from inside a git repository."
echo "Current dir: $(pwd)"
exit 1
fi
# Use override name if provided, otherwise use actual basename
if [[ -n "$REPO_ROOT_NAME_OVERRIDE" ]]; then
REPO_ROOT_NAME="$REPO_ROOT_NAME_OVERRIDE"
else
REPO_ROOT_NAME="$(basename "$REPO_ROOT")"
fi
# Only validate against 'sbox-public' if no override was provided
if [[ -z "$REPO_ROOT_NAME_OVERRIDE" && "$REPO_ROOT_NAME" != "sbox-public" ]]; then
echo "ERROR: Refusing to run: git repo top-level folder is not named 'sbox-public'."
echo "Found repo root: $REPO_ROOT (detected name: $REPO_ROOT_NAME)"
echo "Current dir: $(pwd)"
exit 1
fi
if [[ "$PWD" != "$REPO_ROOT"* ]]; then
echo "ERROR: Current directory is not inside the detected repo root."
exit 1
fi
echo "Starting s&box build in repo: $REPO_ROOT (name override: ${REPO_ROOT_NAME_OVERRIDE:-none})"
if [[ "$DROP_SHELL" -eq 1 ]]; then
echo "Launching interactive bash shell inside container..."
docker run --rm -it \
-v "$PWD:/root/sbox:z" \
-v "$HOME/.cache/sbox-nuget":/root/.wine64/drive_c/users/root/.nuget:z \
-e HOST_UID="$(id -u)" \
-e HOST_GID="$(id -g)" \
--entrypoint bash \
"$LOCAL_IMAGE"
else
docker run --rm -it \
-v "$PWD:/root/sbox:z" \
-v "$HOME/.cache/sbox-nuget":/root/.wine64/drive_c/users/root/.nuget:z \
-e HOST_UID="$(id -u)" \
-e HOST_GID="$(id -g)" \
-e NO_PROMPT="$NO_PROMPT" \
"$LOCAL_IMAGE" "${DOCKER_ARGS[@]}"
fi