Compare commits

..

66 Commits

Author SHA1 Message Date
478e193d78 forgot version bump 2021-05-06 16:17:45 +02:00
11d4c67dce docs 2021-05-06 16:14:29 +02:00
1643309957 changelog 2021-05-06 15:57:28 +02:00
e05386b0b5 add failure and success hooks 2021-05-06 15:55:32 +02:00
aebaf0a225 Merge branch 'master' of https://github.com/cupcakearmy/autorestic 2021-05-06 15:12:37 +02:00
c090013bf5 Update README.md 2021-05-06 15:12:11 +02:00
88c6949208 custom restic binary 2021-05-06 15:04:35 +02:00
9256cdc38c changelog 2021-05-01 22:57:01 +02:00
a8c611e8ce Merge branch 'master' of https://github.com/cupcakearmy/autorestic 2021-05-01 22:54:57 +02:00
d4522c7ffe fix validation for docker volumes 2021-05-01 22:54:52 +02:00
21185d894e Update contrib.md 2021-05-01 17:25:50 +02:00
b119fc7ea5 Merge pull request #72 from themorlan/master
Correcting some typos in the Documentation
2021-05-01 17:25:20 +02:00
themorlan
73f4bcfd48 missing words in sentence 2021-05-01 15:18:05 +02:00
themorlan
3567319314 typo 2021-05-01 15:16:13 +02:00
themorlan
bf19c983d1 typo 2021-05-01 15:15:44 +02:00
themorlan
12e4de110b typo 2021-05-01 15:14:50 +02:00
c9f425ef64 docs on native flags 2021-04-30 10:47:29 +02:00
974f555dff Update contrib.md 2021-04-29 15:18:03 +02:00
1688c1f3c3 add brew docs 2021-04-29 15:16:33 +02:00
29e46d3b5c brew stuff 2021-04-29 14:45:17 +02:00
0335abb669 add sign 2021-04-28 14:51:56 +02:00
b2f9b9a54e typo 2021-04-28 13:50:11 +02:00
2b13a6e13d installtion docs 2021-04-28 13:44:20 +02:00
cc293ea256 Update installation.md 2021-04-28 13:38:20 +02:00
a4ddd5bbcb Update contrib.md 2021-04-28 13:34:58 +02:00
7cbf43b75d Update README.md 2021-04-28 11:13:16 +02:00
bae77c4673 Update README.md 2021-04-28 11:10:36 +02:00
12adeb2b06 changelog 2021-04-28 10:54:33 +02:00
37b26dfc31 consistent casing 2021-04-28 10:54:30 +02:00
c1795b2acc lean flag 2021-04-28 10:54:07 +02:00
b8d12e518c completion docs 2021-04-28 10:34:43 +02:00
50060cf539 explain verbose flag 2021-04-27 18:38:51 +02:00
c33aac42dc quickstart 2021-04-27 18:35:32 +02:00
c359053e0e Update contrib.md 2021-04-27 09:02:39 +02:00
c16340ab26 Update available.md 2021-04-27 09:01:01 +02:00
edc85c4ac3 Merge pull request #60 from david-boles/backblaze
Update Backblaze docs
2021-04-27 08:59:44 +02:00
68682777f2 Merge pull request #59 from david-boles/consistent-config-location
Recommend a consistent config location
2021-04-27 08:26:22 +02:00
David Boles
b6c7922df5 Recommend a consistent config location 2021-04-26 16:47:00 -07:00
David Boles
991b8bec22 Update backblaze docs 2021-04-26 16:38:08 -07:00
bbc32568ad parallel builds 2021-04-26 13:29:26 +02:00
f3c038c716 changelog & version bump 2021-04-26 13:18:02 +02:00
59612a97b6 Merge branch 'master' of https://github.com/cupcakearmy/autorestic 2021-04-26 13:16:01 +02:00
33319a00ef add arm for darwin 2021-04-26 13:15:58 +02:00
8eb14ea14f Update quick.md 2021-04-25 11:19:39 +02:00
70eb9e441f add rclone support 2021-04-24 16:40:53 +02:00
be25af2d76 Merge pull request #53 from TheForcer/master
Fix typo in check output
2021-04-24 13:19:34 +02:00
1c436369f0 check folder 2021-04-24 12:40:33 +02:00
6efcce07b7 show error and exit with bad code if not found 2021-04-23 23:53:57 +02:00
Felix
dc6dd2e712 Fix typo in check output 2021-04-23 19:19:03 +02:00
Felix
68628d3776 Merge pull request #1 from cupcakearmy/master
Update
2021-04-23 19:18:08 +02:00
40988ef3b4 Update contrib.md 2021-04-23 17:53:48 +02:00
fad33fcdaa Merge pull request #51 from TheForcer/master
Fix typos in docs
2021-04-23 17:53:15 +02:00
Felix
8cf8a77558 Fix typos in docs 2021-04-23 17:45:02 +02:00
36998cfd3b changelog 2021-04-23 13:47:21 +02:00
cf03562ea2 docs 2021-04-23 13:45:54 +02:00
188560395d exclude items from config when empty and rest options 2021-04-23 13:11:15 +02:00
bacbd0f806 docs 2021-04-23 12:31:24 +02:00
93bf0388a4 add force flag description 2021-04-22 10:00:52 +02:00
ec8fdbd135 updated contrib list 2021-04-22 01:14:47 +02:00
420934489c Merge pull request #46 from FuzzyMistborn/patch-1
Fix typo in install script
2021-04-22 01:07:11 +02:00
Fuzzy
2ba767c8c3 Fix typo in install script
Fix typo
2021-04-21 14:32:11 -04:00
b489c662c7 docs 2021-04-21 09:41:14 +02:00
6862529a89 move envs to new format 2021-04-21 09:36:47 +02:00
aa96a95600 typos 2021-04-21 09:34:01 +02:00
89e32c298c update the quick guide 2021-04-21 09:27:35 +02:00
873170c6d1 fix auto update 2021-04-20 23:26:57 +02:00
41 changed files with 2349 additions and 1495 deletions

View File

