100 lines
4.0 KiB
Bash
Executable File
100 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Pudu Map GUI — THE one script.
|
|
#
|
|
# ./start.sh start it + open the browser
|
|
# ./start.sh logs follow the server log
|
|
# ./start.sh stop stop it (same as the dashboard's ⏻ Shutdown)
|
|
# ./start.sh restart stop + start
|
|
# ./start.sh build rebuild the docker image, then start
|
|
# ./start.sh fg run attached in this terminal (debugging only)
|
|
#
|
|
# Everything runs in docker; the host needs only docker + an X server.
|
|
# Host paths are mounted VERBATIM so every absolute path behaves the same in
|
|
# and out of the container:
|
|
# ~/Robotics_workspace stage dirs, map editor, relay, rviz configs
|
|
# ~/Downloads Pudu exports
|
|
# ~/.ssh (read-only) robot deploys (known_hosts redirected to /tmp)
|
|
# X11 + DISPLAY RViz + the native file picker
|
|
# --net=host web GUI on :8777, DDS for the local /map, rosbridge
|
|
#
|
|
# DETACHED BY DEFAULT: the dashboard is a service. Also, `docker run -it` can
|
|
# hang forever on a host whose docker attach stream is wedged (seen live on this
|
|
# workstation: create/start/stop fine, every attached run hung) — detached
|
|
# sidesteps that. Use `fg` only when you need the raw attached output.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
set -euo pipefail
|
|
CMD="${1:-start}"
|
|
# not in the docker group in THIS shell? re-run the whole script under sg
|
|
docker ps >/dev/null 2>&1 || exec sg docker -c "$0 $CMD"
|
|
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
IMG=pudu-map-gui
|
|
NAME=pudu-map-gui
|
|
PORT=8777
|
|
URL="http://127.0.0.1:$PORT"
|
|
|
|
_stop() {
|
|
# the GUI's own viewer processes live INSIDE the container, so removing it
|
|
# takes them with it. Robots are never touched by this script.
|
|
if docker rm -f "$NAME" >/dev/null 2>&1; then echo "stopped $NAME"
|
|
else echo "$NAME was not running"; fi
|
|
}
|
|
|
|
case "$CMD" in
|
|
stop) _stop; exit 0 ;;
|
|
logs) exec docker logs -f "$NAME" ;;
|
|
restart) _stop ;;
|
|
esac
|
|
|
|
if [ "$CMD" = build ] || ! docker image inspect $IMG >/dev/null 2>&1; then
|
|
echo "== building $IMG (first run takes a few minutes) =="
|
|
docker build -t $IMG "$HERE"
|
|
fi
|
|
|
|
# let the container's root talk to the host X server (RViz / zenity picker)
|
|
xhost +local: >/dev/null 2>&1 || true
|
|
# a stray host-side instance would hold the port — hand over cleanly
|
|
fuser -k "$PORT/tcp" >/dev/null 2>&1 || true
|
|
docker rm -f "$NAME" >/dev/null 2>&1 || true
|
|
|
|
RUN=(docker run --rm --net=host --name "$NAME"
|
|
-e DISPLAY="${DISPLAY:-:0}"
|
|
-e HOME="$HOME"
|
|
-e PUDU_GUI_DIR="$HERE"
|
|
-v /tmp/.X11-unix:/tmp/.X11-unix
|
|
-v "$HOME/Robotics_workspace:$HOME/Robotics_workspace"
|
|
-v "$HOME/Downloads:$HOME/Downloads"
|
|
-v "$HOME/.ssh:$HOME/.ssh:ro")
|
|
|
|
if [ "$CMD" = fg ]; then # attached, for debugging
|
|
TT=(-it); [ -t 0 ] || TT=()
|
|
exec "${RUN[@]}" "${TT[@]}" $IMG
|
|
fi
|
|
|
|
"${RUN[@]}" -d $IMG >/dev/null
|
|
|
|
# never claim success blindly — wait until the server actually answers
|
|
for _ in $(seq 40); do
|
|
if curl -fsS -m 2 -o /dev/null "$URL/" 2>/dev/null; then
|
|
[ "${NOBROWSER:-0}" = 1 ] || (xdg-open "$URL" >/dev/null 2>&1 &) || true
|
|
cat <<EOT
|
|
|
|
Pudu Map GUI is up -> $URL
|
|
(opened in your browser; if the page looks old, reload with $URL/?v=1)
|
|
|
|
logs: $0 logs stop: $0 stop restart: $0 restart
|
|
or press ⏻ Shutdown in the dashboard header.
|
|
EOT
|
|
exit 0
|
|
fi
|
|
docker ps --format '{{.Names}}' | grep -qx "$NAME" || {
|
|
echo "container exited during startup — last log lines:" >&2
|
|
docker logs "$NAME" 2>&1 | tail -20 >&2 || true
|
|
exit 1
|
|
}
|
|
sleep 1
|
|
done
|
|
echo "started, but $URL did not answer within 40s — check: $0 logs" >&2
|
|
exit 1
|