0265afa054
Import the runnable game code, content, docs, scripts, and repo guidance while leaving local agent state, dependency installs, build output, and backup copies out of the published tree.
239 lines
7.3 KiB
Bash
Executable File
239 lines
7.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Save slot and VM snapshot management for Sysadmin Chronicles.
|
|
#
|
|
# Usage:
|
|
# manage-saves.sh Interactive menu
|
|
# manage-saves.sh --list List save slots (non-interactive)
|
|
# manage-saves.sh --reset Reset current save
|
|
# manage-saves.sh --reset slot-1 Reset a specific slot
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
|
|
source "$PROJECT_ROOT/tools/lib/ui.sh"
|
|
source "$PROJECT_ROOT/tools/lib/config.sh"
|
|
source "$PROJECT_ROOT/tools/lib/save.sh"
|
|
source "$PROJECT_ROOT/tools/lib/libvirt.sh"
|
|
source "$PROJECT_ROOT/tools/lib/vm.sh"
|
|
|
|
config_read || true
|
|
export LIBVIRT_DEFAULT_URI="${SC_LIBVIRT_URI:-${LIBVIRT_DEFAULT_URI:-qemu:///system}}"
|
|
|
|
# Non-interactive flags
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--list)
|
|
save_list
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ "${1:-}" == "--reset" ]]; then
|
|
slot="${2:-}"
|
|
if [ -n "$slot" ]; then
|
|
save_reset "$slot"
|
|
else
|
|
save_reset
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Interactive menu
|
|
# ---------------------------------------------------------------------------
|
|
|
|
declare -A VM_LABEL=(
|
|
[sc-workstation]="workstation (ares)"
|
|
[sc-web-server]="web server (hermes)"
|
|
[sc-build-machine]="build server (vulcan)"
|
|
)
|
|
ALL_VMS=(sc-workstation sc-web-server sc-build-machine)
|
|
|
|
sc_header "SYSADMIN CHRONICLES — SAVE MANAGEMENT"
|
|
|
|
_main_menu() {
|
|
while true; do
|
|
echo ""
|
|
save_list
|
|
echo ""
|
|
echo " ── Save Actions ─────────────────────────────"
|
|
echo " s) Switch active save slot"
|
|
echo " n) New save slot"
|
|
echo " r) Reset a save slot"
|
|
echo " e) Export save to file"
|
|
echo " i) Import save from file"
|
|
echo ""
|
|
echo " ── VM Snapshots ─────────────────────────────"
|
|
echo " v) View and manage VM snapshots"
|
|
echo ""
|
|
echo " q) Quit"
|
|
echo ""
|
|
printf " > " >/dev/tty
|
|
read -r choice </dev/tty
|
|
echo ""
|
|
|
|
case "$choice" in
|
|
s|S) _switch_slot ;;
|
|
n|N) _new_slot ;;
|
|
r|R) _reset_slot ;;
|
|
e|E) _export_slot ;;
|
|
i|I) _import_slot ;;
|
|
v|V) _vm_snapshots ;;
|
|
q|Q) break ;;
|
|
*) sc_warn "Unknown choice." ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
_switch_slot() {
|
|
echo " Switch to which slot? (autosave / slot-1 / slot-2 / slot-3)"
|
|
printf " > " >/dev/tty
|
|
read -r slot </dev/tty
|
|
echo ""
|
|
save_switch "$slot" || true
|
|
|
|
# Warn if VM state may not match
|
|
local active_day
|
|
active_day="$(grep -o '"day":[0-9]*' "$SC_SAVE_DIR/${slot}.json" 2>/dev/null | head -1 | cut -d: -f2 || echo '')"
|
|
if [ -n "$active_day" ] && [ "$active_day" -gt 1 ] 2>/dev/null; then
|
|
echo ""
|
|
sc_warn "This save is on Day $active_day. Your VMs may not match this slot's expected state."
|
|
sc_info "If things look wrong, use 'tools/vm/rebuild-vms.sh' to revert VMs."
|
|
fi
|
|
}
|
|
|
|
_new_slot() {
|
|
echo " Create in which slot? (slot-1 / slot-2 / slot-3)"
|
|
printf " > " >/dev/tty
|
|
read -r slot </dev/tty
|
|
echo ""
|
|
save_new "$slot" || true
|
|
}
|
|
|
|
_reset_slot() {
|
|
echo " Reset which slot? (autosave / slot-1 / slot-2 / slot-3)"
|
|
printf " > " >/dev/tty
|
|
read -r slot </dev/tty
|
|
echo ""
|
|
if sc_confirm " Reset $slot to new game state? This cannot be undone." "N"; then
|
|
save_reset "$slot"
|
|
fi
|
|
}
|
|
|
|
_export_slot() {
|
|
echo " Export which slot? (autosave / slot-1 / slot-2 / slot-3)"
|
|
printf " > " >/dev/tty
|
|
read -r slot </dev/tty
|
|
echo ""
|
|
echo " Save to (full path, e.g. ~/Desktop/my-save.json):"
|
|
printf " > " >/dev/tty
|
|
read -r dest </dev/tty
|
|
dest="${dest/#\~/$HOME}"
|
|
echo ""
|
|
save_export "$slot" "$dest" || true
|
|
}
|
|
|
|
_import_slot() {
|
|
echo " Path to save file to import:"
|
|
printf " > " >/dev/tty
|
|
read -r src </dev/tty
|
|
src="${src/#\~/$HOME}"
|
|
echo ""
|
|
echo " Import into which slot? (autosave / slot-1 / slot-2 / slot-3)"
|
|
printf " > " >/dev/tty
|
|
read -r slot </dev/tty
|
|
echo ""
|
|
save_import "$src" "$slot" || true
|
|
}
|
|
|
|
_vm_snapshots() {
|
|
while true; do
|
|
echo ""
|
|
echo " VM Snapshots"
|
|
echo ""
|
|
|
|
local vm label snaps snap ts prot
|
|
for vm in "${ALL_VMS[@]}"; do
|
|
label="${VM_LABEL[$vm]:-$vm}"
|
|
echo " $label"
|
|
if domain_exists "$vm" 2>/dev/null; then
|
|
snaps="$(virsh snapshot-list "$vm" --name 2>/dev/null | grep -v '^$' || true)"
|
|
if [ -n "$snaps" ]; then
|
|
while IFS= read -r snap; do
|
|
ts="$(virsh snapshot-info "$vm" "$snap" 2>/dev/null | grep 'Creation Time' | awk '{print $3}' || true)"
|
|
if [[ "$snap" == baseline.* ]] || [[ "$snap" == checkpoint.* ]]; then
|
|
prot=" [protected]"
|
|
else
|
|
prot=""
|
|
fi
|
|
printf " %-36s %-12s%s\n" "$snap" "$ts" "$prot"
|
|
done <<< "$snaps"
|
|
else
|
|
echo " (no snapshots)"
|
|
fi
|
|
else
|
|
echo " (VM not found)"
|
|
fi
|
|
echo ""
|
|
done
|
|
|
|
echo " Actions: [t]ake snapshot [r]evert [d]elete [q]uit"
|
|
echo ""
|
|
printf " > " >/dev/tty
|
|
local snap_action
|
|
read -r snap_action </dev/tty
|
|
echo ""
|
|
|
|
case "$snap_action" in
|
|
t|T)
|
|
_pick_vm vm_id " Snapshot which VM? (workstation / web-server / build-machine)"
|
|
echo " Snapshot name (letters, numbers, hyphens):"
|
|
printf " > " >/dev/tty
|
|
read -r snap_name </dev/tty
|
|
echo ""
|
|
vm_snapshot_create "sc-${vm_id}" "$snap_name" \
|
|
&& sc_ok "Snapshot taken: $snap_name on $vm_id" \
|
|
|| sc_warn "Snapshot failed."
|
|
;;
|
|
r|R)
|
|
_pick_vm vm_id " Revert which VM?"
|
|
echo " Snapshot name:"
|
|
printf " > " >/dev/tty
|
|
read -r snap_name </dev/tty
|
|
echo ""
|
|
if sc_confirm " Revert $vm_id to '$snap_name'?" "N"; then
|
|
vm_snapshot_revert "sc-${vm_id}" "$snap_name" \
|
|
&& sc_ok "Reverted to $snap_name" \
|
|
|| sc_warn "Revert failed."
|
|
fi
|
|
;;
|
|
d|D)
|
|
_pick_vm vm_id " Delete snapshot from which VM?"
|
|
echo " Snapshot name:"
|
|
printf " > " >/dev/tty
|
|
read -r snap_name </dev/tty
|
|
echo ""
|
|
vm_snapshot_delete "sc-${vm_id}" "$snap_name" \
|
|
&& sc_ok "Deleted $snap_name from $vm_id" \
|
|
|| true
|
|
;;
|
|
q|Q) break ;;
|
|
*) sc_warn "Unknown action." ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
_pick_vm() {
|
|
local -n _result_ref="$1"
|
|
local _prompt="$2"
|
|
echo " $_prompt (workstation / web-server / build-machine)"
|
|
printf " > " >/dev/tty
|
|
read -r _result_ref </dev/tty
|
|
echo ""
|
|
}
|
|
|
|
_main_menu
|