Skip to content

Commit

Permalink
move main profile run code into wrapper
Browse files Browse the repository at this point in the history
allow to run self-update command with no configuration file
  • Loading branch information
creativeprojects committed Jun 25, 2020
1 parent 2321bf9 commit d32c172
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 95 deletions.
32 changes: 18 additions & 14 deletions commands.go
Expand Up @@ -11,27 +11,31 @@ import (
)

type ownCommand struct {
name string
description string
action func(commandLineFlags, []string) error
name string
description string
action func(commandLineFlags, []string) error
needConfiguration bool // true if the action needs a configuration file loaded
}

var (
ownCommands = []ownCommand{
{
name: "profiles",
description: "display profile names from the configuration file",
action: displayProfilesCommand,
name: "profiles",
description: "display profile names from the configuration file",
action: displayProfilesCommand,
needConfiguration: true,
},
{
name: "self-update",
description: "update resticprofile to latest version (does not update restic)",
action: selfUpdate,
name: "self-update",
description: "update resticprofile to latest version (does not update restic)",
action: selfUpdate,
needConfiguration: false,
},
{
name: "systemd-unit",
description: "create a user systemd timer",
action: createSystemdTimer,
name: "systemd-unit",
description: "create a user systemd timer",
action: createSystemdTimer,
needConfiguration: true,
},
}
)
Expand All @@ -44,9 +48,9 @@ func displayOwnCommands() {
_ = w.Flush()
}

