Skip to content

Commit 4375a38

Browse files
author
Romain de Laage
committed
Add restore hooks feature
1 parent 4d9a2b8 commit 4375a38

File tree

3 files changed

+93
-36
lines changed

3 files changed

+93
-36
lines changed

cmd/restore.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55

66
"github.com/cupcakearmy/autorestic/internal"
7+
"github.com/cupcakearmy/autorestic/internal/colors"
78
"github.com/cupcakearmy/autorestic/internal/lock"
89
"github.com/spf13/cobra"
910
)
@@ -42,8 +43,13 @@ var restoreCmd = &cobra.Command{
4243
}
4344
}
4445

45-
err = l.Restore(target, from, force, snapshot, optional)
46-
CheckErr(err)
46+
errs := l.Restore(target, from, force, snapshot, optional)
47+
for _, err := range errs {
48+
colors.Error.Printf("%s\n\n", err)
49+
}
50+
if len(errs) > 0 {
51+
CheckErr(fmt.Errorf("%d errors were found", len(errs)))
52+
}
4753
},
4854
}
4955

internal/config.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func GetConfig() *Config {
8383
exitConfig(nil, "version specified in config file is not an int")
8484
} else {
8585
// Check for version
86-
if version != 2 {
86+
if version != 3 {
8787
exitConfig(nil, "unsupported config version number. please check the docs for migration\nhttps://autorestic.vercel.app/migration/")
8888
}
8989
}
@@ -132,10 +132,14 @@ func (c *Config) Describe() {
132132

133133
tmp = ""
134134
hooks := map[string][]string{
135-
"Before": l.Hooks.Before,
136-
"After": l.Hooks.After,
137-
"Failure": l.Hooks.Failure,
138-
"Success": l.Hooks.Success,
135+
"Before backup": l.Hooks.BackupOption.Before,
136+
"After backup": l.Hooks.BackupOption.After,
137+
"Failure backup": l.Hooks.BackupOption.Failure,
138+
"Success backup": l.Hooks.BackupOption.Success,
139+
"Before restore": l.Hooks.RestoreOption.Before,
140+
"After restore": l.Hooks.RestoreOption.After,
141+
"Failure restore": l.Hooks.RestoreOption.Failure,
142+
"Success restore": l.Hooks.RestoreOption.Success,
139143
}
140144
for hook, commands := range hooks {
141145
if len(commands) > 0 {

internal/location.go

+76-29
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,30 @@ const (
3333
)
3434

3535
type Hooks struct {
36+
RestoreOption HooksList `mapstructure:"restore,omitempty"`
37+
BackupOption HooksList `mapstructure:"backup,omitempty"`
38+
}
39+
40+
type LocationCopy = map[string][]string
41+
42+
type HooksList struct {
3643
Dir string `mapstructure:"dir"`
3744
Before HookArray `mapstructure:"before,omitempty"`
3845
After HookArray `mapstructure:"after,omitempty"`
3946
Success HookArray `mapstructure:"success,omitempty"`
4047
Failure HookArray `mapstructure:"failure,omitempty"`
4148
}
4249

43-
type LocationCopy = map[string][]string
44-
4550
type Location struct {
46-
name string `mapstructure:",omitempty"`
47-
From []string `mapstructure:"from,omitempty"`
48-
Type string `mapstructure:"type,omitempty"`
49-
To []string `mapstructure:"to,omitempty"`
50-
Hooks Hooks `mapstructure:"hooks,omitempty"`
51-
Cron string `mapstructure:"cron,omitempty"`
52-
Options Options `mapstructure:"options,omitempty"`
53-
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"`
54-
CopyOption LocationCopy `mapstructure:"copy,omitempty"`
51+
name string `mapstructure:",omitempty"`
52+
From []string `mapstructure:"from,omitempty"`
53+
Type string `mapstructure:"type,omitempty"`
54+
To []string `mapstructure:"to,omitempty"`
55+
Hooks Hooks `mapstructure:"hooks,omitempty"`
56+
Cron string `mapstructure:"cron,omitempty"`
57+
Options Options `mapstructure:"options,omitempty"`
58+
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"`
59+
CopyOption LocationCopy `mapstructure:"copy,omitempty"`
5560
}
5661

5762
func GetLocation(name string) (Location, bool) {
@@ -123,12 +128,12 @@ func (l Location) validate() error {
123128
return nil
124129
}
125130

126-
func (l Location) ExecuteHooks(commands []string, options ExecuteOptions) error {
131+
func (l Location) ExecuteHooks(commands []string, directory string, options ExecuteOptions) error {
127132
if len(commands) == 0 {
128133
return nil
129134
}
130-
if l.Hooks.Dir != "" {
131-
if dir, err := GetPathRelativeToConfig(l.Hooks.Dir); err != nil {
135+
if directory != "" {
136+
if dir, err := GetPathRelativeToConfig(directory); err != nil {
132137
return err
133138
} else {
134139
options.Dir = dir
@@ -190,7 +195,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
190195
}
191196

192197
// Hooks
193-
if err := l.ExecuteHooks(l.Hooks.Before, options); err != nil {
198+
if err := l.ExecuteHooks(l.Hooks.BackupOption.Before, l.Hooks.BackupOption.Dir, options); err != nil {
194199
errors = append(errors, err)
195200
goto after
196201
}
@@ -290,19 +295,19 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
290295
}
291296

292297
// After hooks
293-
if err := l.ExecuteHooks(l.Hooks.After, options); err != nil {
298+
if err := l.ExecuteHooks(l.Hooks.BackupOption.After, l.Hooks.BackupOption.Dir, options); err != nil {
294299
errors = append(errors, err)
295300
}
296301

297302
after:
298303
var commands []string
299304
var isSuccess = len(errors) == 0
300305
if isSuccess {
301-
commands = l.Hooks.Success
306+
commands = l.Hooks.BackupOption.Success
302307
} else {
303-
commands = l.Hooks.Failure
308+
commands = l.Hooks.BackupOption.Failure
304309
}
305-
if err := l.ExecuteHooks(commands, options); err != nil {
310+
if err := l.ExecuteHooks(commands, l.Hooks.BackupOption.Dir, options); err != nil {
306311
errors = append(errors, err)
307312
}
308313

@@ -367,11 +372,35 @@ func buildRestoreCommand(l Location, to string, snapshot string, options []strin
367372
return base
368373
}
369374

370-
func (l Location) Restore(to, from string, force bool, snapshot string, options []string) error {
375+
func (l Location) Restore(to, from string, force bool, snapshot string, options []string) (errors []error) {
376+
cwd, _ := GetPathRelativeToConfig(".")
377+
hooksOptions := ExecuteOptions{
378+
Command: "bash",
379+
Dir: cwd,
380+
Envs: map[string]string{
381+
"AUTORESTIC_LOCATION": l.name,
382+
},
383+
}
384+
385+
defer func() {
386+
var commands []string
387+
var isSuccess = len(errors) == 0
388+
if isSuccess {
389+
commands = l.Hooks.RestoreOption.Success
390+
} else {
391+
commands = l.Hooks.RestoreOption.Failure
392+
}
393+
if err := l.ExecuteHooks(commands, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
394+
errors = append(errors, err)
395+
}
396+
397+
colors.Success.Println("Done")
398+
}()
399+
371400
if from == "" {
372401
from = l.To[0]
373402
} else if !l.hasBackend(from) {
374-
return fmt.Errorf("invalid backend: \"%s\"", from)
403+
errors = append(errors, fmt.Errorf("invalid backend: \"%s\"", from))
375404
}
376405

377406
if snapshot == "" {
@@ -382,15 +411,23 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
382411
backend, _ := GetBackend(from)
383412
colors.Secondary.Printf("Restoring %s@%s → %s\n", snapshot, backend.name, to)
384413

414+
// Before Hooks for restore
415+
if err := l.ExecuteHooks(l.Hooks.RestoreOption.Before, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
416+
errors = append(errors, err)
417+
return
418+
}
419+
385420
t, err := l.getType()
386421
if err != nil {
387-
return err
422+
errors = append(errors, err)
423+
return
388424
}
389425
switch t {
390426
case TypeLocal:
391427
to, err = filepath.Abs(to)
392428
if err != nil {
393-
return err
429+
errors = append(errors, err)
430+
return
394431
}
395432
// Check if target is empty
396433
if !force {
@@ -399,14 +436,17 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
399436
if err == nil {
400437
files, err := ioutil.ReadDir(to)
401438
if err != nil {
402-
return err
439+
errors = append(errors, err)
440+
return
403441
}
404442
if len(files) > 0 {
405-
return notEmptyError
443+
errors = append(errors, notEmptyError)
444+
return
406445
}
407446
} else {
408447
if !os.IsNotExist(err) {
409-
return err
448+
errors = append(errors, err)
449+
return
410450
}
411451
}
412452
}
@@ -415,10 +455,17 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
415455
_, _, err = backend.ExecDocker(l, buildRestoreCommand(l, "/", snapshot, options))
416456
}
417457
if err != nil {
418-
return err
458+
errors = append(errors, err)
459+
return
419460
}
420-
colors.Success.Println("Done")
421-
return nil
461+
462+
// After Hooks for restore
463+
if err := l.ExecuteHooks(l.Hooks.RestoreOption.After, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
464+
errors = append(errors, err)
465+
return
466+
}
467+
468+
return
422469
}
423470

424471
func (l Location) RunCron() error {

0 commit comments

Comments
 (0)