From e05386b0b5dc2837635c9d82e5a82cee0564f8f7 Mon Sep 17 00:00:00 2001 From: cupcakearmy Date: Thu, 6 May 2021 15:55:32 +0200 Subject: [PATCH] add failure and success hooks --- cmd/backup.go | 6 +++--- docs/markdown/location/hooks.md | 30 +++++++++++++++++++++++++---- internal/config.go | 25 ++++++++++++------------ internal/location.go | 34 +++++++++++++++++++++++++-------- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/cmd/backup.go b/cmd/backup.go index d9c67f0..8a02bc9 100644 --- a/cmd/backup.go +++ b/cmd/backup.go @@ -17,15 +17,15 @@ var backupCmd = &cobra.Command{ CheckErr(err) defer lock.Unlock() - CheckErr(internal.CheckConfig()) + internal.GetConfig() selected, err := internal.GetAllOrSelected(cmd, false) CheckErr(err) errors := 0 for _, name := range selected { location, _ := internal.GetLocation(name) - err := location.Backup(false) - if err != nil { + errs := location.Backup(false) + for err := range errs { colors.Error.Println(err) errors++ } diff --git a/docs/markdown/location/hooks.md b/docs/markdown/location/hooks.md index ecfb199..ed152e1 100644 --- a/docs/markdown/location/hooks.md +++ b/docs/markdown/location/hooks.md @@ -2,7 +2,14 @@ If you want to perform some commands before and/or after a backup, you can use hooks. -They consist of a list of `before`/`after` commands that will be executed in the same directory as the target `from`. +They consist of a list of commands that will be executed in the same directory as the target `from`. + +The following hooks groups are supported, none are required: + +- `before` +- `after` +- `failure` +- `success` ```yml | .autorestic.yml locations: @@ -11,10 +18,25 @@ locations: to: my-backend hooks: before: - - echo "Hello" - - echo "Human" + - echo "One" + - echo "Two" + - echo "Three" after: - - echo "kthxbye" + - echo "Byte" + failure: + - echo "Something went wrong" + success: + - echo "Well done!" ``` +## Flowchart + +1. `before` hook +2. Run backup +3. `after` hook +4. - `success` hook if no errors were found + - `failure` hook if at least error was encountered + +If the `before` hook encounters errors the backup and `after` hooks will be skipped and only the `failed` hooks will run. + > :ToCPrevNext diff --git a/internal/config.go b/internal/config.go index b9ff25b..cf0dc57 100644 --- a/internal/config.go +++ b/internal/config.go @@ -75,21 +75,22 @@ func (c *Config) Describe() { colors.PrintDescription("Cron", l.Cron) } - after, before := len(l.Hooks.After), len(l.Hooks.Before) - if after+before > 0 { - tmp = "" - if before > 0 { - tmp += "\tBefore" - for _, cmd := range l.Hooks.Before { - tmp += colors.Faint.Sprintf("\n\t ▶ %s", cmd) - } - } - if after > 0 { - tmp += "\n\tAfter" - for _, cmd := range l.Hooks.After { + tmp = "" + hooks := map[string][]string{ + "Before": l.Hooks.Before, + "After": l.Hooks.After, + "Failure": l.Hooks.Failure, + "Success": l.Hooks.Success, + } + for hook, commands := range hooks { + if len(commands) > 0 { + tmp += "\n\t" + hook + for _, cmd := range commands { tmp += colors.Faint.Sprintf("\n\t ▶ %s", cmd) } } + } + if tmp != "" { colors.PrintDescription("Hooks", tmp) } diff --git a/internal/location.go b/internal/location.go index 0a0edc3..2d16295 100644 --- a/internal/location.go +++ b/internal/location.go @@ -24,8 +24,10 @@ const ( type HookArray = []string type Hooks struct { - Before HookArray `yaml:"before"` - After HookArray `yaml:"after"` + Before HookArray `yaml:"before,omitempty"` + After HookArray `yaml:"after,omitempty"` + Success HookArray `yaml:"success,omitempty"` + Failure HookArray `yaml:"failure,omitempty"` } type Options map[string]map[string][]string @@ -133,7 +135,8 @@ func (l Location) getPath() (string, error) { return "", fmt.Errorf("could not get path for location \"%s\"", l.name) } -func (l Location) Backup(cron bool) error { +func (l Location) Backup(cron bool) []error { + var errors []error colors.PrimaryPrint(" Backing up location \"%s\" ", l.name) t := l.getType() options := ExecuteOptions{ @@ -147,7 +150,8 @@ func (l Location) Backup(cron bool) error { // Hooks if err := ExecuteHooks(l.Hooks.Before, options); err != nil { - return err + errors = append(errors, err) + goto after } // Backup @@ -156,7 +160,8 @@ func (l Location) Backup(cron bool) error { colors.Secondary.Printf("Backend: %s\n", backend.name) env, err := backend.getEnv() if err != nil { - return nil + errors = append(errors, err) + continue } flags := l.getOptions("backup") @@ -181,7 +186,8 @@ func (l Location) Backup(cron bool) error { } if err != nil { colors.Error.Println(out) - return err + errors = append(errors, err) + continue } if VERBOSE { colors.Faint.Println(out) @@ -190,10 +196,22 @@ func (l Location) Backup(cron bool) error { // After hooks if err := ExecuteHooks(l.Hooks.After, options); err != nil { - return err + errors = append(errors, err) } + +after: + var commands []string + if len(errors) > 0 { + commands = l.Hooks.Failure + } else { + commands = l.Hooks.Success + } + if err := ExecuteHooks(commands, options); err != nil { + errors = append(errors, err) + } + colors.Success.Println("Done") - return nil + return errors } func (l Location) Forget(prune bool, dry bool) error {