mirror of
https://github.com/cupcakearmy/autorestic.git
synced 2025-09-07 19:10:39 +00:00
Compare commits
10 Commits
v1.7.6
...
f7a20a1210
Author | SHA1 | Date | |
---|---|---|---|
|
f7a20a1210 | ||
|
3b57602fe8 | ||
|
045513234f | ||
|
78b0db50e0 | ||
|
62dd371d51 | ||
|
08766b75db | ||
b3b7c8df95 | |||
2c5266c9a0 | |||
|
f43cc32ac3 | ||
|
4375a38bba |
21
.github/workflows/build.yml
vendored
21
.github/workflows/build.yml
vendored
@@ -10,12 +10,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Docker Labels
|
||||
id: meta
|
||||
uses: crazy-max/ghaction-docker-meta@v2
|
||||
uses: crazy-max/ghaction-docker-meta@v4
|
||||
with:
|
||||
images: cupcakearmy/autorestic
|
||||
tags: |
|
||||
@@ -23,12 +23,12 @@ jobs:
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
@@ -37,17 +37,12 @@ jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "^1.16.3"
|
||||
go-version: "^1.20"
|
||||
- name: Build
|
||||
run: go run build/build.go
|
||||
|
||||
- name: Sign
|
||||
uses: tristan-weil/ghaction-checksum-sign-artifact@v1.0.1
|
||||
with:
|
||||
path: dist/*
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
|
@@ -4,7 +4,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -31,12 +35,37 @@ type buildOptions struct {
|
||||
Target, Arch, Version string
|
||||
}
|
||||
|
||||
func build(options buildOptions, wg *sync.WaitGroup) {
|
||||
fmt.Printf("Building %s %s\n", options.Target, options.Arch)
|
||||
const (
|
||||
CHECKSUM_MD5 = "MD5SUMS"
|
||||
CHECKSUM_SHA_1 = "SHA1SUMS"
|
||||
CHECKSUM_SHA_256 = "SHA256SUMS"
|
||||
)
|
||||
|
||||
type Checksums struct {
|
||||
filename, md5, sha1, sha256 string
|
||||
}
|
||||
|
||||
func writeChecksums(checksums *[]Checksums) {
|
||||
FILE_MD5, _ := os.OpenFile(path.Join(DIR, CHECKSUM_MD5), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
|
||||
defer FILE_MD5.Close()
|
||||
FILE_SHA1, _ := os.OpenFile(path.Join(DIR, CHECKSUM_SHA_1), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
|
||||
defer FILE_SHA1.Close()
|
||||
FILE_SHA256, _ := os.OpenFile(path.Join(DIR, CHECKSUM_SHA_256), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
|
||||
defer FILE_SHA256.Close()
|
||||
|
||||
for _, checksum := range *checksums {
|
||||
fmt.Fprintf(FILE_MD5, "%s %s\n", checksum.md5, checksum.filename)
|
||||
fmt.Fprintf(FILE_SHA1, "%s %s\n", checksum.sha1, checksum.filename)
|
||||
fmt.Fprintf(FILE_SHA256, "%s %s\n", checksum.sha256, checksum.filename)
|
||||
}
|
||||
}
|
||||
|
||||
func build(options buildOptions, wg *sync.WaitGroup, checksums *[]Checksums) {
|
||||
defer wg.Done()
|
||||
|
||||
fmt.Printf("Building: %s %s\n", options.Target, options.Arch)
|
||||
out := fmt.Sprintf("autorestic_%s_%s_%s", options.Version, options.Target, options.Arch)
|
||||
out = path.Join(DIR, out)
|
||||
out, _ = filepath.Abs(out)
|
||||
fmt.Println(out)
|
||||
|
||||
// Build
|
||||
{
|
||||
@@ -65,22 +94,39 @@ func build(options buildOptions, wg *sync.WaitGroup) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
|
||||
// Checksum
|
||||
{
|
||||
file := out + ".bz2"
|
||||
content, _ := ioutil.ReadFile(file)
|
||||
*checksums = append(*checksums, Checksums{
|
||||
filename: path.Base(file),
|
||||
md5: fmt.Sprintf("%x", md5.Sum(content)),
|
||||
sha1: fmt.Sprintf("%x", sha1.Sum(content)),
|
||||
sha256: fmt.Sprintf("%x", sha256.Sum256(content)),
|
||||
})
|
||||
}
|
||||
|
||||
fmt.Printf("Built: %s\n", path.Base(out))
|
||||
}
|
||||
|
||||
func main() {
|
||||
os.RemoveAll(DIR)
|
||||
v := internal.VERSION
|
||||
checksums := []Checksums{}
|
||||
|
||||
// Build async
|
||||
var wg sync.WaitGroup
|
||||
for target, archs := range targets {
|
||||
for _, arch := range archs {
|
||||
wg.Add(1)
|
||||
build(buildOptions{
|
||||
go build(buildOptions{
|
||||
Target: target,
|
||||
Arch: arch,
|
||||
Version: v,
|
||||
}, &wg)
|
||||
}, &wg, &checksums)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
writeChecksums(&checksums)
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cupcakearmy/autorestic/internal"
|
||||
"github.com/cupcakearmy/autorestic/internal/colors"
|
||||
"github.com/cupcakearmy/autorestic/internal/lock"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -42,8 +43,13 @@ var restoreCmd = &cobra.Command{
|
||||
}
|
||||
}
|
||||
|
||||
err = l.Restore(target, from, force, snapshot, optional)
|
||||
CheckErr(err)
|
||||
errs := l.Restore(target, from, force, snapshot, optional)
|
||||
for _, err := range errs {
|
||||
colors.Error.Printf("%s\n\n", err)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
CheckErr(fmt.Errorf("%d errors were found", len(errs)))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -55,7 +55,7 @@ func initConfig() {
|
||||
viper.SetConfigFile(cfgFile)
|
||||
viper.AutomaticEnv()
|
||||
if viper.ConfigFileUsed() == "" {
|
||||
colors.Error.Println("cannot read config file %s\n", cfgFile)
|
||||
colors.Error.Printf("cannot read config file %s\n", cfgFile)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
|
12
docs/.codedoc/package-lock.json
generated
12
docs/.codedoc/package-lock.json
generated
@@ -2618,9 +2618,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
||||
"version": "5.76.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
|
||||
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^0.0.51",
|
||||
@@ -4812,9 +4812,9 @@
|
||||
"integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
||||
"version": "5.76.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
|
||||
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^0.0.51",
|
||||
|
@@ -45,6 +45,7 @@
|
||||
>
|
||||
> [0.x → 1.0](/migration/0.x_1.0)
|
||||
> [1.4 → 1.5](/migration/1.4_1.5)
|
||||
> [1.7 → 1.8](/migration/1.7_1.8)
|
||||
|
||||
[Examples](/examples)
|
||||
[Docker](/docker)
|
||||
|
@@ -55,10 +55,11 @@ version: 2
|
||||
|
||||
extras:
|
||||
hooks: &foo
|
||||
before:
|
||||
- echo "Hello"
|
||||
after:
|
||||
- echo "kthxbye"
|
||||
backup:
|
||||
before:
|
||||
- echo "Hello"
|
||||
after:
|
||||
- echo "kthxbye"
|
||||
policies: &bar
|
||||
keep-daily: 14
|
||||
keep-weekly: 52
|
||||
|
@@ -22,12 +22,13 @@ autorestic exec -b my-backend -- unlock
|
||||
extras:
|
||||
healthchecks: &healthchecks
|
||||
hooks:
|
||||
before:
|
||||
- 'curl -m 10 --retry 5 -X POST -H "Content-Type: text/plain" --data "Starting backup for location: ${AUTORESTIC_LOCATION}" https://<healthchecks-url>/ping/<uid>/start'
|
||||
failure:
|
||||
- 'curl -m 10 --retry 5 -X POST -H "Content-Type: text/plain" --data "Backup failed for location: ${AUTORESTIC_LOCATION}" https://<healthchecks-url>/ping/<uid>/fail'
|
||||
success:
|
||||
- 'curl -m 10 --retry 5 -X POST -H "Content-Type: text/plain" --data "Backup successful for location: ${AUTORESTIC_LOCATION}" https://<healthchecks-url>/ping/<uid>'
|
||||
backup:
|
||||
before:
|
||||
- 'curl -m 10 --retry 5 -X POST -H "Content-Type: text/plain" --data "Starting backup for location: ${AUTORESTIC_LOCATION}" https://<healthchecks-url>/ping/<uid>/start'
|
||||
failure:
|
||||
- 'curl -m 10 --retry 5 -X POST -H "Content-Type: text/plain" --data "Backup failed for location: ${AUTORESTIC_LOCATION}" https://<healthchecks-url>/ping/<uid>/fail'
|
||||
success:
|
||||
- 'curl -m 10 --retry 5 -X POST -H "Content-Type: text/plain" --data "Backup successful for location: ${AUTORESTIC_LOCATION}" https://<healthchecks-url>/ping/<uid>'
|
||||
|
||||
locations:
|
||||
something:
|
||||
|
@@ -24,6 +24,10 @@ You can download the right binary from the release page and simply copy it to `/
|
||||
|
||||
If you are on macOS you can install through brew: `brew install autorestic`.
|
||||
|
||||
### Fedora
|
||||
|
||||
Fedora users can install the [autorestic](https://src.fedoraproject.org/rpms/autorestic/) package with `dnf install autorestic`.
|
||||
|
||||
### AUR
|
||||
|
||||
~~If you are on Arch there is an [AUR Package](https://aur.archlinux.org/packages/autorestic-bin/) (looking for maintainers).~~ - Deprecated
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# Hooks
|
||||
|
||||
If you want to perform some commands before and/or after a backup, you can use hooks.
|
||||
If you want to perform some commands before and/or after a backup or restore, you can use hooks.
|
||||
|
||||
They consist of a list of 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 config file or in the `dir` directory if configured.
|
||||
|
||||
The following hooks groups are supported, none are required:
|
||||
|
||||
@@ -17,16 +17,27 @@ locations:
|
||||
from: /data
|
||||
to: my-backend
|
||||
hooks:
|
||||
before:
|
||||
- echo "One"
|
||||
- echo "Two"
|
||||
- echo "Three"
|
||||
after:
|
||||
- echo "Byte"
|
||||
failure:
|
||||
- echo "Something went wrong"
|
||||
success:
|
||||
- echo "Well done!"
|
||||
backup:
|
||||
before:
|
||||
- echo "One"
|
||||
- echo "Two"
|
||||
- echo "Three"
|
||||
after:
|
||||
- echo "Byte"
|
||||
failure:
|
||||
- echo "Something went wrong"
|
||||
success:
|
||||
- echo "Well done!"
|
||||
restore:
|
||||
dir: /var/www/html
|
||||
before:
|
||||
- echo "Let's restore this backup!"
|
||||
after:
|
||||
- echo "Finished to restore"
|
||||
failure:
|
||||
- echo "A problem has been encountered :("
|
||||
success:
|
||||
- echo "Successfully restored!"
|
||||
```
|
||||
|
||||
## Flowchart
|
||||
|
45
docs/markdown/migration/1.7_1.8.md
Normal file
45
docs/markdown/migration/1.7_1.8.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Migration from `1.7` to `1.8`
|
||||
|
||||
## Config files
|
||||
|
||||
- The config version have been changed
|
||||
- You can now configure restore hooks
|
||||
|
||||
See detailed instructions below.
|
||||
|
||||
## Config Version
|
||||
|
||||
The version field of the config file has been changed from `2` to `3`.
|
||||
|
||||
## Hooks
|
||||
|
||||
Since `1.8` both backup and restore hooks are possible.
|
||||
For this reason, backup hooks have been moved one layer deeper, you have to move them in a `backup` object.
|
||||
|
||||
Before:
|
||||
|
||||
```yaml
|
||||
locations:
|
||||
l1:
|
||||
# ...
|
||||
from: /foo/bar
|
||||
hooks:
|
||||
before:
|
||||
- pwd
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```yaml
|
||||
locations:
|
||||
l1:
|
||||
# ...
|
||||
from: /foo/bar
|
||||
hooks:
|
||||
backup:
|
||||
before:
|
||||
- pwd
|
||||
restore:
|
||||
after:
|
||||
- echo "My super restore hook"
|
||||
```
|
@@ -2,3 +2,4 @@
|
||||
|
||||
- [From 0.x to 1.0](/migration/0.x_1.0)
|
||||
- [From 1.4 to 1.5](/migration/1.4_1.5)
|
||||
- [From 1.7 to 1.8](/migration/1.7_1.8)
|
||||
|
12
docs/package-lock.json
generated
12
docs/package-lock.json
generated
@@ -1493,9 +1493,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
||||
"version": "5.76.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
|
||||
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
@@ -2680,9 +2680,9 @@
|
||||
}
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
||||
"version": "5.76.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
|
||||
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
|
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/cupcakearmy/autorestic
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
|
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const VERSION = "1.7.6"
|
||||
const VERSION = "1.7.7"
|
||||
|
||||
type OptionMap map[string][]interface{}
|
||||
type Options map[string]OptionMap
|
||||
@@ -83,7 +83,7 @@ func GetConfig() *Config {
|
||||
exitConfig(nil, "version specified in config file is not an int")
|
||||
} else {
|
||||
// Check for version
|
||||
if version != 2 {
|
||||
if version != 3 {
|
||||
exitConfig(nil, "unsupported config version number. please check the docs for migration\nhttps://autorestic.vercel.app/migration/")
|
||||
}
|
||||
}
|
||||
@@ -132,10 +132,14 @@ func (c *Config) Describe() {
|
||||
|
||||
tmp = ""
|
||||
hooks := map[string][]string{
|
||||
"Before": l.Hooks.Before,
|
||||
"After": l.Hooks.After,
|
||||
"Failure": l.Hooks.Failure,
|
||||
"Success": l.Hooks.Success,
|
||||
"Before backup": l.Hooks.BackupOption.Before,
|
||||
"After backup": l.Hooks.BackupOption.After,
|
||||
"Failure backup": l.Hooks.BackupOption.Failure,
|
||||
"Success backup": l.Hooks.BackupOption.Success,
|
||||
"Before restore": l.Hooks.RestoreOption.Before,
|
||||
"After restore": l.Hooks.RestoreOption.After,
|
||||
"Failure restore": l.Hooks.RestoreOption.Failure,
|
||||
"Success restore": l.Hooks.RestoreOption.Success,
|
||||
}
|
||||
for hook, commands := range hooks {
|
||||
if len(commands) > 0 {
|
||||
|
@@ -33,6 +33,13 @@ const (
|
||||
)
|
||||
|
||||
type Hooks struct {
|
||||
RestoreOption HooksList `mapstructure:"restore,omitempty"`
|
||||
BackupOption HooksList `mapstructure:"backup,omitempty"`
|
||||
}
|
||||
|
||||
type LocationCopy = map[string][]string
|
||||
|
||||
type HooksList struct {
|
||||
Dir string `mapstructure:"dir"`
|
||||
Before HookArray `mapstructure:"before,omitempty"`
|
||||
After HookArray `mapstructure:"after,omitempty"`
|
||||
@@ -40,18 +47,16 @@ type Hooks struct {
|
||||
Failure HookArray `mapstructure:"failure,omitempty"`
|
||||
}
|
||||
|
||||
type LocationCopy = map[string][]string
|
||||
|
||||
type Location struct {
|
||||
name string `mapstructure:",omitempty"`
|
||||
From []string `mapstructure:"from,omitempty"`
|
||||
Type string `mapstructure:"type,omitempty"`
|
||||
To []string `mapstructure:"to,omitempty"`
|
||||
Hooks Hooks `mapstructure:"hooks,omitempty"`
|
||||
Cron string `mapstructure:"cron,omitempty"`
|
||||
Options Options `mapstructure:"options,omitempty"`
|
||||
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"`
|
||||
CopyOption LocationCopy `mapstructure:"copy,omitempty"`
|
||||
name string `mapstructure:",omitempty"`
|
||||
From []string `mapstructure:"from,omitempty"`
|
||||
Type string `mapstructure:"type,omitempty"`
|
||||
To []string `mapstructure:"to,omitempty"`
|
||||
Hooks Hooks `mapstructure:"hooks,omitempty"`
|
||||
Cron string `mapstructure:"cron,omitempty"`
|
||||
Options Options `mapstructure:"options,omitempty"`
|
||||
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"`
|
||||
CopyOption LocationCopy `mapstructure:"copy,omitempty"`
|
||||
}
|
||||
|
||||
func GetLocation(name string) (Location, bool) {
|
||||
@@ -123,12 +128,12 @@ func (l Location) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l Location) ExecuteHooks(commands []string, options ExecuteOptions) error {
|
||||
func (l Location) ExecuteHooks(commands []string, directory string, options ExecuteOptions) error {
|
||||
if len(commands) == 0 {
|
||||
return nil
|
||||
}
|
||||
if l.Hooks.Dir != "" {
|
||||
if dir, err := GetPathRelativeToConfig(l.Hooks.Dir); err != nil {
|
||||
if directory != "" {
|
||||
if dir, err := GetPathRelativeToConfig(directory); err != nil {
|
||||
return err
|
||||
} else {
|
||||
options.Dir = dir
|
||||
@@ -190,7 +195,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
|
||||
}
|
||||
|
||||
// Hooks
|
||||
if err := l.ExecuteHooks(l.Hooks.Before, options); err != nil {
|
||||
if err := l.ExecuteHooks(l.Hooks.BackupOption.Before, l.Hooks.BackupOption.Dir, options); err != nil {
|
||||
errors = append(errors, err)
|
||||
goto after
|
||||
}
|
||||
@@ -290,7 +295,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
|
||||
}
|
||||
|
||||
// After hooks
|
||||
if err := l.ExecuteHooks(l.Hooks.After, options); err != nil {
|
||||
if err := l.ExecuteHooks(l.Hooks.BackupOption.After, l.Hooks.BackupOption.Dir, options); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
@@ -298,11 +303,11 @@ after:
|
||||
var commands []string
|
||||
var isSuccess = len(errors) == 0
|
||||
if isSuccess {
|
||||
commands = l.Hooks.Success
|
||||
commands = l.Hooks.BackupOption.Success
|
||||
} else {
|
||||
commands = l.Hooks.Failure
|
||||
commands = l.Hooks.BackupOption.Failure
|
||||
}
|
||||
if err := l.ExecuteHooks(commands, options); err != nil {
|
||||
if err := l.ExecuteHooks(commands, l.Hooks.BackupOption.Dir, options); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
@@ -370,11 +375,35 @@ func buildRestoreCommand(l Location, to string, snapshot string, options []strin
|
||||
return base
|
||||
}
|
||||
|
||||
func (l Location) Restore(to, from string, force bool, snapshot string, options []string) error {
|
||||
func (l Location) Restore(to, from string, force bool, snapshot string, options []string) (errors []error) {
|
||||
cwd, _ := GetPathRelativeToConfig(".")
|
||||
hooksOptions := ExecuteOptions{
|
||||
Command: "bash",
|
||||
Dir: cwd,
|
||||
Envs: map[string]string{
|
||||
"AUTORESTIC_LOCATION": l.name,
|
||||
},
|
||||
}
|
||||
|
||||
defer func() {
|
||||
var commands []string
|
||||
var isSuccess = len(errors) == 0
|
||||
if isSuccess {
|
||||
commands = l.Hooks.RestoreOption.Success
|
||||
} else {
|
||||
commands = l.Hooks.RestoreOption.Failure
|
||||
}
|
||||
if err := l.ExecuteHooks(commands, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
colors.Success.Println("Done")
|
||||
}()
|
||||
|
||||
if from == "" {
|
||||
from = l.To[0]
|
||||
} else if !l.hasBackend(from) {
|
||||
return fmt.Errorf("invalid backend: \"%s\"", from)
|
||||
errors = append(errors, fmt.Errorf("invalid backend: \"%s\"", from))
|
||||
}
|
||||
|
||||
if snapshot == "" {
|
||||
@@ -385,15 +414,23 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
|
||||
backend, _ := GetBackend(from)
|
||||
colors.Secondary.Printf("Restoring %s@%s → %s\n", snapshot, backend.name, to)
|
||||
|
||||
// Before Hooks for restore
|
||||
if err := l.ExecuteHooks(l.Hooks.RestoreOption.Before, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
|
||||
errors = append(errors, err)
|
||||
return
|
||||
}
|
||||
|
||||
t, err := l.getType()
|
||||
if err != nil {
|
||||
return err
|
||||
errors = append(errors, err)
|
||||
return
|
||||
}
|
||||
switch t {
|
||||
case TypeLocal:
|
||||
to, err = filepath.Abs(to)
|
||||
if err != nil {
|
||||
return err
|
||||
errors = append(errors, err)
|
||||
return
|
||||
}
|
||||
// Check if target is empty
|
||||
if !force {
|
||||
@@ -402,14 +439,17 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
|
||||
if err == nil {
|
||||
files, err := ioutil.ReadDir(to)
|
||||
if err != nil {
|
||||
return err
|
||||
errors = append(errors, err)
|
||||
return
|
||||
}
|
||||
if len(files) > 0 {
|
||||
return notEmptyError
|
||||
errors = append(errors, notEmptyError)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
errors = append(errors, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,10 +458,17 @@ func (l Location) Restore(to, from string, force bool, snapshot string, options
|
||||
_, _, err = backend.ExecDocker(l, buildRestoreCommand(l, "/", snapshot, options))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
errors = append(errors, err)
|
||||
return
|
||||
}
|
||||
colors.Success.Println("Done")
|
||||
return nil
|
||||
|
||||
// After Hooks for restore
|
||||
if err := l.ExecuteHooks(l.Hooks.RestoreOption.After, l.Hooks.RestoreOption.Dir, hooksOptions); err != nil {
|
||||
errors = append(errors, err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l Location) RunCron() error {
|
||||
|
Reference in New Issue
Block a user