The compose services bind-mount the repo and build as root, so every artifact they leave in src-tauri/target belongs to root on the host. It accumulates: 11,124 such files had built up, enough that cargo clean and scripts/clean.sh failed with EACCES — and a plain cargo build died part-way through, because build scripts compile for the host and land in target/debug even when cross-compiling to Android. That is what blocked the device build in this batch. Restores ownership at the end of each containerised build, reading the intended owner from the checkout so no uid has to be plumbed through from the host. A no-op when not running as root, so the native build scripts call it unconditionally. Running the containers as the host uid is the tidier fix and stays open — it needs the cargo/bun cache volumes moved off /root first, which is why this is not a one-line user: directive. TRACES: | DR-213
54 lines
2.2 KiB
Bash
Executable File
54 lines
2.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Give build artifacts back to the human who owns the working tree.
|
|
#
|
|
# TRACES: | DR-213
|
|
#
|
|
# The containerised builds (docker-compose.yml: desktop-linux-build,
|
|
# windows-cross, android-build, test, dev) bind-mount the repo at /app and run
|
|
# as root, because their caches live at /root/.cargo and /root/.bun. Everything
|
|
# they write into src-tauri/target and dist/ is therefore root-owned *on the
|
|
# host* — and it accumulates: one audit found 11,124 such files, which is enough
|
|
# to make `cargo clean` and scripts/clean.sh fail with EACCES for the developer.
|
|
# Worse, a plain `cargo build` then dies part-way through, because build scripts
|
|
# compile for the host and land in target/debug even during a cross-build.
|
|
#
|
|
# Running the containers as the host uid would be the tidier fix, but it needs
|
|
# the cache volumes relocated off /root first. Until that happens, this restores
|
|
# ownership at the end of each containerised build, which is self-healing and
|
|
# needs no uid plumbing on the host side.
|
|
#
|
|
# Outside a container this is a no-op: it exits immediately unless it is running
|
|
# as root, so the native build scripts can call it unconditionally.
|
|
|
|
set -uo pipefail
|
|
|
|
# Not root (a normal developer build) — nothing to fix, and nothing we may fix.
|
|
[ "$(id -u)" -eq 0 ] || exit 0
|
|
|
|
cd "$(dirname "$0")/.."
|
|
REPO_ROOT="$(pwd)"
|
|
|
|
# Whoever owns the checkout is who the artifacts should belong to. Reading it
|
|
# from the tree means this works for any uid/gid without being told, including
|
|
# CI runners whose uid we do not control.
|
|
OWNER="$(stat -c '%u:%g' "$REPO_ROOT")"
|
|
|
|
# uid 0 owning the tree means it is not a bind mount from a normal host account
|
|
# (a root-owned checkout, or a CI image that clones as root). Nothing to give back.
|
|
if [ "${OWNER%%:*}" = "0" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
echo "🔑 Restoring ownership of build artifacts to ${OWNER}…"
|
|
|
|
for target in src-tauri/target src-tauri/gen dist build node_modules .svelte-kit; do
|
|
[ -e "$REPO_ROOT/$target" ] || continue
|
|
chown -R "$OWNER" "$REPO_ROOT/$target" 2>/dev/null || {
|
|
echo "⚠️ Could not fully chown $target — you may need:"
|
|
echo " sudo chown -R $OWNER $REPO_ROOT/$target"
|
|
}
|
|
done
|
|
|
|
echo "✅ Ownership restored."
|