/* Restore from a series of restic snapshots. */ package main import ( "fmt" "os" "io" "log" "strings" "slices" ) type Snapshot struct { id string dirs []string } func main() { body, err := io.ReadAll(os.Stdin) if err != nil { log.Fatal(err) } var shots []Snapshot var current Snapshot lines := strings.Split(string(body), "\n") for _, s := range lines[2:len(lines) - 3] { split := strings.Split(s, " ") if len(s) == 0 { shots = append(shots, current) // Old snapshot is garbage collected. current = Snapshot{} } else if s[0] == ' ' { // Directory at the end of line. current.dirs = append(current.dirs, split[len(split) - 1]) } else { // New snapshot. current.id = split[0] current.dirs = []string{split[len(split) - 1]} } } // Last not followed by blank line. shots = append(shots, current) /* for _, shot := range shots { fmt.Println(shot.id) for _, dir := range shot.dirs { fmt.Println("\t" + dir) } } */ /* Traverse through the snapshots in reverse order. The earlier entries covered by current are removed. */ seen := []string{} list := make(map[string]string) for i := len(shots) - 1; i >= 0; i-- { for _, dir := range(shots[i].dirs) { if !slices.Contains(seen, dir) { seen = append(seen, dir) list[shots[i].id] += dir + "," } } } for id, paths := range list { for _, dir := range strings.Split(paths, ",") { if dir != "" { fmt.Println("restic restore " + id + ":" + dir + " --overwrite=if-newer --target=" + dir) } } } }