Files
hyperguild/ingestion/cmd/legacymove/main.go
T
mathiasandClaude Sonnet 5.5 e5f8947f3b feat(legacymove): clear the retired wiki/sources layout with an archive and a rollback (#209)
Videos and articles move to the default wing (wing/hall stamped, body and
links byte-preserved); auto-tunnel review logs are deleted; notes, projects and
untyped pages stay. Plan is read-only; Apply archives every page it touches to
archive/wing-migration-<date>/ (outside raw/) before changing anything,
creates destinations O_EXCL and removes sources only after; Rollback restores
byte for byte. concepts/ and entities/ are the shared layer and are untouched.
Dry run against the live brain: 16 move, 24 delete, 15 left.
Mutation-checked: junk guard, type filter, slug collision, no-overwrite,
archive-before-change, action gate.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 20:24:03 +02:00

60 lines
1.9 KiB
Go

// Command legacymove clears wiki/sources/ of the retired layout (hyperguild
// #209). Default is a dry run that prints the plan; -apply performs it after
// archiving every page it touches; -rollback restores from an archive.
package main
import (
"flag"
"fmt"
"log/slog"
"os"
"strings"
"time"
"github.com/mathiasbq/hyperguild/ingestion/internal/legacymove"
)
func main() {
brain := flag.String("brain", "/var/lib/supervisor/brain", "brain directory")
wing := flag.String("wing", "web-clip", "wing that receives video and article sources")
apply := flag.Bool("apply", false, "perform the plan (default: dry run)")
rollback := flag.String("rollback", "", "restore from this archive dir (brain-relative, e.g. archive/wing-migration-2026-10-20)")
flag.Parse()
if err := run(*brain, *wing, *apply, *rollback); err != nil {
slog.Error("legacymove", "err", err)
os.Exit(1)
}
}
func run(brain, wing string, apply bool, rollback string) error {
if rollback != "" {
if err := legacymove.Rollback(brain, rollback); err != nil {
return err
}
fmt.Println("rolled back from", rollback)
return nil
}
items, err := legacymove.Plan(brain, wing)
if err != nil {
return err
}
counts := map[legacymove.Action]int{}
for _, it := range items {
counts[it.Action]++
}
fmt.Printf("# legacy source plan\n\n%d pages: %d move, %d delete, %d left\n\n", len(items), counts[legacymove.Move], counts[legacymove.Delete], counts[legacymove.Skip])
fmt.Println("| action | from | to | why |")
fmt.Println("|---|---|---|---|")
for _, it := range items {
fmt.Printf("| %s | %s | %s | %s |\n", it.Action, it.From, it.To, strings.ReplaceAll(it.Reason, "|", "/"))
}
if !apply {
fmt.Println("\n_dry run: nothing was changed_")
return nil
}
res, err := legacymove.Apply(brain, items, time.Now())
fmt.Printf("\nmoved %d, deleted %d; archive: %s\n", res.Moved, res.Deleted, res.ArchiveDir)
return err
}