func isOwnCommand(command string) bool {
func isOwnCommand(command string, configurationLoaded bool) bool {
for _, commandDef := range ownCommands {
if commandDef.name == command {
if commandDef.name == command && commandDef.needConfiguration == configurationLoaded {
return true
}
}
Expand Down
1 change: 1 addition & 0 deletions config/profile.go
Expand Up @@ -26,6 +26,7 @@ type Profile struct {
Lock string `mapstructure:"lock"`
RunBefore []string `mapstructure:"run-before"`
RunAfter []string `mapstructure:"run-after"`
RunAfterFail []string `mapstructure:"run-after-fail"`
Environment map[string]string `mapstructure:"env"`
Backup *BackupSection `mapstructure:"backup"`
Retention *RetentionSection `mapstructure:"retention"`
Expand Down
109 changes: 29 additions & 80 deletions main.go
Expand Up @@ -41,6 +41,8 @@ func main() {
setLoggerFlags(flags)
banner()

// Deprecated in version 0.7.0
// Keep for compatibility with version 0.6.1
if flags.selfUpdate {
err = confirmAndSelfUpdate(flags.verbose)
if err != nil {
Expand All @@ -50,6 +52,18 @@ func main() {
return
}

// resticprofile own commands (configuration file NOT loaded)
if len(flags.resticArgs) > 0 {
if isOwnCommand(flags.resticArgs[0], false) {
err = runOwnCommand(flags.resticArgs[0], flags, flags.resticArgs[1:])
if err != nil {
clog.Error(err)
os.Exit(1)
}
return
}
}

configFile, err := filesearch.FindConfigurationFile(flags.config)
if err != nil {
clog.Error(err)
Expand Down Expand Up @@ -96,16 +110,16 @@ func main() {
os.Exit(1)
}

// The remaining arguments are sent to the restic command line
// The remaining arguments are going to be sent to the restic command line
resticArguments := flags.resticArgs
resticCommand := global.DefaultCommand
if len(resticArguments) > 0 {
resticCommand = resticArguments[0]
resticArguments = resticArguments[1:]
}

// resticprofile own commands
if isOwnCommand(resticCommand) {
// resticprofile own commands (with configuration file)
if isOwnCommand(resticCommand, true) {
err = runOwnCommand(resticCommand, flags, resticArguments)
if err != nil {
clog.Error(err)
Expand Down Expand Up @@ -233,89 +247,24 @@ func runProfile(global *config.Global, flags commandLineFlags, profileName strin

// Catch CTR-C keypress
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)

wrapper := newResticWrapper(resticBinary, profile, resticArguments, sigChan)
if (global.Initialize || profile.Initialize) && resticCommand != constants.CommandInit {
_ = wrapper.runInitialize()
// it's ok for the initialize to error out when the repository exists
}

err = lockRun(profile.Lock, func() error {
var err error

// pre-profile commands
err = wrapper.runProfilePreCommand()
if err != nil {
return err
}

// pre-commands (for backup)
if resticCommand == constants.CommandBackup {
// Shell commands
err = wrapper.runPreCommand(resticCommand)
if err != nil {
return err
}
// Check
if profile.Backup != nil && profile.Backup.CheckBefore {
err = wrapper.runCheck()
if err != nil {
return err
}
}
// Retention
if profile.Retention != nil && profile.Retention.BeforeBackup {
err = wrapper.runRetention()
if err != nil {
return err
}
}
}

// Main command
err = wrapper.runCommand(resticCommand)
if err != nil {
return err
}

// post-commands (for backup)
if resticCommand == constants.CommandBackup {
// Retention
if profile.Retention != nil && profile.Retention.AfterBackup {
err = wrapper.runRetention()
if err != nil {
return err
}
}
// Check
if profile.Backup != nil && profile.Backup.CheckAfter {
err = wrapper.runCheck()
if err != nil {
return err
}
}
// Shell commands
err = wrapper.runPostCommand(resticCommand)
if err != nil {
return err
}
}

// post-profile commands
err = wrapper.runProfilePostCommand()
if err != nil {
return err
}

return nil
})
signal.Notify(sigChan, os.Interrupt, os.Kill)

wrapper := newResticWrapper(
resticBinary,
global.Initialize || profile.Initialize,
profile,
resticCommand,
resticArguments,
sigChan,
)
err = wrapper.runProfile()
if err != nil {
clog.Error(err)
os.Exit(1)
}
}

// lockRun is making sure the function is only run once by putting a lockfile on the disk
func lockRun(filename string, run func() error) error {
if filename == "" {
// No lock
Expand Down
111 changes: 110 additions & 1 deletion wrapper.go
Expand Up @@ -12,20 +12,112 @@ import (

type resticWrapper struct {
resticBinary string
initialize bool
profile *config.Profile
command string
moreArgs []string
sigChan chan os.Signal
}

func newResticWrapper(resticBinary string, profile *config.Profile, moreArgs []string, c chan os.Signal) *resticWrapper {
func newResticWrapper(
resticBinary string,
initialize bool,
profile *config.Profile,
command string,
moreArgs []string,
c chan os.Signal,
) *resticWrapper {
return &resticWrapper{
resticBinary: resticBinary,
initialize: initialize,
profile: profile,
command: command,
moreArgs: moreArgs,
sigChan: c,
}
}

func (r *resticWrapper) runProfile() error {
if r.initialize && r.command != constants.CommandInit {
_ = r.runInitialize()
// it's ok for the initialize to error out when the repository exists
}

err := lockRun(r.profile.Lock, func() error {
var err error

// pre-profile commands
err = r.runProfilePreCommand()
if err != nil {
return err
}

// pre-commands (for backup)
if r.command == constants.CommandBackup {
// Shell commands
err = r.runPreCommand(r.command)
if err != nil {
return err
}
// Check
if r.profile.Backup != nil && r.profile.Backup.CheckBefore {
err = r.runCheck()
if err != nil {
return err
}
}
// Retention
if r.profile.Retention != nil && r.profile.Retention.BeforeBackup {
err = r.runRetention()
if err != nil {
return err
}
}
}

// Main command
err = r.runCommand(r.command)
if err != nil {
return err
}

// post-commands (for backup)
if r.command == constants.CommandBackup {
// Retention
if r.profile.Retention != nil && r.profile.Retention.AfterBackup {
err = r.runRetention()
if err != nil {
return err
}
}
// Check
if r.profile.Backup != nil && r.profile.Backup.CheckAfter {
err = r.runCheck()
if err != nil {
return err
}
}
// Shell commands
err = r.runPostCommand(r.command)
if err != nil {
return err
}
}

// post-profile commands
err = r.runProfilePostCommand()
if err != nil {
return err
}

return nil
})
if err != nil {
return err
}
return nil
}

func (r *resticWrapper) runInitialize() error {
clog.Infof("Profile '%s': Initializing repository (if not existing)", r.profile.Name)
args := convertIntoArgs(r.profile.GetCommandFlags(constants.CommandInit))
Expand Down Expand Up @@ -159,6 +251,23 @@ func (r *resticWrapper) runProfilePostCommand() error {
return nil
}

func (r *resticWrapper) runProfilePostFailCommand() error {
if r.profile.RunAfterFail == nil || len(r.profile.RunAfterFail) == 0 {
return nil
}
for i, postCommand := range r.profile.RunAfterFail {
clog.Debugf("Starting 'run-after-fail' profile command %d/%d", i+1, len(r.profile.RunAfterFail))
env := append(os.Environ(), r.getEnvironment()...)
rCommand := newShellCommand(postCommand, nil, env)
rCommand.sigChan = r.sigChan
err := runShellCommand(rCommand)
if err != nil {
return err
}
}
return nil
}

func (r *resticWrapper) getEnvironment() []string {
if r.profile.Environment == nil || len(r.profile.Environment) == 0 {
return nil
Expand Down

0 comments on commit d32c172

Please sign in to comment.