Clean up a bit the Restic methods
This commit is contained in:
parent
57afeab4ca
commit
1b89470be5
6
job.go
6
job.go
@ -25,7 +25,7 @@ type TaskConfig struct {
|
|||||||
JobDir string
|
JobDir string
|
||||||
Env map[string]string
|
Env map[string]string
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
Restic *ResticCmd
|
Restic *Restic
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResticConfig is all configuration to be sent to Restic.
|
// ResticConfig is all configuration to be sent to Restic.
|
||||||
@ -500,8 +500,8 @@ func (j Job) RunRestore() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j Job) NewRestic() *ResticCmd {
|
func (j Job) NewRestic() *Restic {
|
||||||
return &ResticCmd{
|
return &Restic{
|
||||||
Logger: GetLogger(j.Name),
|
Logger: GetLogger(j.Name),
|
||||||
Repo: j.Config.Repo,
|
Repo: j.Config.Repo,
|
||||||
Env: j.Config.Env,
|
Env: j.Config.Env,
|
||||||
|
330
restic.go
330
restic.go
@ -9,6 +9,38 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func maybeAddArgString(args []string, name, value string) []string {
|
||||||
|
if value != "" {
|
||||||
|
return append(args, name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func maybeAddArgInt(args []string, name string, value int) []string {
|
||||||
|
if value > 0 {
|
||||||
|
return append(args, name, fmt.Sprint(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func maybeAddArgBool(args []string, name string, value bool) []string {
|
||||||
|
if value {
|
||||||
|
return append(args, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func maybeAddArgsList(args []string, name string, value []string) []string {
|
||||||
|
for _, v := range value {
|
||||||
|
args = append(args, name, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
type CommandOptions interface {
|
type CommandOptions interface {
|
||||||
ToArgs() []string
|
ToArgs() []string
|
||||||
}
|
}
|
||||||
@ -19,115 +51,6 @@ func (NoOpts) ToArgs() []string {
|
|||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResticGlobalOpts struct {
|
|
||||||
CaCertFile string `hcl:"CaCertFile,optional"`
|
|
||||||
CacheDir string `hcl:"CacheDir,optional"`
|
|
||||||
PasswordFile string `hcl:"PasswordFile,optional"`
|
|
||||||
TLSClientCertFile string `hcl:"TlsClientCertFile,optional"`
|
|
||||||
LimitDownload int `hcl:"LimitDownload,optional"`
|
|
||||||
LimitUpload int `hcl:"LimitUpload,optional"`
|
|
||||||
VerboseLevel int `hcl:"VerboseLevel,optional"`
|
|
||||||
CleanupCache bool `hcl:"CleanupCache,optional"`
|
|
||||||
NoCache bool `hcl:"NoCache,optional"`
|
|
||||||
NoLock bool `hcl:"NoLock,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// nolint:cyclop
|
|
||||||
func (glo ResticGlobalOpts) ToArgs() (args []string) {
|
|
||||||
if glo.CaCertFile != "" {
|
|
||||||
args = append(args, "--cacert", glo.CaCertFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.CacheDir != "" {
|
|
||||||
args = append(args, "--cache-dir", glo.CacheDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.PasswordFile != "" {
|
|
||||||
args = append(args, "--password-file", glo.PasswordFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.TLSClientCertFile != "" {
|
|
||||||
args = append(args, "--tls-client-cert", glo.TLSClientCertFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.LimitDownload > 0 {
|
|
||||||
args = append(args, "--limit-download", fmt.Sprint(glo.LimitDownload))
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.LimitUpload > 0 {
|
|
||||||
args = append(args, "--limit-upload", fmt.Sprint(glo.LimitUpload))
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.VerboseLevel > 0 {
|
|
||||||
args = append(args, "--verbose", fmt.Sprint(glo.VerboseLevel))
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.CleanupCache {
|
|
||||||
args = append(args, "--cleanup-cache")
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.NoCache {
|
|
||||||
args = append(args, "--no-cache")
|
|
||||||
}
|
|
||||||
|
|
||||||
if glo.NoLock {
|
|
||||||
args = append(args, "--no-lock")
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResticCmd struct {
|
|
||||||
Logger *log.Logger
|
|
||||||
Repo string
|
|
||||||
Env map[string]string
|
|
||||||
Passphrase string
|
|
||||||
GlobalOpts *ResticGlobalOpts
|
|
||||||
Cwd string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rcmd ResticCmd) BuildEnv() []string {
|
|
||||||
if rcmd.Env == nil {
|
|
||||||
rcmd.Env = map[string]string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcmd.Passphrase != "" {
|
|
||||||
rcmd.Env["RESTIC_PASSWORD"] = rcmd.Passphrase
|
|
||||||
}
|
|
||||||
|
|
||||||
envList := os.Environ()
|
|
||||||
|
|
||||||
for name, value := range rcmd.Env {
|
|
||||||
envList = append(envList, fmt.Sprintf("%s=%s", name, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
return envList
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rcmd ResticCmd) RunRestic(command string, options CommandOptions, commandArgs ...string) error {
|
|
||||||
args := []string{}
|
|
||||||
if rcmd.GlobalOpts != nil {
|
|
||||||
args = rcmd.GlobalOpts.ToArgs()
|
|
||||||
}
|
|
||||||
|
|
||||||
args = append(args, "--repo", rcmd.Repo, command)
|
|
||||||
args = append(args, options.ToArgs()...)
|
|
||||||
args = append(args, commandArgs...)
|
|
||||||
|
|
||||||
cmd := exec.Command("restic", args...)
|
|
||||||
|
|
||||||
cmd.Stdout = NewLogWriter(rcmd.Logger)
|
|
||||||
cmd.Stderr = cmd.Stdout
|
|
||||||
cmd.Env = rcmd.BuildEnv()
|
|
||||||
cmd.Dir = rcmd.Cwd
|
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return fmt.Errorf("error running restic %s: %w", command, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type BackupOpts struct {
|
type BackupOpts struct {
|
||||||
Exclude []string `hcl:"Exclude,optional"`
|
Exclude []string `hcl:"Exclude,optional"`
|
||||||
Include []string `hcl:"Include,optional"`
|
Include []string `hcl:"Include,optional"`
|
||||||
@ -136,29 +59,14 @@ type BackupOpts struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bo BackupOpts) ToArgs() (args []string) {
|
func (bo BackupOpts) ToArgs() (args []string) {
|
||||||
for _, exclude := range bo.Exclude {
|
args = maybeAddArgsList(args, "--exclude", bo.Exclude)
|
||||||
args = append(args, "--exclude", exclude)
|
args = maybeAddArgsList(args, "--include", bo.Include)
|
||||||
}
|
args = maybeAddArgsList(args, "--tag", bo.Tags)
|
||||||
|
args = maybeAddArgString(args, "--host", bo.Host)
|
||||||
for _, include := range bo.Include {
|
|
||||||
args = append(args, "--include", include)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range bo.Tags {
|
|
||||||
args = append(args, "--tag", tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
if bo.Host != "" {
|
|
||||||
args = append(args, "--host", bo.Host)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rcmd ResticCmd) Backup(files []string, opts BackupOpts) error {
|
|
||||||
return rcmd.RunRestic("backup", opts, files...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type RestoreOpts struct {
|
type RestoreOpts struct {
|
||||||
Exclude []string `hcl:"Exclude,optional"`
|
Exclude []string `hcl:"Exclude,optional"`
|
||||||
Include []string `hcl:"Include,optional"`
|
Include []string `hcl:"Include,optional"`
|
||||||
@ -170,41 +78,17 @@ type RestoreOpts struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ro RestoreOpts) ToArgs() (args []string) {
|
func (ro RestoreOpts) ToArgs() (args []string) {
|
||||||
for _, exclude := range ro.Exclude {
|
args = maybeAddArgsList(args, "--exclude", ro.Exclude)
|
||||||
args = append(args, "--exclude", exclude)
|
args = maybeAddArgsList(args, "--include", ro.Include)
|
||||||
}
|
args = maybeAddArgsList(args, "--host", ro.Host)
|
||||||
|
args = maybeAddArgsList(args, "--tag", ro.Tags)
|
||||||
for _, include := range ro.Include {
|
args = maybeAddArgString(args, "--path", ro.Path)
|
||||||
args = append(args, "--include", include)
|
args = maybeAddArgString(args, "--target", ro.Target)
|
||||||
}
|
args = maybeAddArgBool(args, "--verify", ro.Verify)
|
||||||
|
|
||||||
for _, host := range ro.Host {
|
|
||||||
args = append(args, "--host", host)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range ro.Tags {
|
|
||||||
args = append(args, "--tag", tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ro.Path != "" {
|
|
||||||
args = append(args, "--path", ro.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ro.Target != "" {
|
|
||||||
args = append(args, "--target", ro.Target)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ro.Verify {
|
|
||||||
args = append(args, "--verify")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rcmd ResticCmd) Restore(snapshot string, opts RestoreOpts) error {
|
|
||||||
return rcmd.RunRestic("restore", opts, snapshot)
|
|
||||||
}
|
|
||||||
|
|
||||||
type TagList []string
|
type TagList []string
|
||||||
|
|
||||||
func (t TagList) String() string {
|
func (t TagList) String() string {
|
||||||
@ -232,32 +116,13 @@ type ForgetOpts struct {
|
|||||||
Prune bool `hcl:"Prune,optional"`
|
Prune bool `hcl:"Prune,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint:funlen,cyclop
|
|
||||||
func (fo ForgetOpts) ToArgs() (args []string) {
|
func (fo ForgetOpts) ToArgs() (args []string) {
|
||||||
// Add keep-*
|
args = maybeAddArgInt(args, "--keep-last", fo.KeepLast)
|
||||||
if fo.KeepLast > 0 {
|
args = maybeAddArgInt(args, "--keep-hourly", fo.KeepHourly)
|
||||||
args = append(args, "--keep-last", fmt.Sprint(fo.KeepLast))
|
args = maybeAddArgInt(args, "--keep-daily", fo.KeepDaily)
|
||||||
}
|
args = maybeAddArgInt(args, "--keep-weekly", fo.KeepWeekly)
|
||||||
|
args = maybeAddArgInt(args, "--keep-monthly", fo.KeepMonthly)
|
||||||
if fo.KeepHourly > 0 {
|
args = maybeAddArgInt(args, "--keep-yearly", fo.KeepYearly)
|
||||||
args = append(args, "--keep-hourly", fmt.Sprint(fo.KeepHourly))
|
|
||||||
}
|
|
||||||
|
|
||||||
if fo.KeepDaily > 0 {
|
|
||||||
args = append(args, "--keep-daily", fmt.Sprint(fo.KeepDaily))
|
|
||||||
}
|
|
||||||
|
|
||||||
if fo.KeepWeekly > 0 {
|
|
||||||
args = append(args, "--keep-weekly", fmt.Sprint(fo.KeepWeekly))
|
|
||||||
}
|
|
||||||
|
|
||||||
if fo.KeepMonthly > 0 {
|
|
||||||
args = append(args, "--keep-monthly", fmt.Sprint(fo.KeepMonthly))
|
|
||||||
}
|
|
||||||
|
|
||||||
if fo.KeepYearly > 0 {
|
|
||||||
args = append(args, "--keep-yearly", fmt.Sprint(fo.KeepYearly))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add keep-within-*
|
// Add keep-within-*
|
||||||
|
|
||||||
@ -295,22 +160,107 @@ func (fo ForgetOpts) ToArgs() (args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add prune options
|
// Add prune options
|
||||||
if fo.Prune {
|
args = maybeAddArgBool(args, "--prune", fo.Prune)
|
||||||
args = append(args, "--prune")
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rcmd ResticCmd) Forget(forgetOpts ForgetOpts) error {
|
type ResticGlobalOpts struct {
|
||||||
|
CaCertFile string `hcl:"CaCertFile,optional"`
|
||||||
|
CacheDir string `hcl:"CacheDir,optional"`
|
||||||
|
PasswordFile string `hcl:"PasswordFile,optional"`
|
||||||
|
TLSClientCertFile string `hcl:"TlsClientCertFile,optional"`
|
||||||
|
LimitDownload int `hcl:"LimitDownload,optional"`
|
||||||
|
LimitUpload int `hcl:"LimitUpload,optional"`
|
||||||
|
VerboseLevel int `hcl:"VerboseLevel,optional"`
|
||||||
|
CleanupCache bool `hcl:"CleanupCache,optional"`
|
||||||
|
NoCache bool `hcl:"NoCache,optional"`
|
||||||
|
NoLock bool `hcl:"NoLock,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (glo ResticGlobalOpts) ToArgs() (args []string) {
|
||||||
|
args = maybeAddArgString(args, "--cacert", glo.CaCertFile)
|
||||||
|
args = maybeAddArgString(args, "--cache-dir", glo.CacheDir)
|
||||||
|
args = maybeAddArgString(args, "--password-file", glo.PasswordFile)
|
||||||
|
args = maybeAddArgString(args, "--tls-client-cert", glo.TLSClientCertFile)
|
||||||
|
args = maybeAddArgInt(args, "--limit-download", glo.LimitDownload)
|
||||||
|
args = maybeAddArgInt(args, "--limit-upload", glo.LimitUpload)
|
||||||
|
args = maybeAddArgInt(args, "--verbose", glo.VerboseLevel)
|
||||||
|
args = maybeAddArgBool(args, "--cleanup-cache", glo.CleanupCache)
|
||||||
|
args = maybeAddArgBool(args, "--no-cache", glo.NoCache)
|
||||||
|
args = maybeAddArgBool(args, "--no-lock", glo.NoLock)
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
type Restic struct {
|
||||||
|
Logger *log.Logger
|
||||||
|
Repo string
|
||||||
|
Env map[string]string
|
||||||
|
Passphrase string
|
||||||
|
GlobalOpts *ResticGlobalOpts
|
||||||
|
Cwd string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcmd Restic) BuildEnv() []string {
|
||||||
|
if rcmd.Env == nil {
|
||||||
|
rcmd.Env = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rcmd.Passphrase != "" {
|
||||||
|
rcmd.Env["RESTIC_PASSWORD"] = rcmd.Passphrase
|
||||||
|
}
|
||||||
|
|
||||||
|
envList := os.Environ()
|
||||||
|
|
||||||
|
for name, value := range rcmd.Env {
|
||||||
|
envList = append(envList, fmt.Sprintf("%s=%s", name, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
return envList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcmd Restic) RunRestic(command string, options CommandOptions, commandArgs ...string) error {
|
||||||
|
args := []string{}
|
||||||
|
if rcmd.GlobalOpts != nil {
|
||||||
|
args = rcmd.GlobalOpts.ToArgs()
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, "--repo", rcmd.Repo, command)
|
||||||
|
args = append(args, options.ToArgs()...)
|
||||||
|
args = append(args, commandArgs...)
|
||||||
|
|
||||||
|
cmd := exec.Command("restic", args...)
|
||||||
|
|
||||||
|
cmd.Stdout = NewLogWriter(rcmd.Logger)
|
||||||
|
cmd.Stderr = cmd.Stdout
|
||||||
|
cmd.Env = rcmd.BuildEnv()
|
||||||
|
cmd.Dir = rcmd.Cwd
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("error running restic %s: %w", command, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcmd Restic) Backup(files []string, opts BackupOpts) error {
|
||||||
|
return rcmd.RunRestic("backup", opts, files...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcmd Restic) Restore(snapshot string, opts RestoreOpts) error {
|
||||||
|
return rcmd.RunRestic("restore", opts, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcmd Restic) Forget(forgetOpts ForgetOpts) error {
|
||||||
return rcmd.RunRestic("forget", forgetOpts)
|
return rcmd.RunRestic("forget", forgetOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rcmd ResticCmd) Check() error {
|
func (rcmd Restic) Check() error {
|
||||||
return rcmd.RunRestic("check", NoOpts{})
|
return rcmd.RunRestic("check", NoOpts{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rcmd ResticCmd) EnsureInit() error {
|
func (rcmd Restic) EnsureInit() error {
|
||||||
if err := rcmd.RunRestic("snapshots", NoOpts{}); err != nil {
|
if err := rcmd.RunRestic("snapshots", NoOpts{}); err != nil {
|
||||||
return rcmd.RunRestic("init", NoOpts{})
|
return rcmd.RunRestic("init", NoOpts{})
|
||||||
}
|
}
|
||||||
|
@ -148,24 +148,24 @@ func TestBuildEnv(t *testing.T) {
|
|||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
cmd main.ResticCmd
|
cmd main.Restic
|
||||||
expected []string
|
expected []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "No Env",
|
name: "No Env",
|
||||||
cmd: main.ResticCmd{}, // nolint:exhaustivestruct
|
cmd: main.Restic{}, // nolint:exhaustivestruct
|
||||||
expected: os.Environ(),
|
expected: os.Environ(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SetEnv",
|
name: "SetEnv",
|
||||||
cmd: main.ResticCmd{ // nolint:exhaustivestruct
|
cmd: main.Restic{ // nolint:exhaustivestruct
|
||||||
Env: map[string]string{"TestKey": "Value"},
|
Env: map[string]string{"TestKey": "Value"},
|
||||||
},
|
},
|
||||||
expected: append(os.Environ(), "TestKey=Value"),
|
expected: append(os.Environ(), "TestKey=Value"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SetEnv",
|
name: "SetEnv",
|
||||||
cmd: main.ResticCmd{ // nolint:exhaustivestruct
|
cmd: main.Restic{ // nolint:exhaustivestruct
|
||||||
Passphrase: "Shhhhhhhh!!",
|
Passphrase: "Shhhhhhhh!!",
|
||||||
},
|
},
|
||||||
expected: append(os.Environ(), "RESTIC_PASSWORD=Shhhhhhhh!!"),
|
expected: append(os.Environ(), "RESTIC_PASSWORD=Shhhhhhhh!!"),
|
||||||
|
Loading…
Reference in New Issue
Block a user