* stream the output (#186)

* dont duplicate global flags (#187)

* docs for tagging

* fix self update path (#190)

* version bump & changelog
pull/197/head v1.7.0
Nicco 3 years ago committed by GitHub
parent ff2e3714d1
commit 5bcf5c9217
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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
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.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…
Cancel
Save