This commit is contained in:
rdelaage 2023-08-03 12:21:06 +02:00 committed by GitHub
commit 9697e080e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 98 additions and 73 deletions

View File

@ -5,10 +5,10 @@ import (
"path/filepath"
"strings"
"github.com/cupcakearmy/autorestic/internal"
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/flags"
"github.com/cupcakearmy/autorestic/internal/lock"
"github.com/cupcakearmy/autorestic/internal/version"
"github.com/spf13/cobra"
homedir "github.com/mitchellh/go-homedir"
@ -26,7 +26,7 @@ func CheckErr(err error) {
var cfgFile string
var rootCmd = &cobra.Command{
Version: internal.VERSION,
Version: version.VERSION,
Use: "autorestic",
Short: "CLI Wrapper for restic",
Long: "Documentation:\thttps://autorestic.vercel.app\nSupport:\thttps://discord.gg/wS7RpYTYd2",
@ -41,7 +41,7 @@ func init() {
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(&flags.RESTIC_BIN, "restic-bin", "restic", "specify custom restic binary")
rootCmd.PersistentFlags().StringVar(&flags.DOCKER_IMAGE, "docker-image", "cupcakearmy/autorestic:"+internal.VERSION, "specify a custom docker image")
rootCmd.PersistentFlags().StringVar(&flags.DOCKER_IMAGE, "docker-image", "cupcakearmy/autorestic:"+version.VERSION, "specify a custom docker image")
cobra.OnInitialize(initConfig)
}

View File

@ -10,6 +10,8 @@ import (
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/flags"
"github.com/cupcakearmy/autorestic/internal/options"
"github.com/cupcakearmy/autorestic/internal/utils"
)
type BackendRest struct {
@ -24,7 +26,7 @@ type Backend struct {
Key string `mapstructure:"key,omitempty"`
Env map[string]string `mapstructure:"env,omitempty"`
Rest BackendRest `mapstructure:"rest,omitempty"`
Options Options `mapstructure:"options,omitempty"`
Options options.Options `mapstructure:"options,omitempty"`
}
func GetBackend(name string) (Backend, bool) {
@ -120,11 +122,15 @@ func (b Backend) validate() error {
if err != nil {
return err
}
options := ExecuteOptions{Envs: env, Silent: true}
options := utils.ExecuteOptions{
Envs: env,
Silent: true,
Global: GetConfig().Global,
}
// Check if already initialized
cmd := []string{"check"}
cmd = append(cmd, combineBackendOptions("check", b)...)
_, _, err = ExecuteResticCommand(options, cmd...)
_, _, err = utils.ExecuteResticCommand(options, cmd...)
if err == nil {
return nil
} else {
@ -132,7 +138,7 @@ func (b Backend) validate() error {
colors.Body.Printf("Initializing backend \"%s\"...\n", b.name)
cmd := []string{"init"}
cmd = append(cmd, combineBackendOptions("init", b)...)
_, _, err := ExecuteResticCommand(options, cmd...)
_, _, err := utils.ExecuteResticCommand(options, cmd...)
return err
}
}
@ -142,8 +148,11 @@ func (b Backend) Exec(args []string) error {
if err != nil {
return err
}
options := ExecuteOptions{Envs: env}
_, out, err := ExecuteResticCommand(options, args...)
options := utils.ExecuteOptions{
Envs: env,
Global: GetConfig().Global,
}
_, out, err := utils.ExecuteResticCommand(options, args...)
if err != nil {
colors.Error.Println(out)
return err
@ -157,7 +166,7 @@ func (b Backend) ExecDocker(l Location, args []string) (int, string, error) {
return -1, "", err
}
volume := l.From[0]
options := ExecuteOptions{
options := utils.ExecuteOptions{
Command: "docker",
Envs: env,
}
@ -185,7 +194,7 @@ func (b Backend) ExecDocker(l Location, args []string) (int, string, error) {
// No additional setup needed
case "rclone":
// Read host rclone config and mount it into the container
code, configFile, err := ExecuteCommand(ExecuteOptions{Command: "rclone"}, "config", "file")
code, configFile, err := utils.ExecuteCommand(utils.ExecuteOptions{Command: "rclone"}, "config", "file")
if err != nil {
return code, "", err
}
@ -200,5 +209,5 @@ func (b Backend) ExecDocker(l Location, args []string) (int, string, error) {
}
docker = append(docker, flags.DOCKER_IMAGE, "-c", strings.Join(args, " "))
return ExecuteCommand(options, docker...)
return utils.ExecuteCommand(options, docker...)
}

View File

@ -14,9 +14,10 @@ import (
"strings"
"github.com/blang/semver/v4"
"github.com/cupcakearmy/autorestic/internal"
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/flags"
"github.com/cupcakearmy/autorestic/internal/utils"
"github.com/cupcakearmy/autorestic/internal/version"
)
const INSTALL_PATH = "/usr/local/bin"
@ -115,7 +116,7 @@ func downloadAndInstallAsset(body GithubRelease, name string) error {
}
func InstallRestic() error {
installed := internal.CheckIfCommandIsCallable("restic")
installed := utils.CheckIfCommandIsCallable("restic")
if installed {
colors.Body.Println("restic already installed")
return nil
@ -129,7 +130,7 @@ func InstallRestic() error {
}
func upgradeRestic() error {
_, _, err := internal.ExecuteCommand(internal.ExecuteOptions{
_, _, err := utils.ExecuteCommand(utils.ExecuteOptions{
Command: flags.RESTIC_BIN,
}, "self-update")
return err
@ -147,7 +148,7 @@ func Upgrade(restic bool) error {
}
// Upgrade self
current, err := semver.ParseTolerant(internal.VERSION)
current, err := semver.ParseTolerant(version.VERSION)
if err != nil {
return err
}

View File

@ -11,23 +11,20 @@ import (
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/flags"
"github.com/cupcakearmy/autorestic/internal/lock"
"github.com/cupcakearmy/autorestic/internal/options"
"github.com/cupcakearmy/autorestic/internal/utils"
"github.com/joho/godotenv"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const VERSION = "1.7.7"
type OptionMap map[string][]interface{}
type Options map[string]OptionMap
type Config struct {
Version string `mapstructure:"version"`
Extras interface{} `mapstructure:"extras"`
Locations map[string]Location `mapstructure:"locations"`
Backends map[string]Backend `mapstructure:"backends"`
Global Options `mapstructure:"global"`
Global options.Options `mapstructure:"global"`
}
var once sync.Once
@ -184,7 +181,7 @@ func CheckConfig() error {
if c == nil {
return fmt.Errorf("config could not be loaded/found")
}
if !CheckIfResticIsCallable() {
if !utils.CheckIfResticIsCallable() {
return fmt.Errorf(`%s was not found. Install either with "autorestic install" or manually`, flags.RESTIC_BIN)
}
for name, backend := range c.Backends {
@ -263,7 +260,7 @@ func AddFlagsToCommand(cmd *cobra.Command, backend bool) {
func (c *Config) SaveConfig() error {
file := viper.ConfigFileUsed()
if err := CopyFile(file, file+".old"); err != nil {
if err := utils.CopyFile(file, file+".old"); err != nil {
return err
}
colors.Secondary.Println("Saved a backup copy of your file next to the original.")
@ -274,40 +271,11 @@ func (c *Config) SaveConfig() error {
return viper.WriteConfig()
}
func optionToString(option string) string {
if !strings.HasPrefix(option, "-") {
return "--" + option
}
return option
}
func appendOptionsToSlice(str *[]string, options OptionMap) {
for key, values := range options {
for _, value := range values {
// Bool
asBool, ok := value.(bool)
if ok && asBool {
*str = append(*str, optionToString(key))
continue
}
*str = append(*str, optionToString(key), fmt.Sprint(value))
}
}
}
func getOptions(options Options, keys []string) []string {
var selected []string
for _, key := range keys {
appendOptionsToSlice(&selected, options[key])
}
return selected
}
func combineBackendOptions(key string, b Backend) []string {
// Priority: backend > global
var options []string
gFlags := getOptions(GetConfig().Global, []string{key})
bFlags := getOptions(b.Options, []string{"all", key})
gFlags := GetConfig().Global.GetOptions([]string{key})
bFlags := b.Options.GetOptions([]string{"all", key})
options = append(options, gFlags...)
options = append(options, bFlags...)
return options
@ -316,9 +284,9 @@ func combineBackendOptions(key string, b Backend) []string {
func combineAllOptions(key string, l Location, b Backend) []string {
// Priority: location > backend > global
var options []string
gFlags := getOptions(GetConfig().Global, []string{key})
bFlags := getOptions(b.Options, []string{"all", key})
lFlags := getOptions(l.Options, []string{"all", key})
gFlags := GetConfig().Global.GetOptions([]string{key})
bFlags := b.Options.GetOptions([]string{"all", key})
lFlags := l.Options.GetOptions([]string{"all", key})
options = append(options, gFlags...)
options = append(options, bFlags...)
options = append(options, lFlags...)

View File

@ -12,6 +12,8 @@ import (
"github.com/cupcakearmy/autorestic/internal/flags"
"github.com/cupcakearmy/autorestic/internal/lock"
"github.com/cupcakearmy/autorestic/internal/metadata"
"github.com/cupcakearmy/autorestic/internal/utils"
"github.com/cupcakearmy/autorestic/internal/options"
"github.com/robfig/cron"
)
@ -49,7 +51,7 @@ type Location struct {
To []string `mapstructure:"to,omitempty"`
Hooks Hooks `mapstructure:"hooks,omitempty"`
Cron string `mapstructure:"cron,omitempty"`
Options Options `mapstructure:"options,omitempty"`
Options options.Options `mapstructure:"options,omitempty"`
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"`
CopyOption LocationCopy `mapstructure:"copy,omitempty"`
}
@ -101,14 +103,14 @@ func (l Location) validate() error {
if _, ok := GetBackend(copyFrom); !ok {
return fmt.Errorf(`location "%s" has an invalid backend "%s" in copy option`, l.name, copyFrom)
}
if !ArrayContains(l.To, copyFrom) {
if !utils.ArrayContains(l.To, copyFrom) {
return fmt.Errorf(`location "%s" has an invalid copy from "%s"`, l.name, copyFrom)
}
for _, copyToTarget := range copyTo {
if _, ok := GetBackend(copyToTarget); !ok {
return fmt.Errorf(`location "%s" has an invalid backend "%s" in copy option`, l.name, copyToTarget)
}
if ArrayContains(l.To, copyToTarget) {
if utils.ArrayContains(l.To, copyToTarget) {
return fmt.Errorf(`location "%s" cannot copy to "%s" as it's already a target`, l.name, copyToTarget)
}
}
@ -123,7 +125,7 @@ func (l Location) validate() error {
return nil
}
func (l Location) ExecuteHooks(commands []string, options ExecuteOptions) error {
func (l Location) ExecuteHooks(commands []string, options utils.ExecuteOptions) error {
if len(commands) == 0 {
return nil
}
@ -137,7 +139,7 @@ func (l Location) ExecuteHooks(commands []string, options ExecuteOptions) error
colors.Secondary.Println("\nRunning hooks")
for _, command := range commands {
colors.Body.Println("> " + command)
_, out, err := ExecuteCommand(options, "-c", command)
_, out, err := utils.ExecuteCommand(options, "-c", command)
if err != nil {
colors.Error.Println(out)
return err
@ -176,7 +178,7 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
return errors
}
cwd, _ := GetPathRelativeToConfig(".")
options := ExecuteOptions{
options := utils.ExecuteOptions{
Command: "bash",
Dir: cwd,
Envs: map[string]string{
@ -221,8 +223,9 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
cmd = append(cmd, "--tag", buildTag("cron"))
}
cmd = append(cmd, "--tag", l.getLocationTags())
backupOptions := ExecuteOptions{
backupOptions := utils.ExecuteOptions{
Envs: env,
Global: GetConfig().Global,
}
var code int = 0
@ -237,9 +240,9 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
}
cmd = append(cmd, path)
}
code, out, err = ExecuteResticCommand(backupOptions, cmd...)
code, out, err = utils.ExecuteResticCommand(backupOptions, cmd...)
case TypeVolume:
ok := CheckIfVolumeExists(l.From[0])
ok := utils.CheckIfVolumeExists(l.From[0])
if !ok {
errors = append(errors, fmt.Errorf("volume \"%s\" does not exist", l.From[0]))
continue
@ -277,8 +280,9 @@ func (l Location) Backup(cron bool, specificBackend string) []error {
for k, v := range env2 {
env[k+"2"] = v
}
_, _, err := ExecuteResticCommand(ExecuteOptions{
_, _, err := utils.ExecuteResticCommand(utils.ExecuteOptions{
Envs: env,
Global: GetConfig().Global,
}, "copy", md.SnapshotID)
if err != nil {
@ -335,8 +339,9 @@ func (l Location) Forget(prune bool, dry bool) error {
if err != nil {
return nil
}
options := ExecuteOptions{
options := utils.ExecuteOptions{
Envs: env,
Global: GetConfig().Global,
}
cmd := []string{"forget", "--tag", l.getLocationTags()}
if prune {
@ -346,7 +351,7 @@ func (l Location) Forget(prune bool, dry bool) error {
cmd = append(cmd, "--dry-run")
}
cmd = append(cmd, combineAllOptions("forget", l, backend)...)
_, _, err = ExecuteResticCommand(options, cmd...)
_, _, err = utils.ExecuteResticCommand(options, cmd...)
if err != nil {
return err
}

View File

@ -0,0 +1,38 @@
package options
import (
"fmt"
"strings"
)
type OptionMap map[string][]interface{}
type Options map[string]OptionMap
func (o Options) GetOptions(keys []string) []string {
var selected []string
for _, key := range keys {
o[key].AppendOptionsToSlice(&selected)
}
return selected
}
func (m OptionMap) AppendOptionsToSlice(str *[]string) {
for key, values := range m {
for _, value := range values {
// Bool
asBool, ok := value.(bool)
if ok && asBool {
*str = append(*str, optionToString(key))
continue
}
*str = append(*str, optionToString(key), fmt.Sprint(value))
}
}
}
func optionToString(option string) string {
if !strings.HasPrefix(option, "-") {
return "--" + option
}
return option
}

View File

@ -1,4 +1,4 @@
package internal
package utils
import (
"bytes"
@ -9,6 +9,7 @@ import (
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/flags"
"github.com/cupcakearmy/autorestic/internal/options"
"github.com/fatih/color"
)
@ -26,6 +27,7 @@ type ExecuteOptions struct {
Envs map[string]string
Dir string
Silent bool
Global options.Options
}
type ColoredWriter struct {
@ -78,8 +80,7 @@ func ExecuteCommand(options ExecuteOptions, args ...string) (int, string, error)
func ExecuteResticCommand(options ExecuteOptions, args ...string) (int, string, error) {
options.Command = flags.RESTIC_BIN
var c = GetConfig()
var optionsAsString = getOptions(c.Global, []string{"all"})
var optionsAsString = options.Global.GetOptions([]string{"all"})
args = append(optionsAsString, args...)
return ExecuteCommand(options, args...)
}

View File

@ -0,0 +1,3 @@
package version
const VERSION = "1.7.7"