fix(install): find uv for the .venv owner (root shells and sudo lack ~/.local/bin)
CI / Format & lint (push) Successful in 22s
CI / Test suite (push) Successful in 58s

Run as root, SUDO_USER is unset and uv is not on root's PATH, so the training environment was not synced. Now the sync runs as the owner of .venv, with uv from PATH, that user's ~/.local/bin or ~/.cargo/bin, /usr/local/bin, or UV=/path/to/uv.
This commit is contained in:
grabowski committed 2026-10-18 17:55:33 +07:00
1 parent 24998b033c
commit 7f29b1831e
1 file changed
+28 -10
+28 -10
View File
@@ -20,9 +20,11 @@
# built beforehand as a normal user:
# cargo build --release --locked --manifest-path rust/Cargo.toml
# (Rust >= 1.88 from rustup, plus pkg-config and libssl-dev)
# 4. the Python training environment (.venv, `uv sync --frozen`): in place
# as the user running sudo (who pulled and built), otherwise as root;
# SKIP_UV=1 skips it
# 4. the Python training environment (.venv, `uv sync --frozen`), as the
# owner of .venv (in place; else the user running sudo) or as root for a
# copy. uv is looked up on PATH and in that user's ~/.local/bin and
# ~/.cargo/bin (sudo and root shells often lack them); UV=/path/to/uv
# overrides, SKIP_UV=1 skips the step
# 5. .env: created from .env.example on a fresh install (edit, then re-run);
# WEB_LISTEN and FORECAST_IN_COLLECTOR default to the production values
# when absent
@@ -104,16 +106,32 @@ log "Installing $BIN -> ${APP_DIR}/bin/ping-collector ($("$BIN" --version))"
install -D -m 0755 -o root -g root "$BIN" "${APP_DIR}/bin/ping-collector"
# 4. Python training environment ------------------------------------------------
find_uv() { # user -> path of a uv binary that user can run
local home c
home="$(getent passwd "$1" | cut -d: -f6)"
for c in "${UV:-}" "$(command -v uv 2>/dev/null || true)" "${home}/.local/bin/uv" \
"${home}/.cargo/bin/uv" /root/.local/bin/uv /usr/local/bin/uv /usr/bin/uv; do
[ -n "$c" ] && [ -x "$c" ] && runuser -u "$1" -- test -x "$c" && {
echo "$c"
return 0
}
done
return 1
}
if [ "${SKIP_UV:-0}" != 1 ]; then
uv_user=root # copy mode: handed to the service user below
[ "$in_place" = 1 ] && uv_user="${SUDO_USER:-root}"
log "Syncing the Python training environment (${APP_DIR}/.venv) as $uv_user"
if [ "$uv_user" = root ]; then
(cd "$APP_DIR" && uv sync --python 3.11 --frozen) ||
warn "uv sync failed: the monthly retrain needs ${APP_DIR}/.venv (uv sync --python 3.11 --frozen)"
if [ "$in_place" = 1 ]; then
uv_user="${SUDO_USER:-root}"
[ -d "${APP_DIR}/.venv" ] && uv_user="$(stat -c %U "${APP_DIR}/.venv")"
fi
if uv_bin="$(find_uv "$uv_user")"; then
log "Syncing the Python training environment (${APP_DIR}/.venv) as $uv_user with $uv_bin"
(cd "$APP_DIR" && runuser -u "$uv_user" -- env HOME="$(getent passwd "$uv_user" | cut -d: -f6)" \
"$uv_bin" sync --python 3.11 --frozen) ||
warn "uv sync failed: the monthly retrain needs ${APP_DIR}/.venv (uv sync --python 3.11 --frozen as $uv_user)"
else
runuser -u "$uv_user" -- bash -lc "cd '$APP_DIR' && uv sync --python 3.11 --frozen" ||
warn "uv sync as $uv_user failed: run 'uv sync --python 3.11 --frozen' in $APP_DIR as the owner of .venv"
warn "uv not found for $uv_user (pass UV=/path/to/uv): ${APP_DIR}/.venv not synced"
fi
fi