@@ -163,7 +163,20 @@ web_container_id() {
163163 docker compose ps -q web 2> /dev/null | head -n 1
164164}
165165
166+ compose_backend_is_podman () {
167+ if command -v podman-compose > /dev/null 2>&1 ; then
168+ return 0
169+ fi
170+ if docker compose version 2> /dev/null | grep -qi podman; then
171+ return 0
172+ fi
173+ return 1
174+ }
175+
166176compose_cp_supported () {
177+ if compose_backend_is_podman; then
178+ return 1
179+ fi
167180 cd " ${REPO_ROOT} "
168181 docker compose cp --help > /dev/null 2>&1
169182}
@@ -231,31 +244,65 @@ count_files_in_proxy_container() {
231244 docker compose exec -T proxy sh -lc " find '${container_dir} ' -type f 2>/dev/null | wc -l | tr -d ' '"
232245}
233246
234- reset_container_dir () {
235- local cid=" $1 "
236- local target_dir=" $2 "
237- local reset_cmd=" rm -rf '${target_dir} ' && mkdir -p '${target_dir} '"
247+ reset_container_dir_via_compose () {
248+ local target_dir=" $1 "
249+ docker compose exec -T web bash -lc " rm -rf '${target_dir} ' && mkdir -p '${target_dir} '"
250+ }
251+
252+ copy_host_tar_into_web () {
253+ local host_tar=" $1 "
254+ local container_tar=" $2 "
255+ local cid=" $3 "
256+
257+ cd " ${REPO_ROOT} "
258+ if docker compose cp " ${host_tar} " " web:${container_tar} " 2> /dev/null; then
259+ echo " rebuild_frontend.sh: staged deploy tar → web via compose cp" >&2
260+ return 0
261+ fi
262+
238263 if [[ -n " ${cid} " ]] && podman_cli_available; then
239- podman exec " ${cid } " bash -lc " ${reset_cmd } "
240- else
241- docker compose exec -T web bash -lc " ${reset_cmd} "
264+ podman cp " ${host_tar } " " ${cid} : ${container_tar }"
265+ echo " rebuild_frontend.sh: staged deploy tar → web via podman cp " >&2
266+ return 0
242267 fi
268+
269+ echo " rebuild_frontend.sh: failed to copy deploy tar into web container" >&2
270+ return 1
243271}
244272
245- copy_tree_via_compose_cp () {
273+ copy_tree_via_staged_tar () {
246274 local dest=" $1 "
247- docker compose cp " ${STATIC_FRONTEND} /." " web:${dest} /"
275+ local cid host_tar container_tar
276+
277+ cid=" $( web_container_id) "
278+ if [[ -z " ${cid} " ]]; then
279+ echo " rebuild_frontend.sh: web container id not found (is the web service running?)" >&2
280+ exit 1
281+ fi
282+
283+ host_tar=" $( mktemp /tmp/hps-frontend-deploy.XXXXXX.tar) "
284+ container_tar=" /tmp/hps-frontend-deploy.${$} .${RANDOM} .tar"
285+
286+ tar -C " ${STATIC_FRONTEND} " -cf " ${host_tar} " .
287+ if ! copy_host_tar_into_web " ${host_tar} " " ${container_tar} " " ${cid} " ; then
288+ rm -f " ${host_tar} "
289+ exit 1
290+ fi
291+ rm -f " ${host_tar} "
292+
293+ # Extract inside web via compose exec so writes land on the staticfiles_data volume.
294+ docker compose exec -T web bash -lc \
295+ " rm -rf '${dest} ' && mkdir -p '${dest} ' && tar -xf '${container_tar} ' -C '${dest} ' && rm -f '${container_tar} '"
248296}
249297
250- copy_tree_via_podman_exec_tar () {
251- local cid =" $1 "
252- local dest= " $2 "
253- tar -C " ${STATIC_FRONTEND} " -cf - . | podman exec -i " ${cid} " tar -xf - -C " ${dest} "
298+ copy_tree_via_compose_cp () {
299+ local dest =" $1 "
300+ reset_container_dir_via_compose " ${dest} "
301+ docker compose cp " ${STATIC_FRONTEND} /. " " web: ${dest} / "
254302}
255303
256304copy_tree_into_container () {
257- local cid=" $1 "
258- local dest=" $2 "
305+ local dest=" $1 "
259306
260307 if compose_cp_supported; then
261308 echo " rebuild_frontend.sh: copying via docker compose cp → ${dest} " >&2
@@ -264,34 +311,24 @@ copy_tree_into_container() {
264311 fi
265312
266313 if ! podman_cli_available; then
267- echo " rebuild_frontend.sh: compose cp unavailable and podman not on PATH; cannot deploy into web" >&2
268- exit 1
269- fi
270-
271- if [[ -z " ${cid} " ]]; then
272- echo " rebuild_frontend.sh: web container id not found (is the web service running?)" >&2
314+ echo " rebuild_frontend.sh: podman-compose detected but podman not on PATH; cannot deploy into web" >&2
273315 exit 1
274316 fi
275317
276- # podman cp can write to the container layer instead of a bind-mounted volume on some
277- # podman-compose setups; streaming tar through podman exec -i targets the mount reliably.
278- echo " rebuild_frontend.sh: copying via podman exec -i tar → ${dest} " >&2
279- reset_container_dir " ${cid} " " ${dest} "
280- copy_tree_via_podman_exec_tar " ${cid} " " ${dest} "
318+ # podman-compose: stdin tar and direct tree cp are unreliable for named volumes; stage a
319+ # tar on /tmp in the container, then extract with compose exec onto the volume mount.
320+ echo " rebuild_frontend.sh: copying via staged tar + compose exec extract → ${dest} " >&2
321+ copy_tree_via_staged_tar " ${dest} "
281322}
282323
283324copy_frontend_into_web () {
284325 cd " ${REPO_ROOT} "
285- local cid
286- cid=" $( web_container_id) "
287326
288327 # nginx (proxy) reads STATIC_ROOT/frontend from the shared staticfiles_data volume.
289- reset_container_dir " ${cid} " " ${CONTAINER_STATIC_ROOT_FRONTEND} "
290- copy_tree_into_container " ${cid} " " ${CONTAINER_STATIC_ROOT_FRONTEND} "
328+ copy_tree_into_container " ${CONTAINER_STATIC_ROOT_FRONTEND} "
291329
292330 # Keep image source tree in sync for future collectstatic / container rebuilds.
293- reset_container_dir " ${cid} " " ${CONTAINER_STATIC_FRONTEND} "
294- copy_tree_into_container " ${cid} " " ${CONTAINER_STATIC_FRONTEND} "
331+ copy_tree_into_container " ${CONTAINER_STATIC_FRONTEND} "
295332}
296333
297334sha256_in_web_container () {
@@ -405,6 +442,7 @@ deploy_to_compose() {
405442 verify_proxy_file_count_matches_web
406443 print_container_deploy_fingerprint " web STATIC_ROOT" web " ${CONTAINER_STATIC_ROOT_FRONTEND} /machine/index.html"
407444 print_container_deploy_fingerprint " proxy nginx volume" proxy " ${PROXY_STATIC_ROOT_FRONTEND} /machine/index.html"
445+ print_deploy_fingerprint " host build (expected)" " ${STATIC_FRONTEND} /machine/index.html"
408446
409447 echo " Frontend deploy complete. Use the proxy service (ports 80/443), not web:8000 — Gunicorn does not serve /machine/."
410448 echo " Hard-refresh the browser and confirm the deploy fingerprint above matches page-*.js in DevTools Network."
0 commit comments