mirror of
https://github.com/cupcakearmy/autorestic.git
synced 2024-12-22 08:16:25 +00:00
1.7.0 (#188)
* stream the output (#186) * dont duplicate global flags (#187) * docs for tagging * fix self update path (#190) * version bump & changelog
This commit is contained in:
parent
ff2e3714d1
commit
5bcf5c9217
14
CHANGELOG.md
14
CHANGELOG.md
@ -5,11 +5,23 @@ 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.7.0] - 2022-04-27
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- #147 Stream output instead of buffering.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #184 duplicate global options.
|
||||||
|
- #154 add docs for migration.
|
||||||
|
- #182 fix bug with upgrading custom restic with custom path.
|
||||||
|
|
||||||
## [1.6.2] - 2022-04-14
|
## [1.6.2] - 2022-04-14
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Version bump in code
|
- Version bump in code.
|
||||||
|
|
||||||
## [1.6.1] - 2022-04-14
|
## [1.6.1] - 2022-04-14
|
||||||
|
|
||||||
|
@ -40,7 +40,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(&flags.CI, "ci", false, "CI mode disabled interactive mode and colors and enables verbosity")
|
rootCmd.PersistentFlags().BoolVar(&flags.CI, "ci", false, "CI mode disabled interactive mode and colors and enables verbosity")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&flags.VERBOSE, "verbose", "v", false, "verbose mode")
|
rootCmd.PersistentFlags().BoolVarP(&flags.VERBOSE, "verbose", "v", false, "verbose mode")
|
||||||
rootCmd.PersistentFlags().StringVar(&internal.RESTIC_BIN, "restic-bin", "restic", "specify custom restic binary")
|
rootCmd.PersistentFlags().StringVar(&flags.RESTIC_BIN, "restic-bin", "restic", "specify custom restic binary")
|
||||||
cobra.OnInitialize(initConfig)
|
cobra.OnInitialize(initConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,4 +57,12 @@ locations:
|
|||||||
type: volume
|
type: volume
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Tagging
|
||||||
|
|
||||||
|
Autorestic changed the way backups are referenced. Before we took the paths as the identifying information. Now autorestic uses native restic tags to reference them. This means that old backups are not referenced. You can the old snapshots manually. An example can be shown below.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
autorestic exec -va -- tag --add ar:location:LOCATION_NAME # Only if you have only one location
|
||||||
|
```
|
||||||
|
|
||||||
> :ToCPrevNext
|
> :ToCPrevNext
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cupcakearmy/autorestic/internal/colors"
|
"github.com/cupcakearmy/autorestic/internal/colors"
|
||||||
"github.com/cupcakearmy/autorestic/internal/flags"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BackendRest struct {
|
type BackendRest struct {
|
||||||
@ -120,18 +119,15 @@ func (b Backend) validate() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
options := ExecuteOptions{Envs: env}
|
options := ExecuteOptions{Envs: env, Silent: true}
|
||||||
// Check if already initialized
|
// Check if already initialized
|
||||||
_, _, err = ExecuteResticCommand(options, "snapshots")
|
_, _, err = ExecuteResticCommand(options, "check")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
// If not initialize
|
// If not initialize
|
||||||
colors.Body.Printf("Initializing backend \"%s\"...\n", b.name)
|
colors.Body.Printf("Initializing backend \"%s\"...\n", b.name)
|
||||||
_, out, err := ExecuteResticCommand(options, "init")
|
_, _, err := ExecuteResticCommand(options, "init")
|
||||||
if flags.VERBOSE {
|
|
||||||
colors.Faint.Println(out)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,9 +143,6 @@ func (b Backend) Exec(args []string) error {
|
|||||||
colors.Error.Println(out)
|
colors.Error.Println(out)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if flags.VERBOSE {
|
|
||||||
colors.Faint.Println(out)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/blang/semver/v4"
|
"github.com/blang/semver/v4"
|
||||||
"github.com/cupcakearmy/autorestic/internal"
|
"github.com/cupcakearmy/autorestic/internal"
|
||||||
"github.com/cupcakearmy/autorestic/internal/colors"
|
"github.com/cupcakearmy/autorestic/internal/colors"
|
||||||
|
"github.com/cupcakearmy/autorestic/internal/flags"
|
||||||
)
|
)
|
||||||
|
|
||||||
const INSTALL_PATH = "/usr/local/bin"
|
const INSTALL_PATH = "/usr/local/bin"
|
||||||
@ -128,10 +129,9 @@ func InstallRestic() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func upgradeRestic() error {
|
func upgradeRestic() error {
|
||||||
_, out, err := internal.ExecuteCommand(internal.ExecuteOptions{
|
_, _, err := internal.ExecuteCommand(internal.ExecuteOptions{
|
||||||
Command: "restic",
|
Command: flags.RESTIC_BIN,
|
||||||
}, "self-update")
|
}, "self-update")
|
||||||
colors.Faint.Println(out)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const VERSION = "1.6.2"
|
const VERSION = "1.7.0"
|
||||||
|
|
||||||
type OptionMap map[string][]interface{}
|
type OptionMap map[string][]interface{}
|
||||||
type Options map[string]OptionMap
|
type Options map[string]OptionMap
|
||||||
@ -185,7 +185,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(`%s was not found. Install either with "autorestic install" or manually`, RESTIC_BIN)
|
return fmt.Errorf(`%s was not found. Install either with "autorestic install" or manually`, flags.RESTIC_BIN)
|
||||||
}
|
}
|
||||||
for name, backend := range c.Backends {
|
for name, backend := range c.Backends {
|
||||||
backend.name = name
|
backend.name = name
|
||||||
@ -295,12 +295,8 @@ func appendOptionsToSlice(str *[]string, options OptionMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOptions(options Options, key string) []string {
|
func getOptions(options Options, keys []string) []string {
|
||||||
var selected []string
|
var selected []string
|
||||||
var keys = []string{"all"}
|
|
||||||
if key != "" {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
appendOptionsToSlice(&selected, options[key])
|
appendOptionsToSlice(&selected, options[key])
|
||||||
}
|
}
|
||||||
@ -310,9 +306,9 @@ func getOptions(options Options, key string) []string {
|
|||||||
func combineOptions(key string, l Location, b Backend) []string {
|
func combineOptions(key string, l Location, b Backend) []string {
|
||||||
// Priority: location > backend > global
|
// Priority: location > backend > global
|
||||||
var options []string
|
var options []string
|
||||||
gFlags := getOptions(GetConfig().Global, key)
|
gFlags := getOptions(GetConfig().Global, []string{key})
|
||||||
bFlags := getOptions(b.Options, key)
|
bFlags := getOptions(b.Options, []string{"all", key})
|
||||||
lFlags := getOptions(l.Options, key)
|
lFlags := getOptions(l.Options, []string{"all", key})
|
||||||
options = append(options, gFlags...)
|
options = append(options, gFlags...)
|
||||||
options = append(options, bFlags...)
|
options = append(options, bFlags...)
|
||||||
options = append(options, lFlags...)
|
options = append(options, lFlags...)
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package flags
|
package flags
|
||||||
|
|
||||||
var CI bool = false
|
var (
|
||||||
var VERBOSE bool = false
|
CI bool = false
|
||||||
var CRON_LEAN bool = false
|
VERBOSE bool = false
|
||||||
|
CRON_LEAN bool = false
|
||||||
|
RESTIC_BIN string
|
||||||
|
)
|
||||||
|
@ -146,9 +146,6 @@ func (l Location) ExecuteHooks(commands []string, options ExecuteOptions) error
|
|||||||
colors.Error.Println(out)
|
colors.Error.Println(out)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if flags.VERBOSE {
|
|
||||||
colors.Faint.Println(out)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
colors.Body.Println("")
|
colors.Body.Println("")
|
||||||
return nil
|
return nil
|
||||||
@ -284,24 +281,16 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
|
|||||||
for k, v := range env2 {
|
for k, v := range env2 {
|
||||||
env[k+"2"] = v
|
env[k+"2"] = v
|
||||||
}
|
}
|
||||||
_, out, err := ExecuteResticCommand(ExecuteOptions{
|
_, _, err := ExecuteResticCommand(ExecuteOptions{
|
||||||
Envs: env,
|
Envs: env,
|
||||||
}, "copy", md.SnapshotID)
|
}, "copy", md.SnapshotID)
|
||||||
|
|
||||||
if flags.VERBOSE {
|
|
||||||
colors.Faint.Println(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors = append(errors, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.VERBOSE {
|
|
||||||
colors.Faint.Println(out)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// After hooks
|
// After hooks
|
||||||
@ -353,10 +342,7 @@ func (l Location) Forget(prune bool, dry bool) error {
|
|||||||
cmd = append(cmd, "--dry-run")
|
cmd = append(cmd, "--dry-run")
|
||||||
}
|
}
|
||||||
cmd = append(cmd, combineOptions("forget", l, backend)...)
|
cmd = append(cmd, combineOptions("forget", l, backend)...)
|
||||||
_, out, err := ExecuteResticCommand(options, cmd...)
|
_, _, err = ExecuteResticCommand(options, cmd...)
|
||||||
if flags.VERBOSE {
|
|
||||||
colors.Faint.Println(out)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -9,23 +9,34 @@ import (
|
|||||||
|
|
||||||
"github.com/cupcakearmy/autorestic/internal/colors"
|
"github.com/cupcakearmy/autorestic/internal/colors"
|
||||||
"github.com/cupcakearmy/autorestic/internal/flags"
|
"github.com/cupcakearmy/autorestic/internal/flags"
|
||||||
|
"github.com/fatih/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
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_BIN)
|
return CheckIfCommandIsCallable(flags.RESTIC_BIN)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExecuteOptions struct {
|
type ExecuteOptions struct {
|
||||||
Command string
|
Command string
|
||||||
Envs map[string]string
|
Envs map[string]string
|
||||||
Dir string
|
Dir string
|
||||||
|
Silent bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ColoredWriter struct {
|
||||||
|
target io.Writer
|
||||||
|
color *color.Color
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w ColoredWriter) Write(p []byte) (n int, err error) {
|
||||||
|
colored := []byte(w.color.Sprint(string(p)))
|
||||||
|
w.target.Write(colored)
|
||||||
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecuteCommand(options ExecuteOptions, args ...string) (int, string, error) {
|
func ExecuteCommand(options ExecuteOptions, args ...string) (int, string, error) {
|
||||||
@ -43,23 +54,32 @@ func ExecuteCommand(options ExecuteOptions, args ...string) (int, string, error)
|
|||||||
|
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
var error bytes.Buffer
|
var error bytes.Buffer
|
||||||
cmd.Stdout = &out
|
if flags.VERBOSE && !options.Silent {
|
||||||
|
var colored ColoredWriter = ColoredWriter{
|
||||||
|
target: os.Stdout,
|
||||||
|
color: colors.Faint,
|
||||||
|
}
|
||||||
|
mw := io.MultiWriter(colored, &out)
|
||||||
|
cmd.Stdout = mw
|
||||||
|
} else {
|
||||||
|
cmd.Stdout = &out
|
||||||
|
}
|
||||||
cmd.Stderr = &error
|
cmd.Stderr = &error
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
code := -1
|
||||||
if exitError, ok := err.(*exec.ExitError); ok {
|
if exitError, ok := err.(*exec.ExitError); ok {
|
||||||
return exitError.ExitCode(), error.String(), err
|
code = exitError.ExitCode()
|
||||||
} else {
|
|
||||||
return -1, error.String(), err
|
|
||||||
}
|
}
|
||||||
|
return code, error.String(), err
|
||||||
}
|
}
|
||||||
return 0, out.String(), nil
|
return 0, out.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecuteResticCommand(options ExecuteOptions, args ...string) (int, string, error) {
|
func ExecuteResticCommand(options ExecuteOptions, args ...string) (int, string, error) {
|
||||||
options.Command = RESTIC_BIN
|
options.Command = flags.RESTIC_BIN
|
||||||
var c = GetConfig()
|
var c = GetConfig()
|
||||||
var optionsAsString = getOptions(c.Global, "")
|
var optionsAsString = getOptions(c.Global, []string{"all"})
|
||||||
args = append(optionsAsString, args...)
|
args = append(optionsAsString, args...)
|
||||||
return ExecuteCommand(options, args...)
|
return ExecuteCommand(options, args...)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user