make back compatible

This commit is contained in:
cupcakearmy 2021-04-16 22:02:25 +02:00
parent aa0b81023f
commit 1bbd3879fe
No known key found for this signature in database
GPG Key ID: D28129AE5654D9D9
8 changed files with 83 additions and 114 deletions

View File

@ -30,9 +30,7 @@ var backupCmd = &cobra.Command{
CheckErr(err) CheckErr(err)
defer lock.Unlock() defer lock.Unlock()
config := internal.GetConfig() CheckErr(internal.CheckConfig())
err = config.CheckConfig()
CheckErr(err)
selected, err := internal.GetAllOrSelected(cmd, false) selected, err := internal.GetAllOrSelected(cmd, false)
CheckErr(err) CheckErr(err)

View File

@ -31,9 +31,8 @@ var checkCmd = &cobra.Command{
CheckErr(err) CheckErr(err)
defer lock.Unlock() defer lock.Unlock()
config := internal.GetConfig() CheckErr(internal.CheckConfig())
err = config.CheckConfig()
CheckErr(err)
colors.Success.Println("Everyting is fine.") colors.Success.Println("Everyting is fine.")
}, },
} }

View File

@ -31,9 +31,7 @@ var execCmd = &cobra.Command{
CheckErr(err) CheckErr(err)
defer lock.Unlock() defer lock.Unlock()
config := internal.GetConfig() CheckErr(internal.CheckConfig())
err = config.CheckConfig()
CheckErr(err)
selected, err := internal.GetAllOrSelected(cmd, true) selected, err := internal.GetAllOrSelected(cmd, true)
CheckErr(err) CheckErr(err)

View File

@ -30,8 +30,7 @@ var forgetCmd = &cobra.Command{
CheckErr(err) CheckErr(err)
defer lock.Unlock() defer lock.Unlock()
config := internal.GetConfig() CheckErr(internal.CheckConfig())
CheckErr(config.CheckConfig())
selected, err := internal.GetAllOrSelected(cmd, false) selected, err := internal.GetAllOrSelected(cmd, false)
CheckErr(err) CheckErr(err)

View File

@ -12,21 +12,17 @@ import (
) )
type Backend struct { type Backend struct {
Name string `mapstructure:"name"` name string
Type string `mapstructure:"type"` Type string `mapstructure:"type,omitempty"`
Path string `mapstructure:"path"` Path string `mapstructure:"path,omitempty"`
Key string `mapstructure:"key"` Key string `mapstructure:"key,omitempty"`
Env map[string]string `mapstructure:"env"` Env map[string]string `mapstructure:"env,omitempty"`
} }
func GetBackend(name string) (Backend, bool) { func GetBackend(name string) (Backend, bool) {
c := GetConfig() b, ok := GetConfig().Backends[name]
for _, b := range c.Backends { b.name = name
if b.Name == name { return b, ok
return b, true
}
}
return Backend{}, false
} }
func (b Backend) generateRepo() (string, error) { func (b Backend) generateRepo() (string, error) {
@ -59,25 +55,20 @@ func generateRandomKey() string {
} }
func (b Backend) validate() error { func (b Backend) validate() error {
if b.Name == "" {
return fmt.Errorf(`Backend has no "name"`)
}
if b.Type == "" { if b.Type == "" {
return fmt.Errorf(`Backend "%s" has no "type"`, b.Name) return fmt.Errorf(`Backend "%s" has no "type"`, b.name)
} }
if b.Path == "" { if b.Path == "" {
return fmt.Errorf(`Backend "%s" has no "path"`, b.Name) return fmt.Errorf(`Backend "%s" has no "path"`, b.name)
} }
if b.Key == "" { if b.Key == "" {
key := generateRandomKey() key := generateRandomKey()
b.Key = key b.Key = key
c := GetConfig() c := GetConfig()
for i, backend := range c.Backends { tmp := c.Backends[b.name]
if backend.Name == b.Name { tmp.Key = key
c.Backends[i].Key = key tmp.name = ""
break c.Backends[b.name] = tmp
}
}
file := viper.ConfigFileUsed() file := viper.ConfigFileUsed()
if err := CopyFile(file, file+".old"); err != nil { if err := CopyFile(file, file+".old"); err != nil {
return err return err

View File

@ -18,8 +18,8 @@ var CI bool = false
var VERBOSE bool = false var VERBOSE bool = false
type Config struct { type Config struct {
Locations []Location `mapstructure:"locations"` Locations map[string]Location `mapstructure:"locations"`
Backends []Backend `mapstructure:"backends"` Backends map[string]Backend `mapstructure:"backends"`
} }
var once sync.Once var once sync.Once
@ -31,7 +31,6 @@ func GetConfig() *Config {
if err := viper.ReadInConfig(); err == nil { if err := viper.ReadInConfig(); err == nil {
colors.Faint.Println("Using config file:", viper.ConfigFileUsed()) colors.Faint.Println("Using config file:", viper.ConfigFileUsed())
} else { } else {
return return
} }
@ -55,34 +54,25 @@ func GetPathRelativeToConfig(p string) (string, error) {
} }
} }
func (c *Config) CheckConfig() error { func CheckConfig() error {
c := GetConfig()
if c == nil { if c == nil {
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(`restic was not found. Install either with "autorestic install" or manually`) return fmt.Errorf(`restic was not found. Install either with "autorestic install" or manually`)
} }
found := map[string]bool{} for name, backend := range c.Backends {
for _, backend := range c.Backends { backend.name = name
if err := backend.validate(); err != nil { if err := backend.validate(); err != nil {
return err return err
} }
if _, ok := found[backend.Name]; ok {
return fmt.Errorf(`duplicate name for backends "%s"`, backend.Name)
} else {
found[backend.Name] = true
}
} }
found = map[string]bool{} for name, location := range c.Locations {
for _, location := range c.Locations { location.name = name
if err := location.validate(c); err != nil { if err := location.validate(c); err != nil {
return err return err
} }
if _, ok := found[location.Name]; ok {
return fmt.Errorf(`duplicate name for locations "%s"`, location.Name)
} else {
found[location.Name] = true
}
} }
return nil return nil
} }
@ -90,47 +80,47 @@ func (c *Config) CheckConfig() error {
func GetAllOrSelected(cmd *cobra.Command, backends bool) ([]string, error) { func GetAllOrSelected(cmd *cobra.Command, backends bool) ([]string, error) {
var list []string var list []string
if backends { if backends {
for _, b := range config.Backends { for name := range config.Backends {
list = append(list, b.Name) list = append(list, name)
} }
} else { } else {
for _, l := range config.Locations { for name := range config.Locations {
list = append(list, l.Name) list = append(list, name)
} }
} }
all, _ := cmd.Flags().GetBool("all") all, _ := cmd.Flags().GetBool("all")
if all { if all {
return list, nil return list, nil
} else {
var selected []string
if backends {
tmp, _ := cmd.Flags().GetStringSlice("backend")
selected = tmp
} else {
tmp, _ := cmd.Flags().GetStringSlice("location")
selected = tmp
}
for _, s := range selected {
found := false
for _, l := range list {
if l == s {
found = true
break
}
}
if !found {
if backends {
return nil, fmt.Errorf("invalid backend \"%s\"", s)
} else {
return nil, fmt.Errorf("invalid location \"%s\"", s)
}
}
}
if len(selected) == 0 {
return selected, fmt.Errorf("nothing selected, aborting")
}
return selected, nil
} }
var selected []string
if backends {
selected, _ = cmd.Flags().GetStringSlice("backend")
} else {
selected, _ = cmd.Flags().GetStringSlice("location")
}
for _, s := range selected {
found := false
for _, l := range list {
if l == s {
found = true
break
}
}
if !found {
if backends {
return nil, fmt.Errorf("invalid backend \"%s\"", s)
} else {
return nil, fmt.Errorf("invalid location \"%s\"", s)
}
}
}
if len(selected) == 0 {
return selected, fmt.Errorf("nothing selected, aborting")
}
return selected, nil
} }
func AddFlagsToCommand(cmd *cobra.Command, backend bool) { func AddFlagsToCommand(cmd *cobra.Command, backend bool) {

View File

@ -2,7 +2,8 @@ package internal
func RunCron() error { func RunCron() error {
c := GetConfig() c := GetConfig()
for _, l := range c.Locations { for name, l := range c.Locations {
l.name = name
if err := l.RunCron(); err != nil { if err := l.RunCron(); err != nil {
return err return err
} }

View File

@ -31,33 +31,26 @@ type Hooks struct {
type Options map[string]map[string][]string type Options map[string]map[string][]string
type Location struct { type Location struct {
Name string `mapstructure:"name"` name string `mapstructure:",omitempty"`
From string `mapstructure:"from"` From string `mapstructure:"from,omitempty"`
To []string `mapstructure:"to"` To []string `mapstructure:"to,omitempty"`
Hooks Hooks `mapstructure:"hooks"` Hooks Hooks `mapstructure:"hooks,omitempty"`
Cron string `mapstructure:"cron"` Cron string `mapstructure:"cron,omitempty"`
Options Options `mapstructure:"options"` Options Options `mapstructure:"options,omitempty"`
} }
func GetLocation(name string) (Location, bool) { func GetLocation(name string) (Location, bool) {
c := GetConfig() l, ok := GetConfig().Locations[name]
for _, b := range c.Locations { l.name = name
if b.Name == name { return l, ok
return b, true
}
}
return Location{}, false
} }
func (l Location) validate(c *Config) error { func (l Location) validate(c *Config) error {
if l.Name == "" {
return fmt.Errorf(`Location is missing name`)
}
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 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)
} }
// Check if backends are all valid // Check if backends are all valid
for _, to := range l.To { for _, to := range l.To {
@ -120,13 +113,13 @@ func (l Location) getPath() (string, error) {
return path, nil return path, nil
} }
case TypeVolume: case TypeVolume:
return "/volume/" + l.Name + "/" + l.getVolumeName(), nil return "/volume/" + l.name + "/" + l.getVolumeName(), nil
} }
return "", fmt.Errorf("could not get path for location \"%s\"", l.Name) return "", fmt.Errorf("could not get path for location \"%s\"", l.name)
} }
func (l Location) Backup() error { func (l Location) Backup() error {
colors.PrimaryPrint(" Backing up location \"%s\" ", l.Name) colors.PrimaryPrint(" Backing up location \"%s\" ", l.name)
t := l.getType() t := l.getType()
options := ExecuteOptions{ options := ExecuteOptions{
Command: "bash", Command: "bash",
@ -145,7 +138,7 @@ func (l Location) Backup() error {
// Backup // Backup
for _, to := range l.To { for _, to := range l.To {
backend, _ := GetBackend(to) backend, _ := GetBackend(to)
colors.Secondary.Printf("Backend: %s\n", backend.Name) colors.Secondary.Printf("Backend: %s\n", backend.name)
env, err := backend.getEnv() env, err := backend.getEnv()
if err != nil { if err != nil {
return nil return nil
@ -186,7 +179,7 @@ func (l Location) Backup() error {
} }
func (l Location) Forget(prune bool, dry bool) error { func (l Location) Forget(prune bool, dry bool) error {
colors.PrimaryPrint("Forgetting for location \"%s\"", l.Name) colors.PrimaryPrint("Forgetting for location \"%s\"", l.name)
path, err := l.getPath() path, err := l.getPath()
if err != nil { if err != nil {
@ -195,7 +188,7 @@ func (l Location) Forget(prune bool, dry bool) error {
for _, to := range l.To { for _, to := range l.To {
backend, _ := GetBackend(to) backend, _ := GetBackend(to)
colors.Secondary.Printf("For backend \"%s\"\n", backend.Name) colors.Secondary.Printf("For backend \"%s\"\n", backend.name)
env, err := backend.getEnv() env, err := backend.getEnv()
if err != nil { if err != nil {
return nil return nil
@ -244,7 +237,7 @@ func (l Location) Restore(to, from string, force bool) error {
if err != nil { if err != nil {
return err return err
} }
colors.PrimaryPrint("Restoring location \"%s\"", l.Name) colors.PrimaryPrint("Restoring location \"%s\"", l.name)
backend, _ := GetBackend(from) backend, _ := GetBackend(from)
path, err := l.getPath() path, err := l.getPath()
@ -293,14 +286,14 @@ func (l Location) RunCron() error {
if err != nil { if err != nil {
return err return err
} }
last := time.Unix(lock.GetCron(l.Name), 0) last := time.Unix(lock.GetCron(l.name), 0)
next := schedule.Next(last) next := schedule.Next(last)
now := time.Now() now := time.Now()
if now.After(next) { if now.After(next) {
lock.SetCron(l.Name, now.Unix()) lock.SetCron(l.name, now.Unix())
l.Backup() l.Backup()
} else { } else {
colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.Name) colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.name)
} }
return nil return nil
} }