diff --git a/cmd/restore.go b/cmd/restore.go new file mode 100644 index 0000000..4b7c91a --- /dev/null +++ b/cmd/restore.go @@ -0,0 +1,52 @@ +/* +Copyright © 2021 NAME HERE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + + "github.com/cupcakearmy/autorestic/internal" + "github.com/spf13/cobra" +) + +// restoreCmd represents the restore command +var restoreCmd = &cobra.Command{ + Use: "restore", + Short: "Restore backup for location", + Run: func(cmd *cobra.Command, args []string) { + config := internal.GetConfig() + location, _ := cmd.Flags().GetString("location") + l, ok := config.Locations[location] + if !ok { + cobra.CheckErr(fmt.Errorf("invalid location \"%s\"", location)) + } + target, _ := cmd.Flags().GetString("to") + from, _ := cmd.Flags().GetString("from") + force, _ := cmd.Flags().GetBool("force") + err := l.Restore(target, from, force) + cobra.CheckErr(err) + }, +} + +func init() { + rootCmd.AddCommand(restoreCmd) + restoreCmd.Flags().BoolP("force", "f", false, "Force, target folder will be overwritten") + restoreCmd.Flags().String("from", "", "Which backend to use") + restoreCmd.Flags().String("to", "", "Where to restore the data") + restoreCmd.MarkFlagRequired("to") + restoreCmd.Flags().StringP("location", "l", "", "Location to be restored") + restoreCmd.MarkFlagRequired("location") +} diff --git a/internal/location.go b/internal/location.go index 74ab21e..d256572 100644 --- a/internal/location.go +++ b/internal/location.go @@ -2,6 +2,9 @@ package internal import ( "fmt" + "io/ioutil" + "os" + "path/filepath" ) type HookArray = []string @@ -107,3 +110,53 @@ func (l Location) Forget(prune bool) error { } return nil } + +func (l Location) hasBackend(backend string) bool { + for _, b := range l.To { + if b == backend { + return true + } + } + return false +} + +func (l Location) Restore(to, from string, force bool) error { + if from == "" { + from = l.To[0] + } else if !l.hasBackend(from) { + return fmt.Errorf("invalid backend: \"%s\"", from) + } + + to, err := filepath.Abs(to) + if err != nil { + return err + } + fmt.Printf("Restoring location to %s using %s.\n", to, from) + + // Check if target is empty + if !force { + notEmptyError := fmt.Errorf("target %s is not empty", to) + _, err = os.Stat(to) + if err == nil { + files, err := ioutil.ReadDir(to) + if err != nil { + return err + } + if len(files) > 0 { + return notEmptyError + } + } else { + if !os.IsNotExist(err) { + return err + } + } + } + + c := GetConfig() + backend := c.Backends[from] + err = backend.Exec([]string{"restore", "--target", to, "--path", GetPathRelativeToConfig(l.From), "latest"}) + if err != nil { + return err + } + return nil +}