From fbb36bc94ac6eaba7fd346314a9c43d27cb5348d Mon Sep 17 00:00:00 2001 From: bel Date: Sat, 1 Feb 2020 22:24:08 +0000 Subject: [PATCH] Add restore, backup, list, and clean commands --- README.md | 0 main.go | 109 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 98 insertions(+), 11 deletions(-) mode change 100644 => 100755 README.md mode change 100644 => 100755 main.go diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/main.go b/main.go old mode 100644 new mode 100755 index 061d52c..f97e821 --- a/main.go +++ b/main.go @@ -1,7 +1,9 @@ package main import ( + "bytes" "fmt" + "io" "io/ioutil" "local/args" "local/storage" @@ -21,20 +23,42 @@ type Config struct { ns string root string store string + cmd string +} + +type LastN struct { + store storage.DB + conf Config } func main() { conf := config() log.Println(conf) - store, err := storage.New(storage.TypeFromString(conf.store), conf.conf, path.Join(conf.rclone+":", conf.ns)) + storage, err := storage.New(storage.TypeFromString(conf.store), conf.conf, path.Join(conf.rclone+":", conf.ns)) if err != nil { panic(err) } - if err := push(conf.root, store); err != nil { - panic(err) + lastn := &LastN{ + conf: conf, + store: storage, } - if err := clean(conf.n, store); err != nil { - panic(err) + actions := []func() error{} + switch conf.cmd { + case "backup": + actions = append(actions, lastn.push, lastn.clean) + case "list": + actions = append(actions, lastn.list) + case "clean": + actions = append(actions, lastn.clean) + case "restore": + actions = append(actions, lastn.restore) + default: + panic(fmt.Sprintf("not impl: %s")) + } + for _, action := range actions { + if err := action(); err != nil { + panic(err) + } } } @@ -46,20 +70,28 @@ func config() Config { as.Append(args.STRING, "ns", "ns for backups", path.Join("lastn", "dev")) as.Append(args.STRING, "rclone", "rclone backend name", "blapointe-drive-enc") as.Append(args.STRING, "store", "type of store, like [map rclone]", "map") + as.Append(args.STRING, "cmd", "[backup, restore, list, clean]", "backup") if err := as.Parse(); err != nil { panic(err) } + root, err := filepath.Abs(as.Get("root").GetString()) + if err != nil { + panic(err) + } return Config{ n: as.Get("n").GetInt(), conf: as.Get("conf").GetString(), rclone: as.Get("rclone").GetString(), - root: as.Get("root").GetString(), + root: root, ns: as.Get("ns").GetString(), store: as.Get("store").GetString(), + cmd: as.Get("cmd").GetString(), } } -func push(root string, store storage.DB) error { +func (lastN *LastN) push() error { + root := lastN.conf.root + store := lastN.store root, err := filepath.Abs(root) if err != nil { return err @@ -73,11 +105,11 @@ func push(root string, store storage.DB) error { ) cmd := exec.Command( "tar", - "-C", - path.Dir(root), "-czf", archive, - root, + "-C", + path.Dir(root), + path.Base(root), ) out, err := cmd.CombinedOutput() if err != nil { @@ -91,7 +123,9 @@ func push(root string, store storage.DB) error { return store.Set(path.Base(archive), b) } -func clean(n int, store storage.DB) error { +func (lastN *LastN) clean() error { + n := lastN.conf.n + store := lastN.store backups, err := store.List(nil) if err != nil { return err @@ -106,3 +140,56 @@ func clean(n int, store storage.DB) error { } return nil } + +func (lastN *LastN) list() error { + store := lastN.store + backups, err := store.List(nil) + if err != nil { + return err + } + sort.Strings(backups) + for _, backup := range backups { + log.Println(backup) + } + return nil +} + +func (lastN *LastN) restore() error { + root := lastN.conf.root + "-restore" + os.RemoveAll(root) + if err := os.MkdirAll(root, os.ModePerm); err != nil { + return err + } + store := lastN.store + backups, err := store.List(nil) + if err != nil { + return fmt.Errorf("cannot list: %v", err) + } + sort.Strings(backups) + backup := backups[len(backups)-1] + b, err := store.Get(backup) + if err != nil { + return fmt.Errorf("cannot get %s: %v", backup, err) + } + log.Printf("restoring %s (%v) in %s", backup, len(b), root) + cmd := exec.Command( + "tar", + "-C", + root, + "-xzf", + "-", + ) + stdin, err := cmd.StdinPipe() + if err != nil { + return fmt.Errorf("cannot get stdin: %v", err) + } + go func() { + defer stdin.Close() + io.Copy(stdin, bytes.NewReader(b)) + }() + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed tar -xf: %v: %s", err, out) + } + return nil +}