Skip to content

Commit 57d1439

Browse files
Fix for continue-on-error broken in 0.26.0 (#407)
* Fix for continue-on-error broken in 0.26.0 * refactoring + add unit tests
1 parent 4181d9e commit 57d1439

File tree

4 files changed

+309
-187
lines changed

4 files changed

+309
-187
lines changed

commands.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ func prepareScheduledProfile(ctx *Context) {
552552
}
553553

554554
func runSchedule(_ io.Writer, cmdCtx commandContext) error {
555-
err := startProfileOrGroup(&cmdCtx.Context)
555+
err := startProfileOrGroup(&cmdCtx.Context, runProfile)
556556
if err != nil {
557557
return err
558558
}

main.go

Lines changed: 1 addition & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,14 @@ import (
55
"fmt"
66
"math/rand"
77
"os"
8-
"os/signal"
9-
"path/filepath"
108
"runtime"
119
"strings"
12-
"syscall"
1310
"text/tabwriter"
1411

1512
"github.com/creativeprojects/clog"
1613
"github.com/creativeprojects/resticprofile/config"
1714
"github.com/creativeprojects/resticprofile/constants"
1815
"github.com/creativeprojects/resticprofile/filesearch"
19-
"github.com/creativeprojects/resticprofile/monitor/prom"
20-
"github.com/creativeprojects/resticprofile/monitor/status"
2116
"github.com/creativeprojects/resticprofile/preventsleep"
2217
"github.com/creativeprojects/resticprofile/priority"
2318
"github.com/creativeprojects/resticprofile/remote"
@@ -261,7 +256,7 @@ func main() {
261256
ctx = ctx.WithCommand(ctx.request.command)
262257

263258
// it wasn't an internal command so we run a profile
264-
err = startProfileOrGroup(ctx)
259+
err = startProfileOrGroup(ctx, runProfile)
265260
if err != nil {
266261
clog.Error(err)
267262
if errors.Is(err, ErrProfileNotFound) {
@@ -367,186 +362,6 @@ func detectResticBinary(global *config.Global) (string, error) {
367362
return resticBinary, nil
368363
}
369364

370-
func startProfileOrGroup(ctx *Context) error {
371-
if ctx.config.HasProfile(ctx.request.profile) {
372-
// if running as a systemd timer
373-
notifyStart()
374-
defer notifyStop()
375-
376-
// Single profile run
377-
err := runProfile(ctx)
378-
if err != nil {
379-
return err
380-
}
381-
382-
} else if ctx.config.HasProfileGroup(ctx.request.profile) {
383-
// Group run
384-
group, err := ctx.config.GetProfileGroup(ctx.request.profile)
385-
if err != nil {
386-
clog.Errorf("cannot load group '%s': %v", ctx.request.profile, err)
387-
}
388-
if group != nil && len(group.Profiles) > 0 {
389-
// if running as a systemd timer
390-
notifyStart()
391-
defer notifyStop()
392-
393-
// profile name is the group name
394-
groupName := ctx.request.profile
395-
396-
for i, profileName := range group.Profiles {
397-
clog.Debugf("[%d/%d] starting profile '%s' from group '%s'", i+1, len(group.Profiles), profileName, groupName)
398-
ctx = ctx.WithProfile(profileName).WithGroup(groupName)
399-
err = runProfile(ctx)
400-
if err != nil {
401-
if ctx.global.GroupContinueOnError && group.ContinueOnError.IsTrueOrUndefined() {
402-
// keep going to the next profile
403-
clog.Error(err)
404-
continue
405-
}
406-
// fail otherwise
407-
return err
408-
}
409-
}
410-
}
411-
412-
} else {
413-
return fmt.Errorf("%w: %q", ErrProfileNotFound, ctx.request.profile)
414-
}
415-
return nil
416-
}
417-
418-
func openProfile(c *config.Config, profileName string) (profile *config.Profile, cleanup func(), err error) {
419-
done := false
420-
for attempts := 3; attempts > 0 && !done; attempts-- {
421-
profile, err = c.GetProfile(profileName)
422-
if err != nil || profile == nil {
423-
err = fmt.Errorf("cannot load profile '%s': %w", profileName, err)
424-
break
425-
}
426-
427-
done = true
428-
429-
// Adjust baseDir if needed
430-
if len(profile.BaseDir) > 0 {
431-
var currentDir string
432-
currentDir, err = os.Getwd()
433-
if err != nil {
434-
err = fmt.Errorf("changing base directory not allowed as current directory is unknown in profile %q: %w", profileName, err)
435-
break
436-
}
437-
438-
if baseDir, _ := filepath.Abs(profile.BaseDir); filepath.ToSlash(baseDir) != filepath.ToSlash(currentDir) {
439-
if cleanup == nil {
440-
cleanup = func() {
441-
if e := os.Chdir(currentDir); e != nil {
442-
panic(fmt.Errorf(`fatal: failed restoring working directory "%s": %w`, currentDir, e))
443-
}
444-
}
445-
}
446-
447-
if err = os.Chdir(baseDir); err == nil {
448-
clog.Infof("profile '%s': base directory is %q", profileName, baseDir)
449-
done = false // reload the profile as .CurrentDir & .Env has changed
450-
} else {
451-
err = fmt.Errorf(`cannot change to base directory "%s" in profile %q: %w`, baseDir, profileName, err)
452-
break
453-
}
454-
}
455-
}
456-
}
457-
458-
if cleanup == nil {
459-
cleanup = func() {
460-
// nothing to do
461-
}
462-
}
463-
return
464-
}
465-
466-
func runProfile(ctx *Context) error {
467-
profile, cleanup, err := openProfile(ctx.config, ctx.request.profile)
468-
defer cleanup()
469-
if err != nil {
470-
return err
471-
}
472-
ctx.profile = profile
473-
474-
displayProfileDeprecationNotices(profile)
475-
ctx.config.DisplayConfigurationIssues()
476-
477-
// Send the quiet/verbose down to restic as well (override profile configuration)
478-
if ctx.flags.quiet {
479-
profile.Quiet = true
480-
profile.Verbose = constants.VerbosityNone
481-
}
482-
if ctx.flags.verbose {
483-
profile.Verbose = constants.VerbosityLevel1
484-
profile.Quiet = false
485-
}
486-
if ctx.flags.veryVerbose {
487-
profile.Verbose = constants.VerbosityLevel3
488-
profile.Quiet = false
489-
}
490-
491-
// change log filter according to profile settings
492-
if profile.Quiet {
493-
changeLevelFilter(clog.LevelWarning)
494-
} else if profile.Verbose > constants.VerbosityNone && !ctx.flags.veryVerbose {
495-
changeLevelFilter(clog.LevelDebug)
496-
}
497-
498-
// tell the profile what version of restic is in use
499-
if e := profile.SetResticVersion(ctx.global.ResticVersion); e != nil {
500-
clog.Warningf("restic version %q is no valid semver: %s", ctx.global.ResticVersion, e.Error())
501-
}
502-
503-
// Specific case for the "host" flag where an empty value should be replaced by the hostname
504-
hostname := "none"
505-
currentHost, err := os.Hostname()
506-
if err == nil {
507-
hostname = currentHost
508-
}
509-
profile.SetHost(hostname)
510-
511-
if ctx.request.schedule != "" {
512-
// this is a scheduled profile
513-
loadScheduledProfile(ctx)
514-
}
515-
516-
// Catch CTR-C keypress, or other signal sent by a service manager (systemd)
517-
sigChan := make(chan os.Signal, 1)
518-
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGABRT)
519-
// remove signal catch before leaving
520-
defer signal.Stop(sigChan)
521-
522-
ctx.sigChan = sigChan
523-
wrapper := newResticWrapper(ctx)
524-
525-
if ctx.noLock {
526-
wrapper.ignoreLock()
527-
} else if ctx.lockWait > 0 {
528-
wrapper.maxWaitOnLock(ctx.lockWait)
529-
}
530-
531-
// add progress receivers if necessary
532-
if profile.StatusFile != "" {
533-
wrapper.addProgress(status.NewProgress(profile, status.NewStatus(profile.StatusFile)))
534-
}
535-
if profile.PrometheusPush != "" || profile.PrometheusSaveToFile != "" {
536-
wrapper.addProgress(prom.NewProgress(profile, prom.NewMetrics(profile.Name, ctx.request.group, version, profile.PrometheusLabels)))
537-
}
538-
539-
err = wrapper.runProfile()
540-
if err != nil {
541-
return err
542-
}
543-
return nil
544-
}
545-
546-
func loadScheduledProfile(ctx *Context) {
547-
ctx.schedule = ctx.profile.Schedules()[ctx.command]
548-
}
549-
550365
// randomBool returns true for Heads and false for Tails
551366
func randomBool() bool {
552367
return rand.Int31n(10000) < 5000

0 commit comments

Comments
 (0)