luxstats.sh 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/env bash
  2. # LuxStats background launcher for Arch Linux
  3. #
  4. # * Auto-detects every installed CPython 3 and uses the newest one
  5. # * Runs WITHOUT a venv when the system python already has the deps
  6. # (pacman: python-pyqt5 python-pyserial python-psutil)
  7. # * Otherwise creates/uses a managed venv at
  8. # ${XDG_DATA_HOME:-~/.local/share}/luxstats/venv and installs deps there
  9. # * Launches the configurator detached from the terminal, logging to
  10. # ${XDG_STATE_HOME:-~/.local/state}/luxstats/luxstats.log
  11. #
  12. # Usage: ./luxstats.sh start in the background
  13. # ./luxstats.sh stop stop a running instance
  14. # ./luxstats.sh status show whether it's running
  15. set -euo pipefail
  16. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  17. # works both from the repo root (host/ beside this script) and from packaging/
  18. if [[ -f "$SCRIPT_DIR/host/luxstats_configurator.py" ]]; then
  19. APP="$SCRIPT_DIR/host/luxstats_configurator.py"
  20. elif [[ -f "$SCRIPT_DIR/../host/luxstats_configurator.py" ]]; then
  21. APP="$(cd "$SCRIPT_DIR/../host" && pwd)/luxstats_configurator.py"
  22. else
  23. echo "luxstats: cannot locate host/luxstats_configurator.py" >&2
  24. exit 1
  25. fi
  26. DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/luxstats"
  27. STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/luxstats"
  28. VENV="$DATA_DIR/venv"
  29. LOG="$STATE_DIR/luxstats.log"
  30. PIDFILE="$STATE_DIR/luxstats.pid"
  31. DEPS_IMPORT='import PyQt5, serial, psutil'
  32. mkdir -p "$DATA_DIR" "$STATE_DIR"
  33. find_newest_python() {
  34. local best="" bestver=0 py ver base
  35. # scan PATH + common locations for pythonN.M binaries
  36. for py in $(compgen -c python3 | sort -u) /usr/bin/python3 \
  37. /usr/local/bin/python3.*; do
  38. base="$(basename "$py" 2>/dev/null || true)"
  39. [[ "$base" =~ ^python3(\.[0-9]+)?$ ]] || continue
  40. command -v "$py" >/dev/null 2>&1 || [[ -x "$py" ]] || continue
  41. ver="$("$py" -c 'import sys;print(sys.version_info[0]*1000+sys.version_info[1])' \
  42. 2>/dev/null)" || continue
  43. if (( ver > bestver )); then bestver=$ver; best="$py"; fi
  44. done
  45. [[ -n "$best" ]] || { echo "luxstats: no python3 found" >&2; return 1; }
  46. echo "$best"
  47. }
  48. pick_interpreter() {
  49. local sys_py; sys_py="$(find_newest_python)"
  50. echo "using system interpreter candidate: $sys_py" \
  51. "($("$sys_py" -V 2>&1))" >&2
  52. if "$sys_py" -c "$DEPS_IMPORT" 2>/dev/null; then
  53. echo "$sys_py" # no venv needed
  54. return
  55. fi
  56. echo "system python lacks PyQt5/pyserial/psutil - using managed venv" >&2
  57. echo "(tip: 'sudo pacman -S python-pyqt5 python-pyserial python-psutil'" \
  58. "avoids the venv entirely)" >&2
  59. if [[ ! -x "$VENV/bin/python" ]] \
  60. || ! "$VENV/bin/python" -c "$DEPS_IMPORT" 2>/dev/null; then
  61. "$sys_py" -m venv --clear "$VENV"
  62. "$VENV/bin/pip" install --quiet --upgrade pip
  63. "$VENV/bin/pip" install --quiet PyQt5 pyserial psutil
  64. fi
  65. echo "$VENV/bin/python"
  66. }
  67. is_running() {
  68. [[ -f "$PIDFILE" ]] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null
  69. }
  70. case "${1:-start}" in
  71. start)
  72. if is_running; then
  73. echo "luxstats already running (pid $(cat "$PIDFILE"))"
  74. exit 0
  75. fi
  76. PY="$(pick_interpreter)"
  77. echo "launching with $PY"
  78. setsid "$PY" "$APP" >>"$LOG" 2>&1 < /dev/null &
  79. echo $! > "$PIDFILE"
  80. disown
  81. echo "luxstats started in the background (pid $(cat "$PIDFILE"))"
  82. echo "log: $LOG"
  83. ;;
  84. stop)
  85. if is_running; then
  86. kill "$(cat "$PIDFILE")" && rm -f "$PIDFILE"
  87. echo "luxstats stopped"
  88. else
  89. echo "luxstats is not running"
  90. fi
  91. ;;
  92. status)
  93. if is_running; then
  94. echo "running (pid $(cat "$PIDFILE"))"
  95. else
  96. echo "not running"
  97. fi
  98. ;;
  99. *)
  100. echo "usage: $0 [start|stop|status]" >&2
  101. exit 1
  102. ;;
  103. esac