From 5bcf5c921740434311a427180fbcb1a9de2d8443 Mon Sep 17 00:00:00 2001 From: Nicco Date: Wed, 27 Apr 2022 00:48:52 +0200 Subject: [PATCH] 1.7.0 (#188) * stream the output (#186) * dont duplicate global flags (#187) * docs for tagging * fix self update path (#190) * version bump & changelog --- CHANGELOG.md | 14 ++++++++++- cmd/root.go | 2 +- docs/markdown/migration/1.4_1.5.md | 8 +++++++ internal/backend.go | 13 +++------- internal/bins/bins.go | 6 ++--- internal/config.go | 16 +++++-------- internal/flags/flags.go | 9 ++++--- internal/location.go | 18 ++------------ internal/utils.go | 38 +++++++++++++++++++++++------- 9 files changed, 71 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8d8355..fbac014 100644 --- a/CHANGELOG.md +++ b/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/), 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 ### Fixed -- Version bump in code +- Version bump in code. ## [1.6.1] - 2022-04-14 diff --git a/cmd/root.go b/cmd/root.go index 8e18712..a9ea49b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -40,7 +40,7 @@ func init() { 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().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) } diff --git a/docs/markdown/migration/1.4_1.5.md b/docs/markdown/migration/1.4_1.5.md index 349bc40..c402004 100644 --- a/docs/markdown/migration/1.4_1.5.md +++ b/docs/markdown/migration/1.4_1.5.md @@ -57,4 +57,12 @@ locations: 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 diff --git a/internal/backend.go b/internal/backend.go index 745b800..40bb9d6 100644 --- a/internal/backend.go +++ b/internal/backend.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/cupcakearmy/autorestic/internal/colors" - "github.com/cupcakearmy/autorestic/internal/flags" ) type BackendRest struct { @@ -120,18 +119,15 @@ func (b Backend) validate() error { if err != nil { return err } - options := ExecuteOptions{Envs: env} + options := ExecuteOptions{Envs: env, Silent: true} // Check if already initialized - _, _, err = ExecuteResticCommand(options, "snapshots") + _, _, err = ExecuteResticCommand(options, "check") if err == nil { return nil } else { // If not initialize colors.Body.Printf("Initializing backend \"%s\"...\n", b.name) - _, out, err := ExecuteResticCommand(options, "init") - if flags.VERBOSE { - colors.Faint.Println(out) - } + _, _, err := ExecuteResticCommand(options, "init") return err } } @@ -147,9 +143,6 @@ func (b Backend) Exec(args []string) error { colors.Error.Println(out) return err } - if flags.VERBOSE { - colors.Faint.Println(out) - } return nil } diff --git a/internal/bins/bins.go b/internal/bins/bins.go index 104efcb..111df3a 100644 --- a/internal/bins/bins.go +++ b/internal/bins/bins.go @@ -16,6 +16,7 @@ import ( "github.com/blang/semver/v4" "github.com/cupcakearmy/autorestic/internal" "github.com/cupcakearmy/autorestic/internal/colors" + "github.com/cupcakearmy/autorestic/internal/flags" ) const INSTALL_PATH = "/usr/local/bin" @@ -128,10 +129,9 @@ func InstallRestic() error { } func upgradeRestic() error { - _, out, err := internal.ExecuteCommand(internal.ExecuteOptions{ - Command: "restic", + _, _, err := internal.ExecuteCommand(internal.ExecuteOptions{ + Command: flags.RESTIC_BIN, }, "self-update") - colors.Faint.Println(out) return err } diff --git a/internal/config.go b/internal/config.go index 5d11b49..0c0b38d 100644 --- a/internal/config.go +++ b/internal/config.go @@ -17,7 +17,7 @@ import ( "github.com/spf13/viper" ) -const VERSION = "1.6.2" +const VERSION = "1.7.0" type OptionMap map[string][]interface{} type Options map[string]OptionMap @@ -185,7 +185,7 @@ func CheckConfig() error { return fmt.Errorf("config could not be loaded/found") } 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 { 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 keys = []string{"all"} - if key != "" { - keys = append(keys, key) - } for _, key := range keys { appendOptionsToSlice(&selected, options[key]) } @@ -310,9 +306,9 @@ func getOptions(options Options, key string) []string { func combineOptions(key string, l Location, b Backend) []string { // Priority: location > backend > global var options []string - gFlags := getOptions(GetConfig().Global, key) - bFlags := getOptions(b.Options, key) - lFlags := getOptions(l.Options, key) + gFlags := getOptions(GetConfig().Global, []string{key}) + bFlags := getOptions(b.Options, []string{"all", key}) + lFlags := getOptions(l.Options, []string{"all", key}) options = append(options, gFlags...) options = append(options, bFlags...) options = append(options, lFlags...) diff --git a/internal/flags/flags.go b/internal/flags/flags.go index ac7fc3a..8d32124 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -1,5 +1,8 @@ package flags -var CI bool = false -var VERBOSE bool = false -var CRON_LEAN bool = false +var ( + CI bool = false + VERBOSE bool = false + CRON_LEAN bool = false + RESTIC_BIN string +) diff --git a/internal/location.go b/internal/location.go index b715105..0bfb853 100644 --- a/internal/location.go +++ b/internal/location.go @@ -146,9 +146,6 @@ func (l Location) ExecuteHooks(commands []string, options ExecuteOptions) error colors.Error.Println(out) return err } - if flags.VERBOSE { - colors.Faint.Println(out) - } } colors.Body.Println("") return nil @@ -284,24 +281,16 @@ func (l Location) Backup(cron bool, specificBackend string) []error { for k, v := range env2 { env[k+"2"] = v } - _, out, err := ExecuteResticCommand(ExecuteOptions{ + _, _, err := ExecuteResticCommand(ExecuteOptions{ Envs: env, }, "copy", md.SnapshotID) - if flags.VERBOSE { - colors.Faint.Println(out) - } - if err != nil { errors = append(errors, err) } } } } - - if flags.VERBOSE { - colors.Faint.Println(out) - } } // After hooks @@ -353,10 +342,7 @@ func (l Location) Forget(prune bool, dry bool) error { cmd = append(cmd, "--dry-run") } cmd = append(cmd, combineOptions("forget", l, backend)...) - _, out, err := ExecuteResticCommand(options, cmd...) - if flags.VERBOSE { - colors.Faint.Println(out) - } + _, _, err = ExecuteResticCommand(options, cmd...) if err != nil { return err } diff --git a/internal/utils.go b/internal/utils.go index 42389f1..c8bf799 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -9,23 +9,34 @@ import ( "github.com/cupcakearmy/autorestic/internal/colors" "github.com/cupcakearmy/autorestic/internal/flags" + "github.com/fatih/color" ) -var RESTIC_BIN string - func CheckIfCommandIsCallable(cmd string) bool { _, err := exec.LookPath(cmd) return err == nil } func CheckIfResticIsCallable() bool { - return CheckIfCommandIsCallable(RESTIC_BIN) + return CheckIfCommandIsCallable(flags.RESTIC_BIN) } type ExecuteOptions struct { Command string Envs map[string]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) { @@ -43,23 +54,32 @@ func ExecuteCommand(options ExecuteOptions, args ...string) (int, string, error) var out 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 err := cmd.Run() if err != nil { + code := -1 if exitError, ok := err.(*exec.ExitError); ok { - return exitError.ExitCode(), error.String(), err - } else { - return -1, error.String(), err + code = exitError.ExitCode() } + return code, error.String(), err } return 0, out.String(), nil } func ExecuteResticCommand(options ExecuteOptions, args ...string) (int, string, error) { - options.Command = RESTIC_BIN + options.Command = flags.RESTIC_BIN var c = GetConfig() - var optionsAsString = getOptions(c.Global, "") + var optionsAsString = getOptions(c.Global, []string{"all"}) args = append(optionsAsString, args...) return ExecuteCommand(options, args...) }