#!/bin/sh # migrate-toplevel-peers.sh — migrate a ZDDC root from the old # "everything under archive//" layout to the flat top-level # party-peer layout. # # Per project (a top-level dir containing archive/), for each # archive//: # - move archive//{incoming,working,staging,reviewing,mdl,rsk} # → /// (the workspace/register peers) # - move archive//ssr.yaml → /ssr/.yaml # (this establishes the party registry — a party exists iff its # ssr/.yaml exists) # - if a party has no ssr.yaml, synthesize a minimal ssr/.yaml # so it stays registered (else its workspaces can't be recreated) # - LEAVE archive//{received,issued} in place (the WORM record) # # Then, tree-wide, relocate any table.yaml / form.yaml config out of a # directory root and into that directory's .zddc.d/ reserve (where the # server now resolves specs from; the legacy root location still works, so # this is a declutter, not a hard requirement). # # Per-folder .zddc files travel with their directory (the whole slot dir # is moved). Idempotent: already-migrated paths are skipped. Run with the # server stopped (or accept it's a plain filesystem move). # # Usage: # migrate-toplevel-peers.sh [--dry-run] # # --dry-run prints what would happen and changes nothing. set -eu DRY=0 ROOT="" for arg in "$@"; do case "$arg" in --dry-run) DRY=1 ;; -h|--help) sed -n '2,30p' "$0" | sed 's/^# \{0,1\}//' exit 0 ;; -*) echo "unknown flag: $arg" >&2 exit 2 ;; *) ROOT="$arg" ;; esac done if [ -z "$ROOT" ] || [ ! -d "$ROOT" ]; then echo "usage: $0 [--dry-run] " >&2 exit 2 fi WORKSPACE_SLOTS="incoming working staging reviewing mdl rsk" moved=0 synth=0 skipped=0 say() { printf '%s\n' "$*"; } act() { # act desc=$1 shift if [ "$DRY" -eq 1 ]; then say "DRY $desc" else say " -> $desc" "$@" fi } # move_dir SRC DST — move a directory, creating DST's parent. Skips when # SRC is absent (nothing to do) or DST already exists (already migrated). move_dir() { src=$1 dst=$2 [ -d "$src" ] || return 0 if [ -e "$dst" ]; then say " .. skip (dest exists): $dst" skipped=$((skipped + 1)) return 0 fi parent=$(dirname "$dst") act "mkdir -p $parent" mkdir -p "$parent" act "mv $src -> $dst" mv "$src" "$dst" moved=$((moved + 1)) } # move_file SRC DST — same shape, for the ssr.yaml registry row. move_file() { src=$1 dst=$2 [ -f "$src" ] || return 0 if [ -e "$dst" ]; then say " .. skip (dest exists): $dst" skipped=$((skipped + 1)) return 0 fi parent=$(dirname "$dst") act "mkdir -p $parent" mkdir -p "$parent" act "mv $src -> $dst" mv "$src" "$dst" moved=$((moved + 1)) } synth_registry() { dst=$1 [ -e "$dst" ] && return 0 parent=$(dirname "$dst") act "mkdir -p $parent" mkdir -p "$parent" if [ "$DRY" -eq 1 ]; then say "DRY synthesize $dst (kind: SSR)" else say " -> synthesize $dst (kind: SSR)" printf 'kind: SSR\n' >"$dst" fi synth=$((synth + 1)) } # relocate_configs — move every /table.yaml and /form.yaml into # /.zddc.d/. Tree-wide; skips files already under a .zddc.d/ and any # destination that already exists. Uses find | while-read so directory names # with spaces are handled (counters live in the subshell, so this pass just # logs its actions rather than feeding the summary). relocate_configs() { find "$ROOT" -type f \( -name table.yaml -o -name form.yaml \) 2>/dev/null | while IFS= read -r f; do case "$f" in */.zddc.d/*) continue ;; esac d=$(dirname "$f") base=$(basename "$f") dst="$d/.zddc.d/$base" if [ -e "$dst" ]; then say " .. skip (dest exists): $dst" continue fi act "mkdir -p $d/.zddc.d" mkdir -p "$d/.zddc.d" act "mv $f -> $dst" mv "$f" "$dst" done } for projectdir in "$ROOT"/*/; do [ -d "$projectdir/archive" ] || continue project=$(basename "$projectdir") case "$project" in .* | _*) continue ;; esac say "project: $project" for partydir in "$projectdir"archive/*/; do [ -d "$partydir" ] || continue party=$(basename "$partydir") case "$party" in .* | _*) continue ;; esac say " party: $party" # 1. Registry row: archive//ssr.yaml -> ssr/.yaml move_file "${partydir}ssr.yaml" "${projectdir}ssr/${party}.yaml" # 2. Workspace/register slots -> // for slot in $WORKSPACE_SLOTS; do move_dir "${partydir}${slot}" "${projectdir}${slot}/${party}" done # 3. Guarantee a registry entry so the party stays registered. synth_registry "${projectdir}ssr/${party}.yaml" done done # Tree-wide config relocation (runs over the now-migrated layout). say "" say "relocating table.yaml/form.yaml configs into .zddc.d/ …" relocate_configs say "" say "summary: moved=$moved synthesized=$synth skipped=$skipped" [ "$DRY" -eq 1 ] && say "(dry-run — nothing changed)" exit 0