Skip to content

Commit 56f20af

Browse files
Squashed commit of the following: (#259)
* avoid the file to be checked by the json schema validator * commit updated mock * create Init method * allow run-schedule command on v2 format * merge ProfileName and Profiles into one Profiles field * fix: remove schedule name from arguments * docs: add information on run-schedule command * update crond to support new run-schedule command line * add a default log file on darwin * Merge from pass-context-struct * return a new context on each `With` method * add tests * move logTarget to context * refactoring Context struct * pass context to own commands and profile runnner
1 parent e93874d commit 56f20af

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1527
-866
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"cSpell.words": [
33
"afero",
44
"caffeinate",
5+
"creativeprojects",
56
"crond",
67
"ionice",
78
"journalctl",

codecov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ coverage:
2727
threshold: "2%"
2828
patch:
2929
default:
30-
target: "80%"
30+
target: "70%"
3131
threshold: "2%"

commands.go

Lines changed: 112 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func init() {
4141

4242
func getOwnCommands() []ownCommand {
4343
return []ownCommand{
44+
// commands that don't need loading the configuration
4445
{
4546
name: "help",
4647
description: "display help (use resticprofile help [command])",
@@ -56,6 +57,29 @@ func getOwnCommands() []ownCommand {
5657
needConfiguration: false,
5758
flags: map[string]string{"-v, --verbose": "display detailed version information"},
5859
},
60+
{
61+
name: "random-key",
62+
description: "generate a cryptographically secure random key to use as a restic keyfile",
63+
action: randomKey,
64+
needConfiguration: false,
65+
hide: true, // replaced by the generate command
66+
},
67+
{
68+
name: "generate",
69+
description: "generate resources such as random key, bash/zsh completion scripts, etc.",
70+
longDescription: "The \"generate\" command is used to create various resources and print them to stdout",
71+
action: generateCommand,
72+
needConfiguration: false,
73+
hide: false,
74+
flags: map[string]string{
75+
"--random-key [size]": "generate a cryptographically secure random key to use as a restic keyfile (size defaults to 1024 when omitted)",
76+
"--config-reference [--version 0.15] [template]": "generate a config file reference from a go template (defaults to the built-in markdown template when omitted)",
77+
"--json-schema [--version 0.15] [v1|v2]": "generate a JSON schema that validates resticprofile configuration files in YAML or JSON format",
78+
"--bash-completion": "generate a shell completion script for bash",
79+
"--zsh-completion": "generate a shell completion script for zsh",
80+
},
81+
},
82+
// commands that need the configuration
5983
{
6084
name: "profiles",
6185
description: "display profile names from the configuration file",
@@ -70,13 +94,6 @@ func getOwnCommands() []ownCommand {
7094
action: showProfile,
7195
needConfiguration: true,
7296
},
73-
{
74-
name: "random-key",
75-
description: "generate a cryptographically secure random key to use as a restic keyfile",
76-
action: randomKey,
77-
needConfiguration: false,
78-
hide: true,
79-
},
8097
{
8198
name: "schedule",
8299
description: "schedule jobs from a profile (or of all profiles)",
@@ -108,19 +125,15 @@ func getOwnCommands() []ownCommand {
108125
flags: map[string]string{"--all": "display the status of all scheduled jobs of all profiles"},
109126
},
110127
{
111-
name: "generate",
112-
description: "generate resources such as random key, bash/zsh completion scripts, etc.",
113-
longDescription: "The \"generate\" command is used to create various resources and print them to stdout",
114-
action: generateCommand,
115-
needConfiguration: false,
128+
name: "run-schedule",
129+
description: "runs a scheduled job. This command should only be called by the scheduling service",
130+
longDescription: "The \"run-schedule\" command loads the scheduled job configuration from the name in parameter and runs the restic command with the arguments defined in the profile. The name in parameter is <command>@<profile-name> for the configuration file v1, and the schedule name for the configuration file v2+.",
131+
pre: preRunSchedule,
132+
action: runSchedule,
133+
needConfiguration: true,
116134
hide: false,
117-
flags: map[string]string{
118-
"--random-key [size]": "generate a cryptographically secure random key to use as a restic keyfile (size defaults to 1024 when omitted)",
119-
"--config-reference [--version 0.15] [template]": "generate a config file reference from a go template (defaults to the built-in markdown template when omitted)",
120-
"--json-schema [--version 0.15] [v1|v2]": "generate a JSON schema that validates resticprofile configuration files in YAML or JSON format",
121-
"--bash-completion": "generate a shell completion script for bash",
122-
"--zsh-completion": "generate a shell completion script for zsh",
123-
},
135+
hideInCompletion: true,
136+
noProfile: true,
124137
},
125138
// hidden commands
126139
{
@@ -328,10 +341,9 @@ func showProfile(output io.Writer, ctx commandContext) error {
328341
return nil
329342
}
330343

331-
func showSchedules(output io.Writer, schedulesConfig []*config.ScheduleConfig) {
332-
for _, schedule := range schedulesConfig {
333-
export := schedule.Export()
334-
err := config.ShowStruct(output, export, "schedule "+export.Profiles[0]+"-"+export.Command)
344+
func showSchedules(output io.Writer, schedules []*config.Schedule) {
345+
for _, schedule := range schedules {
346+
err := config.ShowStruct(output, schedule, "schedule "+schedule.CommandName+"@"+schedule.Profiles[0])
335347
if err != nil {
336348
fmt.Fprintln(output, err)
337349
}
@@ -408,7 +420,7 @@ func createSchedule(_ io.Writer, ctx commandContext) error {
408420
type profileJobs struct {
409421
scheduler schedule.SchedulerConfig
410422
profile string
411-
jobs []*config.ScheduleConfig
423+
jobs []*config.Schedule
412424
}
413425

414426
allJobs := make([]profileJobs, 0, 1)
@@ -516,7 +528,7 @@ func statusSchedule(w io.Writer, ctx commandContext) error {
516528
return nil
517529
}
518530

519-
func statusScheduleProfile(scheduler schedule.SchedulerConfig, profile *config.Profile, schedules []*config.ScheduleConfig, flags commandLineFlags) error {
531+
func statusScheduleProfile(scheduler schedule.SchedulerConfig, profile *config.Profile, schedules []*config.Schedule, flags commandLineFlags) error {
520532
displayProfileDeprecationNotices(profile)
521533

522534
err := statusJobs(schedule.NewHandler(scheduler), flags.name, schedules)
@@ -526,7 +538,7 @@ func statusScheduleProfile(scheduler schedule.SchedulerConfig, profile *config.P
526538
return nil
527539
}
528540

529-
func getScheduleJobs(c *config.Config, flags commandLineFlags) (schedule.SchedulerConfig, *config.Profile, []*config.ScheduleConfig, error) {
541+
func getScheduleJobs(c *config.Config, flags commandLineFlags) (schedule.SchedulerConfig, *config.Profile, []*config.Schedule, error) {
530542
global, err := c.GetGlobalSection()
531543
if err != nil {
532544
return nil, nil, nil, fmt.Errorf("cannot load global section: %w", err)
@@ -543,14 +555,14 @@ func getScheduleJobs(c *config.Config, flags commandLineFlags) (schedule.Schedul
543555
return schedule.NewSchedulerConfig(global), profile, profile.Schedules(), nil
544556
}
545557

546-
func requireScheduleJobs(schedules []*config.ScheduleConfig, flags commandLineFlags) error {
558+
func requireScheduleJobs(schedules []*config.Schedule, flags commandLineFlags) error {
547559
if len(schedules) == 0 {
548560
return fmt.Errorf("no schedule found for profile '%s'", flags.name)
549561
}
550562
return nil
551563
}
552564

553-
func getRemovableScheduleJobs(c *config.Config, flags commandLineFlags) (schedule.SchedulerConfig, *config.Profile, []*config.ScheduleConfig, error) {
565+
func getRemovableScheduleJobs(c *config.Config, flags commandLineFlags) (schedule.SchedulerConfig, *config.Profile, []*config.Schedule, error) {
554566
scheduler, profile, schedules, err := getScheduleJobs(c, flags)
555567
if err != nil {
556568
return nil, nil, nil, err
@@ -560,18 +572,88 @@ func getRemovableScheduleJobs(c *config.Config, flags commandLineFlags) (schedul
560572
for _, command := range profile.SchedulableCommands() {
561573
declared := false
562574
for _, s := range schedules {
563-
if declared = s.SubTitle == command; declared {
575+
if declared = s.CommandName == command; declared {
564576
break
565577
}
566578
}
567579
if !declared {
568-
schedules = append(schedules, config.NewRemoveOnlyConfig(profile.Name, command))
580+
schedules = append(schedules, config.NewEmptySchedule(profile.Name, command))
569581
}
570582
}
571583

572584
return scheduler, profile, schedules, nil
573585
}
574586

587+
func preRunSchedule(ctx *Context) error {
588+
if len(ctx.request.arguments) < 1 {
589+
return errors.New("run-schedule command expects one argument: schedule name")
590+
}
591+
scheduleName := ctx.request.arguments[0]
592+
// temporarily allow v2 configuration to run v1 schedules
593+
// if ctx.config.GetVersion() < config.Version02
594+
{
595+
// schedule name is in the form "command@profile"
596+
commandName, profileName, ok := strings.Cut(scheduleName, "@")
597+
if !ok {
598+
return errors.New("the expected format of the schedule name is <command>@<profile-name>")
599+
}
600+
ctx.request.profile = profileName
601+
ctx.request.schedule = scheduleName
602+
ctx.command = commandName
603+
// remove the parameter from the arguments
604+
ctx.request.arguments = ctx.request.arguments[1:]
605+
606+
// don't save the profile in the context now, it's only loaded but not prepared
607+
profile, err := ctx.config.GetProfile(profileName)
608+
if err != nil || profile == nil {
609+
return fmt.Errorf("cannot load profile '%s': %w", profileName, err)
610+
}
611+
// get the list of all scheduled commands to find the current command
612+
schedules := profile.Schedules()
613+
for _, schedule := range schedules {
614+
if schedule.CommandName == ctx.command {
615+
ctx.schedule = schedule
616+
prepareScheduledProfile(ctx)
617+
break
618+
}
619+
}
620+
}
621+
return nil
622+
}
623+
624+
func prepareScheduledProfile(ctx *Context) {
625+
clog.Debugf("preparing scheduled profile %q", ctx.request.schedule)
626+
// log file
627+
if len(ctx.schedule.Log) > 0 {
628+
ctx.logTarget = ctx.schedule.Log
629+
}
630+
// battery
631+
if ctx.schedule.IgnoreOnBatteryLessThan > 0 {
632+
ctx.stopOnBattery = ctx.schedule.IgnoreOnBatteryLessThan
633+
} else if ctx.schedule.IgnoreOnBattery {
634+
ctx.stopOnBattery = 100
635+
}
636+
// lock
637+
if ctx.schedule.GetLockWait() > 0 {
638+
ctx.lockWait = ctx.schedule.LockWait
639+
}
640+
if ctx.schedule.GetLockMode() == config.ScheduleLockModeDefault {
641+
if ctx.schedule.GetLockWait() > 0 {
642+
ctx.lockWait = ctx.schedule.GetLockWait()
643+
}
644+
} else if ctx.schedule.GetLockMode() == config.ScheduleLockModeIgnore {
645+
ctx.noLock = true
646+
}
647+
}
648+
649+
func runSchedule(_ io.Writer, cmdCtx commandContext) error {
650+
err := startProfileOrGroup(&cmdCtx.Context)
651+
if err != nil {
652+
return err
653+
}
654+
return nil
655+
}
656+
575657
func testElevationCommand(_ io.Writer, ctx commandContext) error {
576658
if ctx.flags.isChild {
577659
client := remote.NewClient(ctx.flags.parentPort)

commands_display.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ func displayOwnCommandHelp(output io.Writer, commandName string, ctx commandCont
114114
commandFlags = "[command specific flags]"
115115
}
116116
out("Usage:\n")
117-
out("\t%s %s\n\n", getCommonUsageHelpLine(command.name, command.needConfiguration), commandFlags)
117+
out("\t%s %s\n\n", getCommonUsageHelpLine(command.name, command.needConfiguration && !command.noProfile), commandFlags)
118118

119-
var flags []string
119+
var flags = make([]string, 0, len(command.flags))
120120
for f, _ := range command.flags {
121121
flags = append(flags, f)
122122
}

0 commit comments

Comments
 (0)