@@ -15,6 +15,11 @@ jobs:
go-version: '^1.16.3' go-version: '^1.16.3'
- name: Build - name: Build
run: go run build/build.go run: go run build/build.go
- name: Sign
uses: tristan-weil/ghaction-checksum-sign-artifact@v1.0.1
with:
path: dist/*
- name: Release - name: Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:

View File

@@ -5,6 +5,69 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.1.0] - 2021-05-06
### Added
- use custom restic binary
- success & failure hooks
### Fixed
- don't skip other locations on failure
## [1.0.9] - 2021-05-01
### Fixed
- Validation for docker volumes
## [1.0.8] - 2021-04-28
### Added
- `--lean` flag to cron command for less output about skipping backups.
### Fixed
- consistent lower casing in usage descriptions.
## [1.0.7] - 2021-04-26
### Added
- Support for `darwin/arm64` aka Apple Silicon.
- Added support for `arm64` and `aarch64` in install scripts.
## [1.0.6] - 2021-04-24
### Added
- Support for rclone
## [1.0.5] - 2021-04-24
### Fixed
- Correct exit code on backup failure and better logging/output/feedback.
- Check if `from` key is an actual directory.
## [1.0.4] - 2021-04-23
### Added
- Options to add rest username and password in config
### Fixed
- Don't add empty strings when saving config
## [1.0.3] - 2021-04-20
### Fixed
- Auto upgrade script was not working on linux as linux does not support writing to the binary that is being executed
## [1.0.2] - 2021-04-20 ## [1.0.2] - 2021-04-20
### Added ### Added

30
DEVELOPMENT.md Normal file
View File

@@ -0,0 +1,30 @@
# Development
## Coding
The easiest way (imo) is to run [`gowatch`](https://github.com/silenceper/gowatch) in a separate terminal and the simply run `./autorestic ...`. `gowatch` will watch the code and automatically rebuild the binary when changes are saved to disk.
## Building
```bash
go run build/build.go
```
This will build and compress binaries for multiple platforms. The output will be put in the `dist` folder.
## Releasing
Releases are automatically built by the github workflow and uploaded to the release.
1. Bump `VERSION` in `internal/config.go`.
2. Update `CHANGELOG.md`
3. Commit to master
4. Create a new release with the `v1.2.3` tag and mark as draft.
5. The Github action will build the binaries, upload and mark the release as ready when done.
### Brew
1. Download the latest release.
2. Check the checksum with `shasum -a 256 autorestic-1.2.3.tar.gz`
3. Update `url` and `sha256` in the brew repo.
4. Submit PR

View File

@@ -10,6 +10,13 @@
Config driven, easy backup cli for <a href="https://restic.net/">restic</a>. Config driven, easy backup cli for <a href="https://restic.net/">restic</a>.
<br> <br>
<strong><a href="https://autorestic.vercel.app/">»»» Docs & Getting Started »»»</a></strong> <strong><a href="https://autorestic.vercel.app/">»»» Docs & Getting Started »»»</a></strong>
<br><br>
<a target="_blank" href="https://discord.gg/wS7RpYTYd2">
<img src="https://img.shields.io/discord/252403122348097536" alt="discord badge" />
<img src="https://img.shields.io/github/contributors/cupcakearmy/autorestic" alt="contributor badge" />
<img src="https://img.shields.io/github/downloads/cupcakearmy/autorestic/total" alt="downloads badge" />
<img src="https://img.shields.io/github/v/release/cupcakearmy/autorestic" alt="version badge" />
</a>
</p> </p>
</p> </p>
@@ -35,4 +42,9 @@ Autorestic is a wrapper around the amazing [restic](https://restic.net/). While
### ❓ Questions / Support ### ❓ Questions / Support
Check the [discussions page](https://github.com/cupcakearmy/autorestic/discussions) Check the [discussions page](https://github.com/cupcakearmy/autorestic/discussions) or [join on discord](https://discord.gg/wS7RpYTYd2)
## Contributing / Developing
PRs, feature requests, etc. are welcomed :)
Have a look at [the dev docs](./DEVELOPMENT.md)

View File

@@ -1,9 +0,0 @@
# Releasing
Releases are handled by the CD server with includes checksums for each binary.
```bash
git tag 0.x
git push
git push origin --tags
```

View File

@@ -9,6 +9,7 @@ import (
"os/exec" "os/exec"
"path" "path"
"path/filepath" "path/filepath"
"sync"
"github.com/cupcakearmy/autorestic/internal" "github.com/cupcakearmy/autorestic/internal"
) )
@@ -16,7 +17,7 @@ import (
var DIR, _ = filepath.Abs("./dist") var DIR, _ = filepath.Abs("./dist")
var targets = map[string][]string{ var targets = map[string][]string{
"darwin": {"amd64"}, "darwin": {"amd64", "arm64"},
"freebsd": {"386", "amd64", "arm"}, "freebsd": {"386", "amd64", "arm"},
"linux": {"386", "amd64", "arm", "arm64"}, "linux": {"386", "amd64", "arm", "arm64"},
"netbsd": {"386", "amd64"}, "netbsd": {"386", "amd64"},
@@ -27,7 +28,7 @@ type buildOptions struct {
Target, Arch, Version string Target, Arch, Version string
} }
func build(options buildOptions) error { func build(options buildOptions, wg *sync.WaitGroup) {
fmt.Printf("Building %s %s\n", options.Target, options.Arch) fmt.Printf("Building %s %s\n", options.Target, options.Arch)
out := fmt.Sprintf("autorestic_%s_%s_%s", options.Version, options.Target, options.Arch) out := fmt.Sprintf("autorestic_%s_%s_%s", options.Version, options.Target, options.Arch)
out = path.Join(DIR, out) out = path.Join(DIR, out)
@@ -46,7 +47,7 @@ func build(options buildOptions) error {
) )
err := c.Run() err := c.Run()
if err != nil { if err != nil {
return err panic(err)
} }
} }
@@ -58,26 +59,25 @@ func build(options buildOptions) error {
c.Stderr = os.Stderr c.Stderr = os.Stderr
err := c.Run() err := c.Run()
if err != nil { if err != nil {
return err panic(err)
} }
} }
wg.Done()
return nil
} }
func main() { func main() {
os.RemoveAll(DIR) os.RemoveAll(DIR)
v := internal.VERSION v := internal.VERSION
var wg sync.WaitGroup
for target, archs := range targets { for target, archs := range targets {
for _, arch := range archs { for _, arch := range archs {
err := build(buildOptions{ wg.Add(1)
build(buildOptions{
Target: target, Target: target,
Arch: arch, Arch: arch,
Version: v, Version: v,
}) }, &wg)
if err != nil {
panic(err)
}
} }
} }
wg.Wait()
} }

View File

@@ -1,7 +1,10 @@
package cmd package cmd
import ( import (
"fmt"
"github.com/cupcakearmy/autorestic/internal" "github.com/cupcakearmy/autorestic/internal"
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/lock" "github.com/cupcakearmy/autorestic/internal/lock"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -14,13 +17,21 @@ var backupCmd = &cobra.Command{
CheckErr(err) CheckErr(err)
defer lock.Unlock() defer lock.Unlock()
CheckErr(internal.CheckConfig()) internal.GetConfig()
selected, err := internal.GetAllOrSelected(cmd, false) selected, err := internal.GetAllOrSelected(cmd, false)
CheckErr(err) CheckErr(err)
errors := 0
for _, name := range selected { for _, name := range selected {
location, _ := internal.GetLocation(name) location, _ := internal.GetLocation(name)
location.Backup(false) errs := location.Backup(false)
for err := range errs {
colors.Error.Println(err)
errors++
}
}
if errors > 0 {
CheckErr(fmt.Errorf("%d errors were found", errors))
} }
}, },
} }

View File

@@ -17,7 +17,7 @@ var checkCmd = &cobra.Command{
CheckErr(internal.CheckConfig()) CheckErr(internal.CheckConfig())
colors.Success.Println("Everyting is fine.") colors.Success.Println("Everything is fine.")
}, },
} }

View File

@@ -11,6 +11,7 @@ var cronCmd = &cobra.Command{
Short: "Run cron job for automated backups", Short: "Run cron job for automated backups",
Long: `Intended to be mainly triggered by an automated system like systemd or crontab. For each location checks if a cron backup is due and runs it.`, Long: `Intended to be mainly triggered by an automated system like systemd or crontab. For each location checks if a cron backup is due and runs it.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
internal.CRON_LEAN, _ = cmd.Flags().GetBool("lean")
err := lock.Lock() err := lock.Lock()
CheckErr(err) CheckErr(err)
defer lock.Unlock() defer lock.Unlock()
@@ -22,4 +23,5 @@ var cronCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(cronCmd) rootCmd.AddCommand(cronCmd)
cronCmd.Flags().Bool("lean", false, "only output information about actual backups")
} }

View File

@@ -31,6 +31,6 @@ var forgetCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(forgetCmd) rootCmd.AddCommand(forgetCmd)
internal.AddFlagsToCommand(forgetCmd, false) internal.AddFlagsToCommand(forgetCmd, false)
forgetCmd.Flags().Bool("prune", false, "Also prune repository") forgetCmd.Flags().Bool("prune", false, "also prune repository")
forgetCmd.Flags().Bool("dry-run", false, "Do not write changes, show what would be affected") forgetCmd.Flags().Bool("dry-run", false, "do not write changes, show what would be affected")
} }

View File

@@ -37,6 +37,7 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.autorestic.yml or ./.autorestic.yml)") rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.autorestic.yml or ./.autorestic.yml)")
rootCmd.PersistentFlags().BoolVar(&internal.CI, "ci", false, "CI mode disabled interactive mode and colors and enables verbosity") rootCmd.PersistentFlags().BoolVar(&internal.CI, "ci", false, "CI mode disabled interactive mode and colors and enables verbosity")
rootCmd.PersistentFlags().BoolVarP(&internal.VERBOSE, "verbose", "v", false, "verbose mode") rootCmd.PersistentFlags().BoolVarP(&internal.VERBOSE, "verbose", "v", false, "verbose mode")
rootCmd.PersistentFlags().StringVar(&internal.RESTIC_BIN, "restic-bin", "restic", "specify custom restic binary")
cobra.OnInitialize(initConfig) cobra.OnInitialize(initConfig)
} }
@@ -57,5 +58,4 @@ func initConfig() {
viper.SetConfigName(".autorestic") viper.SetConfigName(".autorestic")
} }
viper.AutomaticEnv() viper.AutomaticEnv()
internal.GetConfig()
} }

View File

@@ -16,5 +16,5 @@ var uninstallCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(uninstallCmd) rootCmd.AddCommand(uninstallCmd)
uninstallCmd.Flags().Bool("no-restic", false, "Do not uninstall restic.") uninstallCmd.Flags().Bool("no-restic", false, "do not uninstall restic.")
} }

View File

@@ -17,5 +17,5 @@ var upgradeCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(upgradeCmd) rootCmd.AddCommand(upgradeCmd)
upgradeCmd.Flags().Bool("no-restic", false, "Also update restic. Default: true") upgradeCmd.Flags().Bool("no-restic", false, "also update restic")
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{ {
"dependencies": { "dependencies": {
"@codedoc/core": "^0.2.15" "@codedoc/core": "^0.2.23"
} }
} }

View File

@@ -1,5 +1,6 @@
[Home](/) [Home](/)
[Quick Start](/quick) [Quick Start](/quick)
[Installation](/installation)
[Configuration](/config) [Configuration](/config)
[Upgrade](/upgrade) [Upgrade](/upgrade)
@@ -7,8 +8,13 @@
> >
> [Overview](/location/overview) > [Overview](/location/overview)
> [Hooks](/location/hooks) > [Hooks](/location/hooks)
> [Excluding Files](/location/exclude) >
> [Forget Policy](/location/forget) > > :Collapse label=Options
> >
> > [Overview](/location/options)
> > [Excluding Files](/location/exclude)
> > [Forget Policy](/location/forget)
>
> [Cron](/location/cron) > [Cron](/location/cron)
> [Docker Volumes](/location/docker) > [Docker Volumes](/location/docker)
@@ -22,6 +28,7 @@
> [General](/cli/general) > [General](/cli/general)
> [Info](/cli/info) > [Info](/cli/info)
> [Check](/cli/check) > [Check](/cli/check)
> [Completion](/cli/completion)
> [Backup](/cli/backup) > [Backup](/cli/backup)
> [Restore](/cli/restore) > [Restore](/cli/restore)
> [Forget](/cli/forget) > [Forget](/cli/forget)

View File

@@ -19,11 +19,18 @@ backends:
backends: backends:
name-of-backend: name-of-backend:
type: b2 type: b2
path: 'myAccount:myBucket/my/path' path: 'backblaze_bucketID'
B2_ACCOUNT_ID: backblaze_account_id # Or With a path
B2_ACCOUNT_KEY: backblaze_account_key # path: 'backblaze_bucketID:/some/path'
env:
B2_ACCOUNT_ID: 'backblaze_keyID'
B2_ACCOUNT_KEY: 'backblaze_applicationKey'
``` ```
#### API Keys gotcha
If you use a _File name prefix_ when making the application key, do not include a leading slash. Make sure to include this prefix in the path (e.g. `path: 'backblaze_bucketID:my/path'`).
## S3 / Minio ## S3 / Minio
```yaml ```yaml
@@ -33,6 +40,7 @@ backends:
path: s3.amazonaws.com/bucket_name path: s3.amazonaws.com/bucket_name
# Minio # Minio
# path: http://localhost:9000/bucket_name # path: http://localhost:9000/bucket_name
env:
AWS_ACCESS_KEY_ID: my_key AWS_ACCESS_KEY_ID: my_key
AWS_SECRET_ACCESS_KEY: my_secret AWS_SECRET_ACCESS_KEY: my_secret
``` ```
@@ -57,6 +65,21 @@ backends:
name-of-backend: name-of-backend:
type: rest type: rest
path: http://localhost:8000/repo_name path: http://localhost:8000/repo_name
# Or authenticated
path: https://user:pass@host:6969/path
```
Optionally you can set user and password separately
```yaml
backends:
rest:
type: rest
path: http://localhost:6969/path
key: ...
rest:
user: user
password: pass
``` ```
> :ToCPrevNext > :ToCPrevNext

View File

@@ -1,6 +1,6 @@
# 💽 Backends # 💽 Backends
Backends are the ouputs of the backup process. Each location needs at least one. Backends are the outputs of the backup process. Each location needs at least one.
```yaml | .autorestic.yml ```yaml | .autorestic.yml
backends: backends:

View File

@@ -0,0 +1,17 @@
# Completion
```bash
autorestic completion [bash|zsh|fish|powershell]
```
Autorestic can generate shell completions automatically to make the experience even easier.
Supported shells are
- bash
- zsh
- fish
- powershell
To see how to install run `autorestic help completion` and follow the instructions for your specific shell
> :ToCPrevNext

View File

@@ -1,11 +1,13 @@
# Cron # Cron
```bash ```bash
autorestic cron autorestic cron [--lean]
``` ```
This command is mostly intended to be triggered by an automated system like systemd or crontab. This command is mostly intended to be triggered by an automated system like systemd or crontab.
It will run cron jobs es [specified in the cron section](/locations/cron) of a specific location. It will run cron jobs as [specified in the cron section](/location/cron) of a specific location.
The `--lean` flag will omit output like _skipping location x: not due yet_. This can be useful if you are dumping the output of the cron job to a log file and don't want to be overwhelmed by the output log.
> :ToCPrevNext > :ToCPrevNext

View File

@@ -4,10 +4,10 @@
autorestic exec [-b, --backend] [-a, --all] <command> -- [native options] autorestic exec [-b, --backend] [-a, --all] <command> -- [native options]
``` ```
This is avery handy command which enables you to run any native restic command on desired backends. An example would be listing all the snapshots of all your backends: This is a very handy command which enables you to run any native restic command on desired backends. Generally you will want to include the verbose flag `-v, --verbose` to see the output. An example would be listing all the snapshots of all your backends:
```bash ```bash
autorestic exec -a -- snapshots autorestic exec -av -- snapshots
``` ```
With `exec` you can basically run every cli command that you would be able to run with the restic cli. It only pre-fills path, key, etc. With `exec` you can basically run every cli command that you would be able to run with the restic cli. It only pre-fills path, key, etc.

View File

@@ -26,3 +26,13 @@ Verbose mode will show the output of the native restic commands that are otherwi
```bash ```bash
autorestic --verbose backup -a autorestic --verbose backup -a
``` ```
## `--restic-bin`
With `--restic-bin` you can specify to run a specific restic binary. This can be useful if you want to [create a custom binary with root access that can be executed by any user](https://restic.readthedocs.io/en/stable/080_examples.html#full-backup-without-root).
```bash
autorestic --restic-bin /some/path/to/my/custom/restic/binary
```
> :ToCPrevNext

View File

@@ -1,11 +1,13 @@
# Restore # Restore
```bash ```bash
autorestic restore [-l, --location] [--from backend] [--to <out dir>] autorestic restore [-l, --location] [--from backend] [--to <out dir>] [-f, --force]
``` ```
This will restore all the locations to the selected target. If for one location there are more than one backends specified autorestic will take the first one. This will restore all the locations to the selected target. If for one location there are more than one backends specified autorestic will take the first one.
The `--to` path has to be empty as no data will be overwritten by default. If you are sure you can pass the `-f, --force` flag and the data will be overwritten in the destination. However note that this will overwrite all the data existent in the backup, not only the 1 file that is missing e.g.
## Example ## Example
```bash ```bash

View File

@@ -1,6 +1,6 @@
# Uninstall # Uninstall
Installs both restic and autorestic from `/usr/local/bin`. Uninstalls both restic and autorestic from `/usr/local/bin`.
```bash ```bash
autorestic uninstall autorestic uninstall

View File

@@ -2,7 +2,15 @@
This amazing people helped the project! This amazing people helped the project!
- @ChanceM [Docs] - @agateblue - Docs, Pruning, S3
- @EliotBerriot [Docs, Pruning, S3] - @david-boles - Docs
- @SebDanielsson - Brew
- @n194 - AUR Package
- @jin-park-dev - Typos
- @sumnerboy12 - Typos
- @FuzzyMistborn - Typos
- @ChanceM - Typos
- @TheForcer - Typos
- @themorlan - Typos
> :ToCPrevNext > :ToCPrevNext

View File

@@ -3,12 +3,12 @@
## List all the snapshots for all the backends ## List all the snapshots for all the backends
```bash ```bash
autorestic exec -a -- snapshots autorestic exec -av -- snapshots
``` ```
## Unlock a locked repository ## Unlock a locked repository
This can come in handy if a backup process crashed or if it was accidentally cancelled. Then the repository would still be locked without an actual process using it. Only do this if you know what you are sure no other process is actually reading/writing to the repository of course. This can come in handy if a backup process crashed or if it was accidentally cancelled. Then the repository would still be locked without an actual process using it. Only do this if you know what you are doing and are sure no other process is actually reading/writing to the repository of course.
```bash ```bash
autorestic exec -b my-backend -- unlock autorestic exec -b my-backend -- unlock

View File

@@ -8,4 +8,18 @@ Autorestic requires `curl`, `wget` and `bzip2` to be installed. For most systems
curl -s https://raw.githubusercontent.com/CupCakeArmy/autorestic/master/install.sh | bash curl -s https://raw.githubusercontent.com/CupCakeArmy/autorestic/master/install.sh | bash
``` ```
## Alternatives
### Manual
You can download the right binary from the release page and simply copy it to `/usr/local/bin` or whatever path you prefer. Autoupdates will still work.
### Brew
If you are on macOS you can install through brew: `brew install autorestic`.
### AUR
If you are on Arch there is an [AUR Package](https://aur.archlinux.org/packages/autorestic-bin/) by @n194.
> :ToCPrevNext > :ToCPrevNext

View File

@@ -1,6 +1,6 @@
# Cron # Cron
Often it is usefull to trigger backups autmatically. For this we can specify a `cron` attribute to each location. Often it is usefully to trigger backups automatically. For this we can specify a `cron` attribute to each location.
```yaml | .autorestic.yml ```yaml | .autorestic.yml
locations: locations:
@@ -14,11 +14,11 @@ Here is a awesome website with [some examples](https://crontab.guru/examples.htm
## Installing the cron ## Installing the cron
**This has to be done only once, regadless of now many cros you have in your config file.** **This has to be done only once, regardless of now many cron jobs you have in your config file.**
To actually enable cron jobs you need something to call `autorestic cron` on a timed shedule. To actually enable cron jobs you need something to call `autorestic cron` on a timed schedule.
Note that the shedule has nothing to do with the `cron` attribute in each location. Note that the schedule has nothing to do with the `cron` attribute in each location.
My advise would be to trigger the command every 5min, but if you have a cronjob that runs only once a week, it's probably enough to shedule it once a day. My advise would be to trigger the command every 5min, but if you have a cronjob that runs only once a week, it's probably enough to schedule it once a day.
### Crontab ### Crontab
@@ -30,14 +30,14 @@ First, open your crontab in edit mode
crontab -e crontab -e
``` ```
Then paste this at the bottom of the file and save it. Note that in this specific example the `.autorestic.yml` is located in `/srv/`. You need to modify that part of course to fit your config file. Then paste this at the bottom of the file and save it. Note that in this specific example the config file is located at one of the default locations (e.g. `~/.autorestic.yml`). If your config is somewhere else you'll need to specify it using the `-c` option.
```bash ```bash
# This is required, as it otherwise cannot find restic as a command. # This is required, as it otherwise cannot find restic as a command.
PATH="/usr/local/bin:/usr/bin:/bin" PATH="/usr/local/bin:/usr/bin:/bin"
# Example running every 5 minutes # Example running every 5 minutes
*/5 * * * * autorestic -c /srv/.autorestic.yml --ci cron */5 * * * * autorestic --ci cron
``` ```
> The `--ci` option is not required, but recommended > The `--ci` option is not required, but recommended

