#!/usr/bin/env bash set -euo pipefail log() { echo -e "\033[0;34m[INFO]\033[0m $*"; } warn() { echo -e "\033[1;33m[WARN]\033[0m $*"; } err() { echo -e "\033[0;31m[ERR ]\033[0m $*" >&2; } require_cmd() { local miss=0 for c in "$@"; do if ! command -v "$c" >/dev/null 2>&1; then err "missing command: $c"; miss=1; fi done [[ $miss -eq 0 ]] } today_version() { date +%Y%m%d; } checksum_dir() { local dir="$1"; local out="$2"; : > "$out"; (cd "$dir" && find . -type f -print0 | sort -z | xargs -0 sha256sum) >> "$out" } make_dir() { mkdir -p "$1"; } copy_tree() { local src="$1" dst="$2"; rsync -a --delete "$src/" "$dst/" 2>/dev/null || cp -r "$src/." "$dst/"; } gen_manifest() { local root="$1"; local out="$2"; : > "$out"; (cd "$root" && find . -maxdepth 4 -type f -printf "%p\n" | sort) >> "$out" }