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>
60 lines
1.9 KiB
Go
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
|
|
}
|