View File

@@ -1,6 +1,6 @@
# Excluding files # Excluding files
If you want to exclude certain files or folders it done easily by specifiyng the right flags in the location you desire to filter. If you want to exclude certain files or folders it done easily by specifying the right flags in the location you desire to filter.
The flags are taken straight from the [restic cli exclude rules](https://restic.readthedocs.io/en/latest/040_backup.html#excluding-files) so you can use any flag used there. The flags are taken straight from the [restic cli exclude rules](https://restic.readthedocs.io/en/latest/040_backup.html#excluding-files) so you can use any flag used there.

View File

@@ -14,11 +14,11 @@ locations:
options: options:
forget: forget:
keep-last: 5 # always keep at least 5 snapshots keep-last: 5 # always keep at least 5 snapshots
keep-hourly: 3 # keep 3 last hourly shapshots keep-hourly: 3 # keep 3 last hourly snapshots
keep-daily: 4 # keep 4 last daily shapshots keep-daily: 4 # keep 4 last daily snapshots
keep-weekly: 1 # keep 1 last weekly shapshots keep-weekly: 1 # keep 1 last weekly snapshots
keep-monthly: 12 # keep 12 last monthly shapshots keep-monthly: 12 # keep 12 last monthly snapshots
keep-yearly: 7 # keep 7 last yearly shapshots keep-yearly: 7 # keep 7 last yearly snapshots
keep-within: '2w' # keep snapshots from the last 2 weeks keep-within: '2w' # keep snapshots from the last 2 weeks
``` ```

View File

@@ -2,7 +2,14 @@
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, 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 ```yml | .autorestic.yml
locations: locations:
@@ -11,10 +18,25 @@ locations:
to: my-backend to: my-backend
hooks: hooks:
before: before:
- echo "Hello" - echo "One"
- echo "Human" - echo "Two"
- echo "Three"
after: 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 > :ToCPrevNext

View File

@@ -0,0 +1,19 @@
# Options
For the `backup` and `forget` commands you can pass any native flags to `restic`.
```yaml
locations:
foo:
path: ...
to: ...
options:
backup:
tag:
- foo
- bar
```
In this example, whenever `autorestic` runs `restic backup` it will append a `--tag abc --tag` to the native command.
> :ToCPrevNext

View File

@@ -22,6 +22,6 @@ Paths can be absolute or relative. If relative they are resolved relative to the
## `to` ## `to`
This is einther a single backend or an array of backends. The backends have to be configured in the same config file. This is either a single backend or an array of backends. The backends have to be configured in the same config file.
> :ToCPrevNext > :ToCPrevNext

View File

@@ -6,16 +6,18 @@
curl -s https://raw.githubusercontent.com/CupCakeArmy/autorestic/master/install.sh | bash curl -s https://raw.githubusercontent.com/CupCakeArmy/autorestic/master/install.sh | bash
``` ```
See [installation](/installation) for alternative options.
## Write a simple config file ## Write a simple config file
```bash ```bash
vim .autorestic.yml vim ~/.autorestic.yml
``` ```
For a quick overview: For a quick overview:
- `locations` can be seen as the inputs and `backends` the output where the data is stored and backed up. - `locations` can be seen as the inputs and `backends` the output where the data is stored and backed up.
- One `location` can have one or multiple `backends` for redudancy. - One `location` can have one or multiple `backends` for redundancy.
- One `backend` can also be the target for multiple `locations`. - One `backend` can also be the target for multiple `locations`.
> **⚠️ WARNING ⚠️** > **⚠️ WARNING ⚠️**
@@ -24,25 +26,26 @@ For a quick overview:
```yaml | .autorestic.yml ```yaml | .autorestic.yml
locations: locations:
- name: home home:
from: /home/me from: /home/me
to: remote to: remote
- name: important important:
from: /path/to/important/stuff from: /path/to/important/stuff
to: to:
- remote - remote
- hdd - hdd
backends: backends:
- name: remote remote:
type: s3 type: s3
path: 's3.amazonaws.com/bucket_name' path: 's3.amazonaws.com/bucket_name'
key: some-random-password-198rc79r8y1029c8yfewj8f1u0ef87yh198uoieufy key: some-random-password-198rc79r8y1029c8yfewj8f1u0ef87yh198uoieufy
env:
AWS_ACCESS_KEY_ID: account_id AWS_ACCESS_KEY_ID: account_id
AWS_SECRET_ACCESS_KEY: account_key AWS_SECRET_ACCESS_KEY: account_key
- name: hdd hdd:
type: local type: local
path: /mnt/my_external_storage path: /mnt/my_external_storage
key: 'if not key is set it will be generated for you' key: 'if not key is set it will be generated for you'
@@ -51,7 +54,7 @@ backends:
## Check ## Check
```bash ```bash
autorestic check -a autorestic check
``` ```
This checks if the config file has any issues. If this is the first time this can take longer as autorestic will setup the backends. This checks if the config file has any issues. If this is the first time this can take longer as autorestic will setup the backends.

12
docs/package-lock.json generated
View File

@@ -131,9 +131,9 @@
} }
}, },
"node_modules/chalk": { "node_modules/chalk": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dependencies": { "dependencies": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
"supports-color": "^7.1.0" "supports-color": "^7.1.0"
@@ -1153,9 +1153,9 @@
} }
}, },
"chalk": { "chalk": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"requires": { "requires": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
"supports-color": "^7.1.0" "supports-color": "^7.1.0"

View File

@@ -16,9 +16,11 @@ else
fi fi
echo $OS echo $OS
NATIVE_ARCH=$(uname -m) NATIVE_ARCH=$(uname -m | tr '[:upper:]' '[:lower:]')
if [[ $NATIVE_ARCH == *"x86_64"* ]]; then if [[ $NATIVE_ARCH == *"x86_64"* ]]; then
ARCH=amd64 ARCH=amd64
elif [[ $NATIVE_ARCH == *"arm64"* || $NATIVE_ARCH == *"aarch64"* ]]; then
ARCH=arm64
elif [[ $NATIVE_ARCH == *"x86"* ]]; then elif [[ $NATIVE_ARCH == *"x86"* ]]; then
ARCH=386 ARCH=386
else else
@@ -36,4 +38,4 @@ bzip2 -fd "${OUT_FILE}.bz2"
chmod +x ${OUT_FILE} chmod +x ${OUT_FILE}
autorestic install autorestic install
echo "Succefsully installed autorestic" echo "Successfully installed autorestic"

View File

@@ -4,19 +4,25 @@ import (
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"net/url"
"os" "os"
"strings" "strings"
"github.com/cupcakearmy/autorestic/internal/colors" "github.com/cupcakearmy/autorestic/internal/colors"
"github.com/spf13/viper"
) )
type BackendRest struct {
User string `yaml:"user,omitempty"`
Password string `yaml:"password,omitempty"`
}
type Backend struct { type Backend struct {
name string name string
Type string `mapstructure:"type,omitempty"` Type string `yaml:"type,omitempty"`
Path string `mapstructure:"path,omitempty"` Path string `yaml:"path,omitempty"`
Key string `mapstructure:"key,omitempty"` Key string `yaml:"key,omitempty"`
Env map[string]string `mapstructure:"env,omitempty"` Env map[string]string `yaml:"env,omitempty"`
Rest BackendRest `yaml:"rest,omitempty"`
} }
func GetBackend(name string) (Backend, bool) { func GetBackend(name string) (Backend, bool) {
@@ -29,7 +35,20 @@ func (b Backend) generateRepo() (string, error) {
switch b.Type { switch b.Type {
case "local": case "local":
return GetPathRelativeToConfig(b.Path) return GetPathRelativeToConfig(b.Path)
case "b2", "azure", "gs", "s3", "sftp", "rest": case "rest":
parsed, err := url.Parse(b.Path)
if err != nil {
return "", err
}
if b.Rest.User != "" {
if b.Rest.Password == "" {
parsed.User = url.User(b.Rest.User)
} else {
parsed.User = url.UserPassword(b.Rest.User, b.Rest.Password)
}
}
return fmt.Sprintf("%s:%s", b.Type, parsed.String()), nil
case "b2", "azure", "gs", "s3", "sftp", "rclone":
return fmt.Sprintf("%s:%s", b.Type, b.Path), nil return fmt.Sprintf("%s:%s", b.Type, b.Path), nil
default: default:
return "", fmt.Errorf("backend type \"%s\" is invalid", b.Type) return "", fmt.Errorf("backend type \"%s\" is invalid", b.Type)
@@ -70,15 +89,10 @@ func (b Backend) validate() error {
c := GetConfig() c := GetConfig()
tmp := c.Backends[b.name] tmp := c.Backends[b.name]
tmp.Key = key tmp.Key = key
tmp.name = ""
c.Backends[b.name] = tmp c.Backends[b.name] = tmp
file := viper.ConfigFileUsed() if err := c.SaveConfig(); err != nil {
if err := CopyFile(file, file+".old"); err != nil {
return err return err
} }
colors.Secondary.Println("Saved a backup copy of your file next the the original.")
viper.Set("backends", c.Backends)
viper.WriteConfig()
} }
env, err := b.getEnv() env, err := b.getEnv()
if err != nil { if err != nil {
@@ -107,16 +121,20 @@ func (b Backend) Exec(args []string) error {
} }
options := ExecuteOptions{Envs: env} options := ExecuteOptions{Envs: env}
out, err := ExecuteResticCommand(options, args...) out, err := ExecuteResticCommand(options, args...)
if err != nil {
colors.Error.Println(out)
return err
}
if VERBOSE { if VERBOSE {
colors.Faint.Println(out) colors.Faint.Println(out)
} }
return err return nil
} }
func (b Backend) ExecDocker(l Location, args []string) error { func (b Backend) ExecDocker(l Location, args []string) (string, error) {
env, err := b.getEnv() env, err := b.getEnv()
if err != nil { if err != nil {
return err return "", err
} }
volume := l.getVolumeName() volume := l.getVolumeName()
path, _ := l.getPath() path, _ := l.getPath()
@@ -143,8 +161,5 @@ func (b Backend) ExecDocker(l Location, args []string) error {
} }
docker = append(docker, "restic/restic", "-c", "restic "+strings.Join(args, " ")) docker = append(docker, "restic/restic", "-c", "restic "+strings.Join(args, " "))
out, err := ExecuteCommand(options, docker...) out, err := ExecuteCommand(options, docker...)
if VERBOSE { return out, err
colors.Faint.Println(out)
}
return err
} }

View File

@@ -72,14 +72,21 @@ func downloadAndInstallAsset(body GithubRelease, name string) error {
// Uncompress // Uncompress
bz := bzip2.NewReader(resp.Body) bz := bzip2.NewReader(resp.Body)
// Save binary // Save to tmp
file, err := os.Create(path.Join(INSTALL_PATH, name)) // Linux does not support overwriting the file that is currently being overwritten, but it can be deleted and a new one moved in its place.
tmp, err := ioutil.TempFile(os.TempDir(), "autorestic-")
if err != nil { if err != nil {
return err return err
} }
file.Chmod(0755) defer tmp.Close()
defer file.Close() tmp.Chmod(0755)
io.Copy(file, bz) io.Copy(tmp, bz)
to := path.Join(INSTALL_PATH, name)
os.Remove(to) // Delete if current, ignore error if file does not exits.
if err := os.Rename(tmp.Name(), to); err != nil {
return nil
}
colors.Success.Printf("Successfully installed '%s' under %s\n", name, INSTALL_PATH) colors.Success.Printf("Successfully installed '%s' under %s\n", name, INSTALL_PATH)
return nil return nil
@@ -113,7 +120,9 @@ func upgradeRestic() error {
func Upgrade(restic bool) error { func Upgrade(restic bool) error {
// Upgrade restic // Upgrade restic
if restic { if restic {
InstallRestic() if err := InstallRestic(); err != nil {
colors.Error.Println(err)
}
upgradeRestic() upgradeRestic()
} }

View File

@@ -12,14 +12,15 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
) )
const VERSION = "1.0.2" const VERSION = "1.1.0"
var CI bool = false var CI bool = false
var VERBOSE bool = false var VERBOSE bool = false
var CRON_LEAN bool = false
type Config struct { type Config struct {
Locations map[string]Location `mapstructure:"locations"` Locations map[string]Location `yaml:"locations"`
Backends map[string]Backend `mapstructure:"backends"` Backends map[string]Backend `yaml:"backends"`
} }
var once sync.Once var once sync.Once
@@ -29,7 +30,9 @@ func GetConfig() *Config {
if config == nil { if config == nil {
once.Do(func() { once.Do(func() {
if err := viper.ReadInConfig(); err == nil { if err := viper.ReadInConfig(); err == nil {
if !CRON_LEAN {
colors.Faint.Println("Using config file:", viper.ConfigFileUsed()) colors.Faint.Println("Using config file:", viper.ConfigFileUsed())
}
} else { } else {
return return
} }
@@ -72,21 +75,22 @@ func (c *Config) Describe() {
colors.PrintDescription("Cron", l.Cron) colors.PrintDescription("Cron", l.Cron)
} }
after, before := len(l.Hooks.After), len(l.Hooks.Before)
if after+before > 0 {
tmp = "" tmp = ""
if before > 0 { hooks := map[string][]string{
tmp += "\tBefore" "Before": l.Hooks.Before,
for _, cmd := range 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) tmp += colors.Faint.Sprintf("\n\t ▶ %s", cmd)
} }
} }
if after > 0 {
tmp += "\n\tAfter"
for _, cmd := range l.Hooks.After {
tmp += colors.Faint.Sprintf("\n\t ▶ %s", cmd)
}
} }
if tmp != "" {
colors.PrintDescription("Hooks", tmp) colors.PrintDescription("Hooks", tmp)
} }
@@ -126,7 +130,7 @@ func CheckConfig() error {
return fmt.Errorf("config could not be loaded/found") return fmt.Errorf("config could not be loaded/found")
} }
if !CheckIfResticIsCallable() { if !CheckIfResticIsCallable() {
return fmt.Errorf(`restic was not found. Install either with "autorestic install" or manually`) return fmt.Errorf(`%s was not found. Install either with "autorestic install" or manually`, RESTIC_BIN)
} }
for name, backend := range c.Backends { for name, backend := range c.Backends {
backend.name = name backend.name = name
@@ -190,10 +194,29 @@ func GetAllOrSelected(cmd *cobra.Command, backends bool) ([]string, error) {
} }
func AddFlagsToCommand(cmd *cobra.Command, backend bool) { func AddFlagsToCommand(cmd *cobra.Command, backend bool) {
cmd.PersistentFlags().BoolP("all", "a", false, "Backup all locations") var usage string
if backend { if backend {
cmd.PersistentFlags().StringSliceP("backend", "b", []string{}, "backends") usage = "all backends"
} else { } else {
cmd.PersistentFlags().StringSliceP("location", "l", []string{}, "Locations") usage = "all locations"
}
cmd.PersistentFlags().BoolP("all", "a", false, usage)
if backend {
cmd.PersistentFlags().StringSliceP("backend", "b", []string{}, "select backends")
} else {
cmd.PersistentFlags().StringSliceP("location", "l", []string{}, "select locations")
} }
} }
func (c *Config) SaveConfig() error {
file := viper.ConfigFileUsed()
if err := CopyFile(file, file+".old"); err != nil {
return err
}
colors.Secondary.Println("Saved a backup copy of your file next the the original.")
viper.Set("backends", c.Backends)
viper.Set("locations", c.Locations)
return viper.WriteConfig()
}

View File

@@ -24,19 +24,21 @@ const (
type HookArray = []string type HookArray = []string
type Hooks struct { type Hooks struct {
Before HookArray `mapstructure:"before"` Before HookArray `yaml:"before,omitempty"`
After HookArray `mapstructure:"after"` After HookArray `yaml:"after,omitempty"`
Success HookArray `yaml:"success,omitempty"`
Failure HookArray `yaml:"failure,omitempty"`
} }
type Options map[string]map[string][]string type Options map[string]map[string][]string
type Location struct { type Location struct {
name string `mapstructure:",omitempty"` name string `yaml:",omitempty"`
From string `mapstructure:"from,omitempty"` From string `yaml:"from,omitempty"`
To []string `mapstructure:"to,omitempty"` To []string `yaml:"to,omitempty"`
Hooks Hooks `mapstructure:"hooks,omitempty"` Hooks Hooks `yaml:"hooks,omitempty"`
Cron string `mapstructure:"cron,omitempty"` Cron string `yaml:"cron,omitempty"`
Options Options `mapstructure:"options,omitempty"` Options Options `yaml:"options,omitempty"`
} }
func GetLocation(name string) (Location, bool) { func GetLocation(name string) (Location, bool) {
@@ -49,6 +51,20 @@ func (l Location) validate(c *Config) error {
if l.From == "" { if l.From == "" {
return fmt.Errorf(`Location "%s" is missing "from" key`, l.name) return fmt.Errorf(`Location "%s" is missing "from" key`, l.name)
} }
if l.getType() == TypeLocal {
if from, err := GetPathRelativeToConfig(l.From); err != nil {
return err
} else {
if stat, err := os.Stat(from); err != nil {
return err
} else {
if !stat.IsDir() {
return fmt.Errorf("\"%s\" is not valid directory for location \"%s\"", from, l.name)
}
}
}
}
if len(l.To) == 0 { if len(l.To) == 0 {
return fmt.Errorf(`Location "%s" has no "to" targets`, l.name) return fmt.Errorf(`Location "%s" has no "to" targets`, l.name)
} }
@@ -81,12 +97,13 @@ func ExecuteHooks(commands []string, options ExecuteOptions) error {
for _, command := range commands { for _, command := range commands {
colors.Body.Println("> " + command) colors.Body.Println("> " + command)
out, err := ExecuteCommand(options, "-c", command) out, err := ExecuteCommand(options, "-c", command)
if err != nil {
colors.Error.Println(out)
return err
}
if VERBOSE { if VERBOSE {
colors.Faint.Println(out) colors.Faint.Println(out)
} }
if err != nil {
return err
}
} }
colors.Body.Println("") colors.Body.Println("")
return nil return nil
@@ -118,7 +135,8 @@ func (l Location) getPath() (string, error) {
return "", fmt.Errorf("could not get path for location \"%s\"", l.name) 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) colors.PrimaryPrint(" Backing up location \"%s\" ", l.name)
t := l.getType() t := l.getType()
options := ExecuteOptions{ options := ExecuteOptions{
@@ -132,7 +150,8 @@ func (l Location) Backup(cron bool) error {
// Hooks // Hooks
if err := ExecuteHooks(l.Hooks.Before, options); err != nil { if err := ExecuteHooks(l.Hooks.Before, options); err != nil {
return err errors = append(errors, err)
goto after
} }
// Backup // Backup
@@ -141,7 +160,8 @@ func (l Location) Backup(cron bool) error {
colors.Secondary.Printf("Backend: %s\n", backend.name) colors.Secondary.Printf("Backend: %s\n", backend.name)
env, err := backend.getEnv() env, err := backend.getEnv()
if err != nil { if err != nil {
return nil errors = append(errors, err)
continue
} }
flags := l.getOptions("backup") flags := l.getOptions("backup")
@@ -161,24 +181,37 @@ func (l Location) Backup(cron bool) error {
switch t { switch t {
case TypeLocal: case TypeLocal:
out, err = ExecuteResticCommand(backupOptions, cmd...) out, err = ExecuteResticCommand(backupOptions, cmd...)
case TypeVolume:
out, err = backend.ExecDocker(l, cmd)
}
if err != nil {
colors.Error.Println(out)
errors = append(errors, err)
continue
}
if VERBOSE { if VERBOSE {
colors.Faint.Println(out) colors.Faint.Println(out)
} }
case TypeVolume:
err = backend.ExecDocker(l, cmd)
}
if err != nil {
return err
}
} }
// After hooks // After hooks
if err := ExecuteHooks(l.Hooks.After, options); err != nil { 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") colors.Success.Println("Done")
return nil return errors
} }
func (l Location) Forget(prune bool, dry bool) error { func (l Location) Forget(prune bool, dry bool) error {
@@ -271,7 +304,7 @@ func (l Location) Restore(to, from string, force bool) error {
} }
err = backend.Exec([]string{"restore", "--target", to, "--path", path, "latest"}) err = backend.Exec([]string{"restore", "--target", to, "--path", path, "latest"})
case TypeVolume: case TypeVolume:
err = backend.ExecDocker(l, []string{"restore", "--target", ".", "--path", path, "latest"}) _, err = backend.ExecDocker(l, []string{"restore", "--target", ".", "--path", path, "latest"})
} }
if err != nil { if err != nil {
return err return err
@@ -296,7 +329,9 @@ func (l Location) RunCron() error {
lock.SetCron(l.name, now.Unix()) lock.SetCron(l.name, now.Unix())
l.Backup(true) l.Backup(true)
} else { } else {
if !CRON_LEAN {
colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.name) colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.name)
} }
}
return nil return nil
} }

View File

@@ -10,13 +10,15 @@ import (
"github.com/cupcakearmy/autorestic/internal/colors" "github.com/cupcakearmy/autorestic/internal/colors"
) )
var RESTIC_BIN string
func CheckIfCommandIsCallable(cmd string) bool { func CheckIfCommandIsCallable(cmd string) bool {
_, err := exec.LookPath(cmd) _, err := exec.LookPath(cmd)
return err == nil return err == nil
} }
func CheckIfResticIsCallable() bool { func CheckIfResticIsCallable() bool {
return CheckIfCommandIsCallable("restic") return CheckIfCommandIsCallable(RESTIC_BIN)
} }
type ExecuteOptions struct { type ExecuteOptions struct {
@@ -50,7 +52,7 @@ func ExecuteCommand(options ExecuteOptions, args ...string) (string, error) {
} }
func ExecuteResticCommand(options ExecuteOptions, args ...string) (string, error) { func ExecuteResticCommand(options ExecuteOptions, args ...string) (string, error) {
options.Command = "restic" options.Command = RESTIC_BIN
return ExecuteCommand(options, args...) return ExecuteCommand(options, args...)
} }