1
0

dw 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. #!/bin/bash
  2. #
  3. # Dune Weaver CLI
  4. #
  5. # Usage: dw <command>
  6. #
  7. # Commands:
  8. # install Run initial setup (Docker + WiFi fix)
  9. # start Start Dune Weaver
  10. # stop Stop Dune Weaver
  11. # restart Restart Dune Weaver
  12. # update Pull latest changes and restart
  13. # logs View live logs (Ctrl+C to exit)
  14. # status Show container status
  15. # shell Open a shell in the container
  16. # checkout Switch to a branch and pull its Docker images
  17. # touch Manage touch screen app
  18. # wifi Manage WiFi and hotspot
  19. # help Show this help message
  20. #
  21. set -e
  22. # Colors
  23. RED='\033[0;31m'
  24. GREEN='\033[0;32m'
  25. YELLOW='\033[1;33m'
  26. BLUE='\033[0;34m'
  27. NC='\033[0m'
  28. # Find dune-weaver directory
  29. find_install_dir() {
  30. # Check common locations
  31. if [[ -f "$HOME/dune-weaver/main.py" ]]; then
  32. echo "$HOME/dune-weaver"
  33. elif [[ -f "/home/pi/dune-weaver/main.py" ]]; then
  34. echo "/home/pi/dune-weaver"
  35. elif [[ -f "./main.py" ]]; then
  36. pwd
  37. else
  38. echo ""
  39. fi
  40. }
  41. # Check if using Docker or systemd
  42. is_docker_mode() {
  43. # Docker mode if docker-compose.yml exists and docker is available
  44. [[ -f "$INSTALL_DIR/docker-compose.yml" ]] && command -v docker &> /dev/null
  45. }
  46. # Set IMAGE_TAG from current git branch (e.g. feature/foo -> feature-foo)
  47. set_image_tag() {
  48. local branch
  49. branch=$(git -C "$INSTALL_DIR" rev-parse --abbrev-ref HEAD)
  50. export IMAGE_TAG="${branch//\//-}"
  51. }
  52. INSTALL_DIR=$(find_install_dir)
  53. # Check if installed
  54. check_installed() {
  55. if [[ -z "$INSTALL_DIR" ]]; then
  56. echo -e "${RED}Error: Dune Weaver not found${NC}"
  57. echo ""
  58. echo "Please install first:"
  59. echo " git clone https://github.com/tuanchris/dune-weaver --single-branch"
  60. echo " cd dune-weaver"
  61. echo " dw install"
  62. exit 1
  63. fi
  64. }
  65. # Commands
  66. cmd_install() {
  67. if [[ -z "$INSTALL_DIR" ]]; then
  68. # Not installed, check if we're in the right directory
  69. if [[ -f "./docker-compose.yml" ]] && [[ -f "./main.py" ]]; then
  70. INSTALL_DIR=$(pwd)
  71. else
  72. echo -e "${RED}Error: Run this from the dune-weaver directory${NC}"
  73. echo ""
  74. echo " git clone https://github.com/tuanchris/dune-weaver --single-branch"
  75. echo " cd dune-weaver"
  76. echo " dw install"
  77. exit 1
  78. fi
  79. fi
  80. cd "$INSTALL_DIR"
  81. bash setup-pi.sh "$@"
  82. }
  83. cmd_start() {
  84. check_installed
  85. echo -e "${BLUE}Starting Dune Weaver...${NC}"
  86. cd "$INSTALL_DIR"
  87. if is_docker_mode; then
  88. set_image_tag
  89. sudo -E docker compose up -d
  90. else
  91. sudo systemctl start dune-weaver
  92. fi
  93. local fe_port="${FRONTEND_PORT:-80}"
  94. local port_suffix=""
  95. [[ "$fe_port" != "80" ]] && port_suffix=":$fe_port"
  96. echo -e "${GREEN}Started!${NC} Access at http://$(hostname -I | awk '{print $1}')${port_suffix}"
  97. }
  98. cmd_stop() {
  99. check_installed
  100. echo -e "${BLUE}Stopping Dune Weaver...${NC}"
  101. cd "$INSTALL_DIR"
  102. if is_docker_mode; then
  103. sudo docker compose down
  104. else
  105. sudo systemctl stop dune-weaver
  106. fi
  107. echo -e "${GREEN}Stopped${NC}"
  108. }
  109. cmd_restart() {
  110. check_installed
  111. echo -e "${BLUE}Restarting Dune Weaver...${NC}"
  112. cd "$INSTALL_DIR"
  113. if is_docker_mode; then
  114. set_image_tag
  115. sudo -E docker compose restart
  116. else
  117. sudo systemctl restart dune-weaver
  118. fi
  119. echo -e "${GREEN}Restarted${NC}"
  120. }
  121. cmd_update() {
  122. check_installed
  123. echo -e "${BLUE}Updating Dune Weaver...${NC}"
  124. cd "$INSTALL_DIR"
  125. # Check if we should skip the pull phase (called after re-exec)
  126. if [[ "$1" != "--continue" ]]; then
  127. echo "Pulling latest code..."
  128. git pull
  129. # Update dw CLI
  130. echo "Updating dw command..."
  131. sudo cp "$INSTALL_DIR/dw" /usr/local/bin/dw
  132. sudo chmod +x /usr/local/bin/dw
  133. # Re-exec with the new script to ensure new code runs
  134. echo "Restarting with updated CLI..."
  135. exec /usr/local/bin/dw update --continue
  136. fi
  137. if is_docker_mode; then
  138. set_image_tag
  139. echo -e "Image tag: ${BLUE}${IMAGE_TAG}${NC}"
  140. echo "Pulling latest Docker image..."
  141. sudo -E docker compose pull
  142. echo "Stopping current container..."
  143. sudo docker compose down
  144. echo "Starting with new version..."
  145. sudo -E docker compose up -d --remove-orphans
  146. echo "Cleaning up unused Docker resources..."
  147. sudo docker image prune -f
  148. sudo docker container prune -f
  149. else
  150. echo "Updating Python dependencies..."
  151. source .venv/bin/activate
  152. pip install -r requirements.txt
  153. echo "Restarting service..."
  154. sudo systemctl restart dune-weaver
  155. fi
  156. # Install/update WiFi host scripts if not present
  157. if [[ -f "$INSTALL_DIR/wifi/setup-wifi.sh" ]]; then
  158. if [[ ! -f /usr/local/bin/autohotspot ]]; then
  159. echo ""
  160. echo -e "${BLUE}Installing autohotspot WiFi scripts...${NC}"
  161. sudo bash "$INSTALL_DIR/wifi/setup-wifi.sh"
  162. else
  163. # Always update the script and service files to latest
  164. echo "Updating WiFi host scripts..."
  165. sudo cp "$INSTALL_DIR/wifi/autohotspot" /usr/local/bin/autohotspot
  166. sudo chmod +x /usr/local/bin/autohotspot
  167. # Update service/timer files
  168. sudo cp "$INSTALL_DIR/wifi/autohotspot.service" /etc/systemd/system/autohotspot.service
  169. sudo cp "$INSTALL_DIR/wifi/autohotspot-check.service" /etc/systemd/system/autohotspot-check.service 2>/dev/null || true
  170. sudo cp "$INSTALL_DIR/wifi/autohotspot-check.timer" /etc/systemd/system/autohotspot-check.timer 2>/dev/null || true
  171. sudo systemctl daemon-reload
  172. sudo systemctl enable autohotspot-check.timer 2>/dev/null || true
  173. fi
  174. fi
  175. # Update touch app if installed (check both directory and service exist)
  176. local touch_dir="$INSTALL_DIR/dune-weaver-touch"
  177. if [[ -d "$touch_dir" ]] && systemctl list-unit-files dune-weaver-touch.service 2>/dev/null | grep -q dune-weaver-touch; then
  178. echo ""
  179. echo -e "${BLUE}Updating touch app...${NC}"
  180. cd "$touch_dir"
  181. # Update Python dependencies (code already pulled with main repo)
  182. if [[ -f "requirements.txt" ]] && [[ -d ".venv" ]]; then
  183. echo "Updating touch app dependencies..."
  184. source .venv/bin/activate
  185. pip install -q -r requirements.txt
  186. deactivate
  187. fi
  188. # Restart to apply changes
  189. sudo systemctl restart dune-weaver-touch
  190. echo -e "${GREEN}Touch app updated!${NC}"
  191. fi
  192. echo -e "${GREEN}Update complete!${NC}"
  193. }
  194. cmd_logs() {
  195. check_installed
  196. cd "$INSTALL_DIR"
  197. # Parse optional line count (e.g., dw logs 100)
  198. local lines="${1:-}"
  199. local follow="-f"
  200. if [[ -n "$lines" ]]; then
  201. follow="--tail $lines"
  202. fi
  203. if is_docker_mode; then
  204. sudo docker compose logs $follow
  205. else
  206. if [[ -n "$lines" ]]; then
  207. sudo journalctl -u dune-weaver -n "$lines"
  208. else
  209. sudo journalctl -u dune-weaver -f
  210. fi
  211. fi
  212. }
  213. cmd_status() {
  214. check_installed
  215. cd "$INSTALL_DIR"
  216. if is_docker_mode; then
  217. sudo docker compose ps
  218. else
  219. sudo systemctl status dune-weaver
  220. fi
  221. }
  222. cmd_shell() {
  223. check_installed
  224. cd "$INSTALL_DIR"
  225. if is_docker_mode; then
  226. sudo docker compose exec dune-weaver /bin/bash
  227. else
  228. echo -e "${YELLOW}Shell not available in systemd mode${NC}"
  229. echo "Use: cd $INSTALL_DIR && source .venv/bin/activate"
  230. fi
  231. }
  232. # Touch app commands (systemd service)
  233. cmd_touch() {
  234. local subcmd="${1:-help}"
  235. case "$subcmd" in
  236. logs)
  237. local lines="${2:-}"
  238. if [[ -n "$lines" ]]; then
  239. sudo journalctl -u dune-weaver-touch -n "$lines"
  240. else
  241. sudo journalctl -u dune-weaver-touch -f
  242. fi
  243. ;;
  244. restart)
  245. echo -e "${BLUE}Restarting touch app...${NC}"
  246. sudo systemctl restart dune-weaver-touch
  247. echo -e "${GREEN}Touch app restarted${NC}"
  248. ;;
  249. stop)
  250. echo -e "${BLUE}Stopping touch app...${NC}"
  251. sudo systemctl stop dune-weaver-touch
  252. echo -e "${GREEN}Touch app stopped${NC}"
  253. ;;
  254. start)
  255. echo -e "${BLUE}Starting touch app...${NC}"
  256. sudo systemctl start dune-weaver-touch
  257. echo -e "${GREEN}Touch app started${NC}"
  258. ;;
  259. status)
  260. sudo systemctl status dune-weaver-touch
  261. ;;
  262. install)
  263. check_installed
  264. local touch_dir="$INSTALL_DIR/dune-weaver-touch"
  265. if [[ ! -f "$touch_dir/install.sh" ]]; then
  266. echo -e "${RED}Touch app installer not found at $touch_dir/install.sh${NC}"
  267. echo "Make sure you have the dune-weaver-touch directory in your dune-weaver folder."
  268. exit 1
  269. fi
  270. echo -e "${BLUE}Running touch app installer...${NC}"
  271. cd "$touch_dir"
  272. sudo bash install.sh
  273. ;;
  274. help|*)
  275. echo -e "${GREEN}Touch App Commands${NC}"
  276. echo ""
  277. echo "Usage: dw touch <command>"
  278. echo ""
  279. echo "Commands:"
  280. echo " install Install touch app (clone, setup, enable service)"
  281. echo " logs [N] View logs (N lines or follow if omitted)"
  282. echo " restart Restart touch app"
  283. echo " stop Stop touch app"
  284. echo " start Start touch app"
  285. echo " status Show touch app status"
  286. echo " help Show this help message"
  287. ;;
  288. esac
  289. }
  290. cmd_checkout() {
  291. check_installed
  292. local branch="$1"
  293. if [[ -z "$branch" ]]; then
  294. echo -e "${RED}Usage: dw checkout <branch>${NC}"
  295. echo ""
  296. echo "Examples:"
  297. echo " dw checkout main"
  298. echo " dw checkout feature/security-settings-split"
  299. echo ""
  300. echo "Current branch: $(git -C "$INSTALL_DIR" rev-parse --abbrev-ref HEAD)"
  301. exit 1
  302. fi
  303. cd "$INSTALL_DIR"
  304. # Repo may be cloned with --single-branch; fetch the target branch explicitly
  305. echo -e "${BLUE}Fetching branch ${branch}...${NC}"
  306. if ! git fetch origin "$branch" 2>/dev/null; then
  307. echo -e "${RED}Branch '${branch}' not found on remote${NC}"
  308. exit 1
  309. fi
  310. # Checkout: create local tracking branch if it doesn't exist
  311. if git show-ref --verify --quiet "refs/heads/$branch"; then
  312. git checkout "$branch"
  313. git pull
  314. else
  315. git checkout -b "$branch" "origin/$branch"
  316. fi
  317. echo -e "Switched to branch: ${GREEN}${branch}${NC}"
  318. # Pull and restart Docker images for the new branch
  319. if is_docker_mode; then
  320. set_image_tag
  321. echo -e "Image tag: ${BLUE}${IMAGE_TAG}${NC}"
  322. echo "Pulling Docker images..."
  323. sudo -E docker compose pull
  324. echo "Restarting with new images..."
  325. sudo docker compose down
  326. sudo -E docker compose up -d --remove-orphans
  327. echo "Cleaning up old images..."
  328. sudo docker image prune -f
  329. fi
  330. # Update dw CLI from the new branch
  331. sudo cp "$INSTALL_DIR/dw" /usr/local/bin/dw
  332. sudo chmod +x /usr/local/bin/dw
  333. # Install WiFi scripts if available on this branch but not yet installed
  334. if [[ -f "$INSTALL_DIR/wifi/setup-wifi.sh" ]] && [[ ! -f /usr/local/bin/autohotspot ]]; then
  335. echo ""
  336. echo -e "${BLUE}Installing autohotspot WiFi scripts...${NC}"
  337. sudo bash "$INSTALL_DIR/wifi/setup-wifi.sh"
  338. fi
  339. echo -e "${GREEN}Checkout complete!${NC}"
  340. }
  341. # WiFi / Hotspot commands
  342. cmd_wifi() {
  343. local subcmd="${1:-help}"
  344. case "$subcmd" in
  345. status)
  346. check_installed
  347. echo -e "${BLUE}WiFi Status${NC}"
  348. echo ""
  349. # Show current mode
  350. local mode="unknown"
  351. if [[ -f /tmp/dw-wifi-mode ]]; then
  352. mode=$(cat /tmp/dw-wifi-mode)
  353. fi
  354. echo -e "Mode: ${GREEN}${mode}${NC}"
  355. # Show connected network
  356. local ssid
  357. ssid=$(nmcli -t -f GENERAL.CONNECTION dev show wlan0 2>/dev/null | head -1 | cut -d: -f2)
  358. if [[ -n "$ssid" && "$ssid" != "--" ]]; then
  359. echo -e "Network: ${GREEN}${ssid}${NC}"
  360. fi
  361. # Show IP
  362. local ip
  363. ip=$(nmcli -t -f IP4.ADDRESS dev show wlan0 2>/dev/null | head -1 | cut -d: -f2 | cut -d/ -f1)
  364. if [[ -n "$ip" ]]; then
  365. echo -e "IP: ${GREEN}${ip}${NC}"
  366. fi
  367. ;;
  368. scan)
  369. echo -e "${BLUE}Scanning for WiFi networks...${NC}"
  370. nmcli dev wifi rescan 2>/dev/null || true
  371. sleep 2
  372. nmcli dev wifi list
  373. ;;
  374. connect)
  375. echo -e "${BLUE}Available WiFi networks:${NC}"
  376. nmcli dev wifi rescan 2>/dev/null || true
  377. sleep 2
  378. nmcli dev wifi list
  379. echo ""
  380. read -p "Enter SSID to connect to: " ssid
  381. if [[ -z "$ssid" ]]; then
  382. echo -e "${RED}No SSID provided${NC}"
  383. exit 1
  384. fi
  385. read -sp "Enter password (leave empty for open networks): " password
  386. echo ""
  387. # Delete any stale connection profile for this SSID
  388. sudo nmcli con delete "$ssid" 2>/dev/null || true
  389. if [[ -n "$password" ]]; then
  390. # Create connection with explicit security settings
  391. # (nmcli dev wifi connect can fail on Trixie without key-mgmt)
  392. sudo nmcli con add type wifi ifname wlan0 con-name "$ssid" \
  393. ssid "$ssid" \
  394. wifi-sec.key-mgmt wpa-psk \
  395. wifi-sec.psk "$password"
  396. else
  397. sudo nmcli con add type wifi ifname wlan0 con-name "$ssid" \
  398. ssid "$ssid"
  399. fi
  400. echo -e "${BLUE}Connecting to '$ssid'...${NC}"
  401. if sudo nmcli con up "$ssid"; then
  402. echo -e "${GREEN}Connected!${NC}"
  403. else
  404. echo -e "${RED}Failed to connect. Check password and try again.${NC}"
  405. sudo nmcli con delete "$ssid" 2>/dev/null || true
  406. exit 1
  407. fi
  408. ;;
  409. hotspot)
  410. echo -e "${BLUE}Switching to hotspot mode...${NC}"
  411. sudo nmcli dev disconnect wlan0 2>/dev/null || true
  412. sudo nmcli con up DuneWeaver-Hotspot 2>/dev/null
  413. echo "hotspot" | sudo tee /tmp/dw-wifi-mode > /dev/null
  414. echo -e "${GREEN}Hotspot active!${NC} Connect to the 'Dune Weaver' WiFi network."
  415. ;;
  416. setup)
  417. check_installed
  418. cd "$INSTALL_DIR"
  419. sudo bash wifi/setup-wifi.sh
  420. ;;
  421. help|*)
  422. echo -e "${GREEN}WiFi Commands${NC}"
  423. echo ""
  424. echo "Usage: dw wifi <command>"
  425. echo ""
  426. echo "Commands:"
  427. echo " status Show current WiFi mode and connection"
  428. echo " scan Scan for available networks"
  429. echo " connect Interactive: scan + select + connect"
  430. echo " hotspot Force hotspot mode"
  431. echo " setup Run initial autohotspot setup"
  432. echo " help Show this help message"
  433. ;;
  434. esac
  435. }
  436. cmd_help() {
  437. echo -e "${GREEN}Dune Weaver CLI${NC}"
  438. echo ""
  439. echo "Usage: dw <command>"
  440. echo ""
  441. echo "Commands:"
  442. echo " install Run initial setup (Docker + WiFi fix)"
  443. echo " start Start Dune Weaver"
  444. echo " stop Stop Dune Weaver"
  445. echo " restart Restart Dune Weaver"
  446. echo " update Pull latest changes and restart"
  447. echo " checkout Switch to a branch and pull its Docker images"
  448. echo " logs [N] View logs (N=number of lines, or follow if omitted)"
  449. echo " status Show container status"
  450. echo " shell Open a shell in the container"
  451. echo " touch Manage touch screen app (run 'dw touch help')"
  452. echo " wifi Manage WiFi and hotspot (run 'dw wifi help')"
  453. echo " help Show this help message"
  454. echo ""
  455. if [[ -n "$INSTALL_DIR" ]]; then
  456. echo -e "Install directory: ${BLUE}$INSTALL_DIR${NC}"
  457. fi
  458. }
  459. # Main
  460. case "${1:-help}" in
  461. install)
  462. shift
  463. cmd_install "$@"
  464. ;;
  465. start)
  466. cmd_start
  467. ;;
  468. stop)
  469. cmd_stop
  470. ;;
  471. restart)
  472. cmd_restart
  473. ;;
  474. update)
  475. cmd_update "$2"
  476. ;;
  477. checkout)
  478. cmd_checkout "$2"
  479. ;;
  480. logs)
  481. cmd_logs "$2"
  482. ;;
  483. status)
  484. cmd_status
  485. ;;
  486. shell)
  487. cmd_shell
  488. ;;
  489. touch)
  490. shift
  491. cmd_touch "$@"
  492. ;;
  493. wifi)
  494. shift
  495. cmd_wifi "$@"
  496. ;;
  497. help|--help|-h)
  498. cmd_help
  499. ;;
  500. *)
  501. echo -e "${RED}Unknown command: $1${NC}"
  502. echo ""
  503. cmd_help
  504. exit 1
  505. ;;
  506. esac