Compare commits

..

26 Commits

Author SHA1 Message Date
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
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
ea82fea8e1 add cron tag 2021-04-20 20:49:09 +02:00
a35edcaea5 version bump 2021-04-17 20:55:09 +02:00
86d44eafad exit with better message 2021-04-17 20:51:40 +02:00
e927fd5a64 panic on already running 2021-04-17 20:45:52 +02:00
d5e13d4e27 changelog 2021-04-17 17:54:24 +02:00
824c90904c docs 2021-04-17 17:51:23 +02:00
58fb5e073a Update README.md 2021-04-17 17:50:53 +02:00
541a7c2a72 add autocompletetions 2021-04-17 17:48:31 +02:00
28 changed files with 2210 additions and 1436 deletions

49
CHANGELOG.md Normal file
View File

@@ -0,0 +1,49 @@
# Changelog
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/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [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
### Added
- Add the `cron` tag to backup to backups made with cron.
### Fixed
- Don't unlock lockfile if process is already running.
## [1.0.1] - 2021-04-17
### Added
- Completion command for various shells
## [1.0.0] - 2021-04-17
- Rewrite in go. See https://autorestic.vercel.app/upgrade for migration.

23
DEVELOPMENT.md Normal file
View File

@@ -0,0 +1,23 @@
# 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.

View File

@@ -16,10 +16,28 @@
<br>
<br>
### Why / What?
### 💭 Why / What?
Autorestic is a wrapper around the amazing [restic](https://restic.net/). While being amazing the restic cli can be a bit overwhelming and difficult to manage if you have many different location that you want to backup to multiple locations. This utility is aimed at making this easier 🙂
### Questions / Support
### 🌈 Features
- YAML config files, no CLI
- Incremental -> Minimal space is used
- Backup locations to multiple backends
- Snapshot policies and pruning
- Fully encrypted
- Pre/After hooks
- Exclude pattern/files
- Cron jobs for automatic backup
- Backup & Restore docker volume
- Generated completions for `[bash|zsh|fish|powershell]`
### ❓ Questions / Support
Check the [discussions page](https://github.com/cupcakearmy/autorestic/discussions)
## 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

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

70
cmd/completion.go Normal file
View File

@@ -0,0 +1,70 @@
package cmd
import (
"os"
"github.com/spf13/cobra"
)
var completionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script",
Long: `To load completions:
Bash:
$ source <(autorestic completion bash)
# To load completions for each session, execute once:
# Linux:
$ autorestic completion bash > /etc/bash_completion.d/autorestic
# macOS:
$ autorestic completion bash > /usr/local/etc/bash_completion.d/autorestic
Zsh:
# If shell completion is not already enabled in your environment,
# you will need to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ autorestic completion zsh > "${fpath[1]}/_autorestic"
# You will need to start a new shell for this setup to take effect.
fish:
$ autorestic completion fish | source
# To load completions for each session, execute once:
$ autorestic completion fish > ~/.config/fish/completions/autorestic.fish
PowerShell:
PS> autorestic completion powershell | Out-String | Invoke-Expression
# To load completions for every new session, run:
PS> autorestic completion powershell > autorestic.ps1
# and source this file from your PowerShell profile.
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.ExactValidArgs(1),
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "bash":
cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
cmd.Root().GenFishCompletion(os.Stdout, true)
case "powershell":
cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
}
},
}
func init() {
rootCmd.AddCommand(completionCmd)
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -20,10 +20,16 @@ backends:
name-of-backend:
type: b2
path: 'myAccount:myBucket/my/path'
env:
B2_ACCOUNT_ID: backblaze_account_id
B2_ACCOUNT_KEY: backblaze_account_key
```
#### API Keys gotcha
When creating API make sure you check _Allow List All Bucket Names_ if you allow access to a single bucket only.
Also make sure that the _File name prefix_ (if used) does not includes a leading slash.
## S3 / Minio
```yaml
@@ -33,6 +39,7 @@ backends:
path: s3.amazonaws.com/bucket_name
# Minio
# path: http://localhost:9000/bucket_name
env:
AWS_ACCESS_KEY_ID: my_key
AWS_SECRET_ACCESS_KEY: my_secret
```
@@ -57,6 +64,21 @@ backends:
name-of-backend:
type: rest
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

View File

@@ -1,6 +1,6 @@
# 💽 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
backends:

View File

@@ -6,6 +6,6 @@ autorestic cron
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.
> :ToCPrevNext

View File

@@ -26,3 +26,5 @@ Verbose mode will show the output of the native restic commands that are otherwi
```bash
autorestic --verbose backup -a
```
> :ToCPrevNext

View File

@@ -1,11 +1,13 @@
# Restore
```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.
The `--to` path das 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
```bash

View File

@@ -2,7 +2,11 @@
This amazing people helped the project!
- @ChanceM [Docs]
- @EliotBerriot [Docs, Pruning, S3]
- @agateblue - Docs, Pruning, S3
- @jin-park-dev - Typos
- @sumnerboy12 - Typos
- @FuzzyMistborn - Typos
- @ChanceM - Typos
- @TheForcer - Typos
> :ToCPrevNext

View File

@@ -3,7 +3,7 @@
## List all the snapshots for all the backends
```bash
autorestic exec -a -- snapshots
autorestic exec -av -- snapshots
```
## Unlock a locked repository

View File

@@ -17,5 +17,6 @@ Autorestic is a wrapper around the amazing [restic](https://restic.net/). While
- Exclude pattern/files
- Cron jobs for automatic backup
- Backup & Restore docker volumes
- Generated completions for `[bash|zsh|fish|powershell]`
> :ToCPrevNext

View File

@@ -1,6 +1,6 @@
# 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
locations:
@@ -14,11 +14,11 @@ Here is a awesome website with [some examples](https://crontab.guru/examples.htm
## 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.
Note that the shedule 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.
To actually enable cron jobs you need something to call `autorestic cron` on a timed schedule.
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 schedule it once a day.
### Crontab

View File

@@ -1,6 +1,6 @@
# 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.

View File

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

View File

@@ -22,6 +22,6 @@ Paths can be absolute or relative. If relative they are resolved relative to the
## `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

View File

@@ -15,7 +15,7 @@ vim .autorestic.yml
For a quick overview:
- `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`.
> **⚠️ WARNING ⚠️**
@@ -24,11 +24,11 @@ For a quick overview:
```yaml | .autorestic.yml
locations:
- name: home
home:
from: /home/me
to: remote
- name: important
important:
from: /path/to/important/stuff
to:
- remote
@@ -39,6 +39,7 @@ backends:
type: s3
path: 's3.amazonaws.com/bucket_name'
key: some-random-password-198rc79r8y1029c8yfewj8f1u0ef87yh198uoieufy
env:
AWS_ACCESS_KEY_ID: account_id
AWS_SECRET_ACCESS_KEY: account_key

12
docs/package-lock.json generated
View File

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

View File

@@ -36,4 +36,4 @@ bzip2 -fd "${OUT_FILE}.bz2"
chmod +x ${OUT_FILE}
autorestic install
echo "Succefsully installed autorestic"
echo "Successfully installed autorestic"

View File

@@ -4,19 +4,25 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
"net/url"
"os"
"strings"
"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 {
name string
Type string `mapstructure:"type,omitempty"`
Path string `mapstructure:"path,omitempty"`
Key string `mapstructure:"key,omitempty"`
Env map[string]string `mapstructure:"env,omitempty"`
Type string `yaml:"type,omitempty"`
Path string `yaml:"path,omitempty"`
Key string `yaml:"key,omitempty"`
Env map[string]string `yaml:"env,omitempty"`
Rest BackendRest `yaml:"rest,omitempty"`
}
func GetBackend(name string) (Backend, bool) {
@@ -29,7 +35,20 @@ func (b Backend) generateRepo() (string, error) {
switch b.Type {
case "local":
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":
return fmt.Sprintf("%s:%s", b.Type, b.Path), nil
default:
return "", fmt.Errorf("backend type \"%s\" is invalid", b.Type)
@@ -70,15 +89,10 @@ func (b Backend) validate() error {
c := GetConfig()
tmp := c.Backends[b.name]
tmp.Key = key
tmp.name = ""
c.Backends[b.name] = tmp
file := viper.ConfigFileUsed()
if err := CopyFile(file, file+".old"); err != nil {
if err := c.SaveConfig(); err != nil {
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()
if err != nil {
@@ -107,16 +121,20 @@ func (b Backend) Exec(args []string) error {
}
options := ExecuteOptions{Envs: env}
out, err := ExecuteResticCommand(options, args...)
if err != nil {
colors.Error.Println(out)
return err
}
if VERBOSE {
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()
if err != nil {
return err
return "", err
}
volume := l.getVolumeName()
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, " "))
out, err := ExecuteCommand(options, docker...)
if VERBOSE {
colors.Faint.Println(out)
}
return err
return out, err
}

View File

@@ -72,14 +72,21 @@ func downloadAndInstallAsset(body GithubRelease, name string) error {
// Uncompress
bz := bzip2.NewReader(resp.Body)
// Save binary
file, err := os.Create(path.Join(INSTALL_PATH, name))
// Save to tmp
// 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 {
return err
}
file.Chmod(0755)
defer file.Close()
io.Copy(file, bz)
defer tmp.Close()
tmp.Chmod(0755)
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)
return nil

View File

@@ -12,14 +12,14 @@ import (
"github.com/spf13/viper"
)
const VERSION = "1.0.0"
const VERSION = "1.0.5"
var CI bool = false
var VERBOSE bool = false
type Config struct {
Locations map[string]Location `mapstructure:"locations"`
Backends map[string]Backend `mapstructure:"backends"`
Locations map[string]Location `yaml:"locations"`
Backends map[string]Backend `yaml:"backends"`
}
var once sync.Once
@@ -197,3 +197,16 @@ func AddFlagsToCommand(cmd *cobra.Command, backend bool) {
cmd.PersistentFlags().StringSliceP("location", "l", []string{}, "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,19 @@ const (
type HookArray = []string
type Hooks struct {
Before HookArray `mapstructure:"before"`
After HookArray `mapstructure:"after"`
Before HookArray `yaml:"before"`
After HookArray `yaml:"after"`
}
type Options map[string]map[string][]string
type Location struct {
name string `mapstructure:",omitempty"`
From string `mapstructure:"from,omitempty"`
To []string `mapstructure:"to,omitempty"`
Hooks Hooks `mapstructure:"hooks,omitempty"`
Cron string `mapstructure:"cron,omitempty"`
Options Options `mapstructure:"options,omitempty"`
name string `yaml:",omitempty"`
From string `yaml:"from,omitempty"`
To []string `yaml:"to,omitempty"`
Hooks Hooks `yaml:"hooks,omitempty"`
Cron string `yaml:"cron,omitempty"`
Options Options `yaml:"options,omitempty"`
}
func GetLocation(name string) (Location, bool) {
@@ -49,6 +49,18 @@ func (l Location) validate(c *Config) error {
if l.From == "" {
return fmt.Errorf(`Location "%s" is missing "from" key`, l.name)
}
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 {
return fmt.Errorf(`Location "%s" has no "to" targets`, l.name)
}
@@ -81,12 +93,13 @@ func ExecuteHooks(commands []string, options ExecuteOptions) error {
for _, command := range commands {
colors.Body.Println("> " + command)
out, err := ExecuteCommand(options, "-c", command)
if err != nil {
colors.Error.Println(out)
return err
}
if VERBOSE {
colors.Faint.Println(out)
}
if err != nil {
return err
}
}
colors.Body.Println("")
return nil
@@ -118,7 +131,7 @@ func (l Location) getPath() (string, error) {
return "", fmt.Errorf("could not get path for location \"%s\"", l.name)
}
func (l Location) Backup() error {
func (l Location) Backup(cron bool) error {
colors.PrimaryPrint(" Backing up location \"%s\" ", l.name)
t := l.getType()
options := ExecuteOptions{
@@ -147,6 +160,9 @@ func (l Location) Backup() error {
flags := l.getOptions("backup")
cmd := []string{"backup"}
cmd = append(cmd, flags...)
if cron {
cmd = append(cmd, "--tag", "cron")
}
cmd = append(cmd, ".")
backupOptions := ExecuteOptions{
Dir: options.Dir,
@@ -158,16 +174,16 @@ func (l Location) Backup() error {
switch t {
case TypeLocal:
out, err = ExecuteResticCommand(backupOptions, cmd...)
case TypeVolume:
out, err = backend.ExecDocker(l, cmd)
}
if err != nil {
colors.Error.Println(out)
return err
}
if VERBOSE {
colors.Faint.Println(out)
}
case TypeVolume:
err = backend.ExecDocker(l, cmd)
}
if err != nil {
return err
}
}
// After hooks
@@ -268,7 +284,7 @@ func (l Location) Restore(to, from string, force bool) error {
}
err = backend.Exec([]string{"restore", "--target", to, "--path", path, "latest"})
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 {
return err
@@ -291,7 +307,7 @@ func (l Location) RunCron() error {
now := time.Now()
if now.After(next) {
lock.SetCron(l.name, now.Unix())
l.Backup()
l.Backup(true)
} else {
colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.name)
}

View File

@@ -1,10 +1,11 @@
package lock
import (
"errors"
"os"
"path"
"sync"
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/spf13/viper"
)
@@ -33,7 +34,8 @@ func setLock(locked bool) error {
if locked {
running := lock.GetBool("running")
if running {
return errors.New("an instance is already running")
colors.Error.Println("an instance is already running. exiting")
os.Exit(1)
}
}
lock.Set("running", locked)