mirror of
https://github.com/cupcakearmy/autorestic.git
synced 2025-09-06 02:20:39 +00:00
Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
9256cdc38c | |||
a8c611e8ce | |||
d4522c7ffe | |||
21185d894e | |||
b119fc7ea5 | |||
|
73f4bcfd48 | ||
|
3567319314 | ||
|
bf19c983d1 | ||
|
12e4de110b | ||
c9f425ef64 | |||
974f555dff | |||
1688c1f3c3 | |||
29e46d3b5c | |||
0335abb669 | |||
b2f9b9a54e | |||
2b13a6e13d | |||
cc293ea256 | |||
a4ddd5bbcb | |||
7cbf43b75d | |||
bae77c4673 | |||
12adeb2b06 | |||
37b26dfc31 | |||
c1795b2acc | |||
b8d12e518c | |||
50060cf539 | |||
c33aac42dc | |||
c359053e0e | |||
c16340ab26 | |||
edc85c4ac3 | |||
68682777f2 | |||
|
b6c7922df5 | ||
|
991b8bec22 | ||
bbc32568ad | |||
f3c038c716 | |||
59612a97b6 | |||
33319a00ef | |||
8eb14ea14f | |||
70eb9e441f | |||
be25af2d76 | |||
1c436369f0 | |||
6efcce07b7 | |||
|
dc6dd2e712 | ||
|
68628d3776 | ||
40988ef3b4 | |||
fad33fcdaa | |||
|
8cf8a77558 |
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@@ -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:
|
||||||
|
36
CHANGELOG.md
36
CHANGELOG.md
@@ -5,6 +5,42 @@ 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.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
|
## [1.0.4] - 2021-04-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@@ -21,3 +21,9 @@ Releases are automatically built by the github workflow and uploaded to the rele
|
|||||||
3. Commit to master
|
3. Commit to master
|
||||||
4. Create a new release with the `v1.2.3` tag and mark as draft.
|
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.
|
5. The Github action will build the binaries, upload and mark the release as ready when done.
|
||||||
|
|
||||||
|
### Brew
|
||||||
|
|
||||||
|
1. Check the checksum with `shasum -a 256 autorestic-1.2.3.tar.gz`
|
||||||
|
2. Update `url` and `sha256` in the brew repo.
|
||||||
|
3. Submit PR
|
||||||
|
@@ -10,6 +10,10 @@
|
|||||||
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" />
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -35,7 +39,7 @@ 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
|
## Contributing / Developing
|
||||||
|
|
||||||
|
@@ -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()
|
||||||
}
|
}
|
||||||
|
@@ -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"
|
||||||
)
|
)
|
||||||
@@ -18,9 +21,17 @@ var backupCmd = &cobra.Command{
|
|||||||
|
|
||||||
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)
|
err := location.Backup(false)
|
||||||
|
if err != nil {
|
||||||
|
colors.Error.Println(err)
|
||||||
|
errors++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errors > 0 {
|
||||||
|
CheckErr(fmt.Errorf("%d errors were found", errors))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -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.")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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")
|
||||||
}
|
}
|
||||||
|
@@ -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")
|
||||||
}
|
}
|
||||||
|
@@ -57,5 +57,4 @@ func initConfig() {
|
|||||||
viper.SetConfigName(".autorestic")
|
viper.SetConfigName(".autorestic")
|
||||||
}
|
}
|
||||||
viper.AutomaticEnv()
|
viper.AutomaticEnv()
|
||||||
internal.GetConfig()
|
|
||||||
}
|
}
|
||||||
|
@@ -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.")
|
||||||
}
|
}
|
||||||
|
@@ -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")
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
||||||
|
@@ -19,16 +19,17 @@ backends:
|
|||||||
backends:
|
backends:
|
||||||
name-of-backend:
|
name-of-backend:
|
||||||
type: b2
|
type: b2
|
||||||
path: 'myAccount:myBucket/my/path'
|
path: 'backblaze_bucketID'
|
||||||
|
# Or With a path
|
||||||
|
# path: 'backblaze_bucketID:/some/path'
|
||||||
env:
|
env:
|
||||||
B2_ACCOUNT_ID: backblaze_account_id
|
B2_ACCOUNT_ID: 'backblaze_keyID'
|
||||||
B2_ACCOUNT_KEY: backblaze_account_key
|
B2_ACCOUNT_KEY: 'backblaze_applicationKey'
|
||||||
```
|
```
|
||||||
|
|
||||||
#### API Keys gotcha
|
#### API Keys gotcha
|
||||||
|
|
||||||
When creating API make sure you check _Allow List All Bucket Names_ if you allow access to a single bucket only.
|
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'`).
|
||||||
Also make sure that the _File name prefix_ (if used) does not includes a leading slash.
|
|
||||||
|
|
||||||
## S3 / Minio
|
## S3 / Minio
|
||||||
|
|
||||||
|
17
docs/markdown/cli/completion.md
Normal file
17
docs/markdown/cli/completion.md
Normal 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
|
@@ -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
|
||||||
|
@@ -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.
|
||||||
|
@@ -6,7 +6,7 @@ autorestic restore [-l, --location] [--from backend] [--to <out dir>] [-f, --for
|
|||||||
|
|
||||||
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 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.
|
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
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -3,9 +3,14 @@
|
|||||||
This amazing people helped the project!
|
This amazing people helped the project!
|
||||||
|
|
||||||
- @agateblue - Docs, Pruning, S3
|
- @agateblue - Docs, Pruning, S3
|
||||||
|
- @david-boles - Docs
|
||||||
|
- @SebDanielsson - Brew
|
||||||
|
- @n194 - AUR Package
|
||||||
- @jin-park-dev - Typos
|
- @jin-park-dev - Typos
|
||||||
- @sumnerboy12 - Typos
|
- @sumnerboy12 - Typos
|
||||||
- @FuzzyMistborn - Typos
|
- @FuzzyMistborn - Typos
|
||||||
- @ChanceM - Typos
|
- @ChanceM - Typos
|
||||||
|
- @TheForcer - Typos
|
||||||
|
- @themorlan - Typos
|
||||||
|
|
||||||
> :ToCPrevNext
|
> :ToCPrevNext
|
||||||
|
@@ -8,7 +8,7 @@ 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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
19
docs/markdown/location/options.md
Normal file
19
docs/markdown/location/options.md
Normal 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
|
@@ -6,10 +6,12 @@
|
|||||||
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:
|
||||||
@@ -35,7 +37,7 @@ locations:
|
|||||||
- 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
|
||||||
@@ -43,7 +45,7 @@ backends:
|
|||||||
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'
|
||||||
@@ -52,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.
|
||||||
|
@@ -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
|
||||||
|
@@ -48,7 +48,7 @@ func (b Backend) generateRepo() (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s:%s", b.Type, parsed.String()), nil
|
return fmt.Sprintf("%s:%s", b.Type, parsed.String()), nil
|
||||||
case "b2", "azure", "gs", "s3", "sftp":
|
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)
|
||||||
@@ -121,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()
|
||||||
@@ -157,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
|
|
||||||
}
|
}
|
||||||
|
@@ -120,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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,10 +12,11 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const VERSION = "1.0.4"
|
const VERSION = "1.0.9"
|
||||||
|
|
||||||
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 `yaml:"locations"`
|
Locations map[string]Location `yaml:"locations"`
|
||||||
@@ -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 {
|
||||||
colors.Faint.Println("Using config file:", viper.ConfigFileUsed())
|
if !CRON_LEAN {
|
||||||
|
colors.Faint.Println("Using config file:", viper.ConfigFileUsed())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -190,11 +193,17 @@ 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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,6 +49,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 +95,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
|
||||||
@@ -161,16 +176,16 @@ 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...)
|
||||||
if VERBOSE {
|
|
||||||
colors.Faint.Println(out)
|
|
||||||
}
|
|
||||||
case TypeVolume:
|
case TypeVolume:
|
||||||
err = backend.ExecDocker(l, cmd)
|
out, err = backend.ExecDocker(l, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
colors.Error.Println(out)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if VERBOSE {
|
||||||
|
colors.Faint.Println(out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// After hooks
|
// After hooks
|
||||||
@@ -271,7 +286,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 +311,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 {
|
||||||
colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.name)
|
if !CRON_LEAN {
|
||||||
|
colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user