diff --git a/.gitignore b/.gitignore index ef64b27..cb81dcf 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ **.sw* +lastn **/testdata **/._* **/exec-* diff --git a/main.go b/main.go new file mode 100644 index 0000000..061d52c --- /dev/null +++ b/main.go @@ -0,0 +1,108 @@ +package main + +import ( + "fmt" + "io/ioutil" + "local/args" + "local/storage" + "log" + "os" + "os/exec" + "path" + "path/filepath" + "sort" + "time" +) + +type Config struct { + n int + conf string + rclone string + ns string + root string + store string +} + +func main() { + conf := config() + log.Println(conf) + store, 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) + } + if err := clean(conf.n, store); err != nil { + panic(err) + } +} + +func config() Config { + as := args.NewArgSet() + as.Append(args.INT, "n", "number of backups to retain", 5) + as.Append(args.STRING, "conf", "path to rclone conf", path.Join(os.Getenv("HOME"), "/.config/rclone/rclone.conf")) + as.Append(args.STRING, "root", "path to root", "./public") + 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") + if err := as.Parse(); 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(), + ns: as.Get("ns").GetString(), + store: as.Get("store").GetString(), + } +} + +func push(root string, store storage.DB) error { + root, err := filepath.Abs(root) + if err != nil { + return err + } + archive := path.Join( + os.TempDir(), + fmt.Sprintf( + "%s.tar", + time.Now().Format("2006.01.02.15.04.05"), + ), + ) + cmd := exec.Command( + "tar", + "-C", + path.Dir(root), + "-czf", + archive, + root, + ) + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("%v: %s", err, out) + } + b, err := ioutil.ReadFile(archive) + if err != nil { + return err + } + log.Println("Created backup", path.Base(archive)) + return store.Set(path.Base(archive), b) +} + +func clean(n int, store storage.DB) error { + backups, err := store.List(nil) + if err != nil { + return err + } + sort.Strings(backups) + for i := 0; i < len(backups)-n; i++ { + log.Println("Pruning old backup", backups[i]) + err := store.Set(backups[i], nil) + if err != nil { + return err + } + } + return nil +}