diff options
Diffstat (limited to 'producer.sh')
| -rwxr-xr-x | producer.sh | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/producer.sh b/producer.sh index cab10dd..893cf87 100755 --- a/producer.sh +++ b/producer.sh @@ -62,6 +62,51 @@ USAGE log() { printf '[producer] %s\n' "$*" >&2; } fail() { printf '[producer] Error: %s\n' "$*" >&2; exit 1; } +# uv writes the base interpreter's absolute path into every venv it creates +# (the 'home' line in pyvenv.cfg and the bin/python* links). This directory +# is shared between environments that mount it at different paths (a +# container sees /workspace, the host does not), so re-point all of them to +# the current path on every launch. This is a tiny local rewrite, never a +# rebuild, and it self-heals in whichever environment launched last. +repoint_runtime() { + local cfg venv home tail tmp line link target + for cfg in "$RUNTIME"/*/pyvenv.cfg; do + [[ -f "$cfg" ]] || continue + venv="$(dirname -- "$cfg")" + home="$(sed -n 's/^home = //p' "$cfg" | head -1)" + # Only managed Pythons inside this runtime can be re-pointed; the + # tail after '/lib/runtime/' is the stable, path-independent part. + if [[ "$home" == */lib/runtime/uv/python/* \ + && "$home" != "$RUNTIME"/* ]]; then + tail="${home#*/lib/runtime/}" + if [[ -d "$RUNTIME/$tail" ]]; then + tmp="$cfg.tmp.$$" + { while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" == "home = "* ]]; then + printf 'home = %s\n' "$RUNTIME/$tail" + else + printf '%s\n' "$line" + fi + done < "$cfg"; } > "$tmp" && mv -f -- "$tmp" "$cfg" + fi + fi + for link in "$venv"/bin/python "$venv"/bin/python3 "$venv"/bin/python3.*; do + [[ -L "$link" ]] || continue + target="$(readlink -- "$link")" + case "$target" in */lib/runtime/uv/python/*) + # Map stale mounts of this same directory onto the current + # path, then make the link relative. Skip if the target is + # missing (a broken install is the bootstrap's problem). + tail="${target#*/lib/runtime/}" + if [[ -e "$RUNTIME/$tail" ]]; then + ln -sfn -- "$(realpath -m --relative-to="$venv/bin" -- "$RUNTIME/$tail")" "$link" + fi + ;; + esac + done + done +} + # Print the PIDs of processes holding an open descriptor for the given file # (a leading space each, e.g. " 1234 5678"). A plain /proc scan avoids a # dependency on fuser or lsof, which may not be installed. Only processes @@ -183,6 +228,7 @@ bootstrap() { flock 9 fi if [[ "$REBUILD" -eq 0 ]] && marker_current; then + repoint_runtime exec 9>&- # Runtime lock (fd 8): held shared for the application's lifetime so # a later --rebuild cannot delete files this process runs from. @@ -243,18 +289,6 @@ bootstrap() { # The AI worker keeps its own pinned Python 3.11 (glibc only). "$UV" venv --python 3.13 --managed-python --relocatable --allow-existing "$APP" \ || fail "Creating the managed Python 3.13 environment failed; check network access and free space." - # uv creates the interpreter links with absolute targets. Make them - # relative so one runtime serves every environment that mounts this - # directory at a different path (host and containers included). - local link target - for link in "$APP"/bin/python "$APP"/bin/python3 "$APP"/bin/python3.*; do - [[ -L "$link" ]] || continue - target="$(readlink -- "$link")" - case "$target" in "$RUNTIME"/*) - ln -sfn -- "$(realpath -m --relative-to="$APP/bin" -- "$target")" "$link" - ;; - esac - done # The bundled FFmpeg wheel is preferred; where it does not exist (for # example musl systems), fall back to a system FFmpeg at runtime. local bundled="$PROJECT[bundled-ffmpeg]" core="$PROJECT" @@ -281,6 +315,7 @@ bootstrap() { fi printf '%s v%s\n' "$RUNTIME" "$RUNTIME_VERSION" > "$READY.tmp" mv -f -- "$READY.tmp" "$READY" + repoint_runtime # Downgrade to the shared runtime lock for the application's lifetime. flock -s 8 exec 9>&- |
