#!/usr/bin/env bash set -euo pipefail project_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P) source_dir=$project_dir pi_user= pi_host= remote_dir= apply=false install_service=false usage() { cat <<'EOF' Projektdateien per SSH/rsync auf einen Raspberry Pi kopieren. Aufruf: bash tools/upload_to_pi.sh --user BENUTZER --host HOST \ --remote-dir /home/BENUTZER/halloween [--source ORDNER] [--install-service] [--apply] Ohne --apply wird nur der geplante Aufruf angezeigt; es gibt keine Verbindung zum Pi. --apply legt den Zielordner an und kopiert die Dateien. Alte Dateien auf dem Pi werden nicht gelöscht. --install-service richtet nach dem Upload einen systemd-Autostart ein. Dazu muss die Python-Umgebung auf dem Pi bereits vorbereitet sein; sudo wird dort benötigt. Ohne --apply wird auch der Dienst nicht installiert. EOF } die() { printf 'Fehler: %s\n' "$*" >&2 exit 2 } while (($#)); do case $1 in --user|--host|--remote-dir|--source) (($# >= 2)) || die "Wert für $1 fehlt" case $1 in --user) pi_user=$2 ;; --host) pi_host=$2 ;; --remote-dir) remote_dir=$2 ;; --source) source_dir=$2 ;; esac shift 2 ;; --apply) apply=true; shift ;; --install-service) install_service=true; shift ;; -h|--help) usage; exit 0 ;; *) die "Unbekanntes Argument: $1" ;; esac done [[ $pi_user =~ ^[a-zA-Z_][a-zA-Z0-9_-]*$ ]] || die 'Gültigen --user angeben' [[ $pi_host =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]] || die 'Gültigen --host angeben (Name oder IPv4-Adresse)' [[ $remote_dir =~ ^/[a-zA-Z0-9_./-]+$ && $remote_dir != / ]] || die 'Sicheren absoluten --remote-dir angeben' [[ /$remote_dir/ != *'/../'* && /$remote_dir/ != *'/./'* ]] || die 'Zielpfad darf keine . oder .. Segmente enthalten' [[ -d $source_dir ]] || die "Quellordner fehlt: $source_dir" source_dir=$(cd -- "$source_dir" && pwd -P) if $install_service; then [[ -f "$source_dir/tools/install_pi_service.sh" ]] || die 'tools/install_pi_service.sh fehlt in der Quelle' fi command -v ssh >/dev/null || die 'ssh fehlt lokal' command -v rsync >/dev/null || die 'rsync fehlt lokal' target="$pi_user@$pi_host" excludes=( --exclude=.git/ --exclude=.venv/ --exclude=__pycache__/ --exclude=data/ --exclude=preview/ --exclude=references/ --exclude=.env --exclude='*.pem' --exclude='*.key' --exclude='*.p12' --exclude='*.pfx' ) ssh_cmd=(ssh -o StrictHostKeyChecking=ask "$target" "mkdir -p -- '$remote_dir'") rsync_cmd=( rsync -a --delay-updates --human-readable --info=stats2 "${excludes[@]}" -e 'ssh -o StrictHostKeyChecking=ask' -- "$source_dir/" "$target:$remote_dir/" ) service_cmd=(ssh -tt -o StrictHostKeyChecking=ask "$target" "cd -- '$remote_dir' && bash tools/install_pi_service.sh --apply") printf 'Quelle: %s\nZiel: %s:%s/\n' "$source_dir" "$target" "$remote_dir" printf 'Ausgelassen: .git, .venv, data, preview, references, __pycache__, .env, Schlüsseldateien\n' if ! $apply; then printf '\nVorschau, noch keine Verbindung und keine Übertragung:\n' printf ' %q' "${ssh_cmd[@]}"; printf '\n' printf ' %q' "${rsync_cmd[@]}"; printf '\n' if $install_service; then printf ' %q' "${service_cmd[@]}"; printf '\n' fi printf '\nMit --apply ausführen.\n' exit 0 fi "${ssh_cmd[@]}" "${rsync_cmd[@]}" printf 'Übertragung abgeschlossen.\n' if $install_service; then "${service_cmd[@]}" fi