Add -R restart operation for timer and service jobs
Resets the countdown for timer jobs and restarts the process for service jobs. Disabled jobs are refused with a clear error message. Accepts hex ID or name like all other management operations. - restartJob() function with disabled-job guard - getopts R:, manage_count, mutual-exclusion error messages updated - 9 new tests in test.sh (112 total), 1 new tape command (24 total) - README options table, names prose, and future-ideas checklist updated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8e45f7917c
commit
530a2162bf
5 changed files with 70 additions and 6 deletions
|
|
@ -182,7 +182,7 @@ systab -C
|
||||||
|
|
||||||
### Job IDs and names
|
### Job IDs and names
|
||||||
|
|
||||||
Each job gets a 6-character hex ID (e.g., `a1b2c3`) displayed on creation and in status output. You can also assign a human-readable name with `-n` at creation time. Names can be used interchangeably with hex IDs in `-D`, `-E`, `-X`, `-S`, and `-L`. Names must be unique and cannot contain whitespace, pipes, or colons.
|
Each job gets a 6-character hex ID (e.g., `a1b2c3`) displayed on creation and in status output. You can also assign a human-readable name with `-n` at creation time. Names can be used interchangeably with hex IDs in `-D`, `-E`, `-X`, `-R`, `-S`, and `-L`. Names must be unique and cannot contain whitespace, pipes, or colons.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
|
|
@ -209,6 +209,7 @@ Management (accept hex ID or name):
|
||||||
-D <id|name> Disable a job
|
-D <id|name> Disable a job
|
||||||
-E <id|name> Enable a disabled job
|
-E <id|name> Enable a disabled job
|
||||||
-X <id|name> Delete a job (stop, disable, and remove unit files)
|
-X <id|name> Delete a job (stop, disable, and remove unit files)
|
||||||
|
-R <id|name> Restart a job (resets timer countdown / restarts service process)
|
||||||
-e Edit jobs in crontab-like format
|
-e Edit jobs in crontab-like format
|
||||||
-l Print jobs in crontab-like format to stdout
|
-l Print jobs in crontab-like format to stdout
|
||||||
-L [id|name] [filter] List job logs (optionally for a specific job and/or filtered)
|
-L [id|name] [filter] List job logs (optionally for a specific job and/or filtered)
|
||||||
|
|
@ -219,7 +220,7 @@ Management (accept hex ID or name):
|
||||||
|
|
||||||
## Future feature ideas
|
## Future feature ideas
|
||||||
|
|
||||||
- [ ] `-R` flag to restart / reload
|
- [x] `-R` flag to restart / reload
|
||||||
- [x] `-X` flag to delete
|
- [x] `-X` flag to delete
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"label": "tests",
|
"label": "tests",
|
||||||
"message": "127 passed",
|
"message": "136 passed",
|
||||||
"color": "brightgreen"
|
"color": "brightgreen"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,19 @@ Sleep 500ms
|
||||||
Enter
|
Enter
|
||||||
Sleep 2s
|
Sleep 2s
|
||||||
|
|
||||||
|
# ── Restart ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Hide
|
||||||
|
Type "./demo/note.sh 'Restart a job — resets the timer countdown'"
|
||||||
|
Enter
|
||||||
|
Sleep 500ms
|
||||||
|
Show
|
||||||
|
Sleep 1s
|
||||||
|
Type "systab -R healthcheck_home"
|
||||||
|
Sleep 500ms
|
||||||
|
Enter
|
||||||
|
Sleep 2s
|
||||||
|
|
||||||
# ── Notifications ─────────────────────────────────────────────
|
# ── Notifications ─────────────────────────────────────────────
|
||||||
|
|
||||||
Hide
|
Hide
|
||||||
|
|
|
||||||
36
systab
36
systab
|
|
@ -24,6 +24,7 @@ opt_status=false
|
||||||
opt_disable=""
|
opt_disable=""
|
||||||
opt_enable=""
|
opt_enable=""
|
||||||
opt_delete=""
|
opt_delete=""
|
||||||
|
opt_restart=""
|
||||||
opt_filter=""
|
opt_filter=""
|
||||||
opt_output=""
|
opt_output=""
|
||||||
opt_name=""
|
opt_name=""
|
||||||
|
|
@ -50,6 +51,7 @@ Management Options (accept hex ID or name):
|
||||||
-D <id|name> Disable a job
|
-D <id|name> Disable a job
|
||||||
-E <id|name> Enable a disabled job
|
-E <id|name> Enable a disabled job
|
||||||
-X <id|name> Delete a job (stop, disable, and remove unit files)
|
-X <id|name> Delete a job (stop, disable, and remove unit files)
|
||||||
|
-R <id|name> Restart a job (resets timer countdown / restarts service process)
|
||||||
-e Edit jobs in crontab-like format
|
-e Edit jobs in crontab-like format
|
||||||
-l Print jobs in crontab-like format to stdout
|
-l Print jobs in crontab-like format to stdout
|
||||||
-L [id|name] [filter] List job logs (optionally for a specific job and/or filtered)
|
-L [id|name] [filter] List job logs (optionally for a specific job and/or filtered)
|
||||||
|
|
@ -95,6 +97,10 @@ EXAMPLES:
|
||||||
$SCRIPT_NAME -X <id>
|
$SCRIPT_NAME -X <id>
|
||||||
$SCRIPT_NAME -X backup
|
$SCRIPT_NAME -X backup
|
||||||
|
|
||||||
|
# Restart a job
|
||||||
|
$SCRIPT_NAME -R <id>
|
||||||
|
$SCRIPT_NAME -R healthcheck_home
|
||||||
|
|
||||||
# View logs for backup jobs
|
# View logs for backup jobs
|
||||||
$SCRIPT_NAME -L backup
|
$SCRIPT_NAME -L backup
|
||||||
|
|
||||||
|
|
@ -353,6 +359,26 @@ deleteJob() {
|
||||||
echo "Deleted: $label"
|
echo "Deleted: $label"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Restart a job by hex ID or name
|
||||||
|
restartJob() {
|
||||||
|
local input="$1"
|
||||||
|
validateJobId "$input"
|
||||||
|
local id="$_resolved_id"
|
||||||
|
local name
|
||||||
|
name=$(getJobName "$SYSTEMD_USER_DIR/${_job_name}.service")
|
||||||
|
local label
|
||||||
|
label=$(formatJobId "$id" "$name")
|
||||||
|
if ! isJobEnabled "$_job_name"; then
|
||||||
|
error "Job is disabled, enable it first with -E: $label"
|
||||||
|
fi
|
||||||
|
if isJobService "$_job_name"; then
|
||||||
|
systemctl --user restart "${_job_name}.service" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
systemctl --user restart "${_job_name}.timer" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
echo "Restarted: $label"
|
||||||
|
}
|
||||||
|
|
||||||
# Get all managed unit files of a given type (service or timer)
|
# Get all managed unit files of a given type (service or timer)
|
||||||
getManagedUnits() {
|
getManagedUnits() {
|
||||||
local ext="$1"
|
local ext="$1"
|
||||||
|
|
@ -1205,7 +1231,7 @@ cleanJobs() {
|
||||||
|
|
||||||
# Parse command-line options
|
# Parse command-line options
|
||||||
parseOptions() {
|
parseOptions() {
|
||||||
while getopts "t:sc:f:n:im:oD:E:X:elLSCh" opt; do
|
while getopts "t:sc:f:n:im:oD:E:X:R:elLSCh" opt; do
|
||||||
case $opt in
|
case $opt in
|
||||||
t) opt_time="$OPTARG" ;;
|
t) opt_time="$OPTARG" ;;
|
||||||
s) opt_service=true ;;
|
s) opt_service=true ;;
|
||||||
|
|
@ -1229,6 +1255,7 @@ parseOptions() {
|
||||||
D) opt_disable="$OPTARG" ;;
|
D) opt_disable="$OPTARG" ;;
|
||||||
E) opt_enable="$OPTARG" ;;
|
E) opt_enable="$OPTARG" ;;
|
||||||
X) opt_delete="$OPTARG" ;;
|
X) opt_delete="$OPTARG" ;;
|
||||||
|
R) opt_restart="$OPTARG" ;;
|
||||||
e) opt_edit=true ;;
|
e) opt_edit=true ;;
|
||||||
l) opt_print_crontab=true ;;
|
l) opt_print_crontab=true ;;
|
||||||
L) opt_list=true ;;
|
L) opt_list=true ;;
|
||||||
|
|
@ -1272,6 +1299,7 @@ parseOptions() {
|
||||||
[[ -n "$opt_disable" ]] && manage_count=$((manage_count + 1))
|
[[ -n "$opt_disable" ]] && manage_count=$((manage_count + 1))
|
||||||
[[ -n "$opt_enable" ]] && manage_count=$((manage_count + 1))
|
[[ -n "$opt_enable" ]] && manage_count=$((manage_count + 1))
|
||||||
[[ -n "$opt_delete" ]] && manage_count=$((manage_count + 1))
|
[[ -n "$opt_delete" ]] && manage_count=$((manage_count + 1))
|
||||||
|
[[ -n "$opt_restart" ]] && manage_count=$((manage_count + 1))
|
||||||
$opt_edit && manage_count=$((manage_count + 1))
|
$opt_edit && manage_count=$((manage_count + 1))
|
||||||
$opt_print_crontab && manage_count=$((manage_count + 1))
|
$opt_print_crontab && manage_count=$((manage_count + 1))
|
||||||
$opt_list && manage_count=$((manage_count + 1))
|
$opt_list && manage_count=$((manage_count + 1))
|
||||||
|
|
@ -1279,11 +1307,11 @@ parseOptions() {
|
||||||
$opt_clean && manage_count=$((manage_count + 1))
|
$opt_clean && manage_count=$((manage_count + 1))
|
||||||
|
|
||||||
if [[ $manage_count -gt 1 ]]; then
|
if [[ $manage_count -gt 1 ]]; then
|
||||||
error "Options -D, -E, -X, -e, -l, -L, -S, and -C are mutually exclusive"
|
error "Options -D, -E, -X, -R, -e, -l, -L, -S, and -C are mutually exclusive"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $manage_count -gt 0 ]] && { [[ -n "$opt_time$opt_command$opt_file" ]] || $opt_service; }; then
|
if [[ $manage_count -gt 0 ]] && { [[ -n "$opt_time$opt_command$opt_file" ]] || $opt_service; }; then
|
||||||
error "Management options -D, -E, -X, -e, -l, -L, -S, and -C cannot be used with job creation options"
|
error "Management options -D, -E, -X, -R, -e, -l, -L, -S, and -C cannot be used with job creation options"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$opt_command" && -n "$opt_file" ]]; then
|
if [[ -n "$opt_command" && -n "$opt_file" ]]; then
|
||||||
|
|
@ -1314,6 +1342,8 @@ main() {
|
||||||
toggleJobById "$opt_enable" enable
|
toggleJobById "$opt_enable" enable
|
||||||
elif [[ -n "$opt_delete" ]]; then
|
elif [[ -n "$opt_delete" ]]; then
|
||||||
deleteJob "$opt_delete"
|
deleteJob "$opt_delete"
|
||||||
|
elif [[ -n "$opt_restart" ]]; then
|
||||||
|
restartJob "$opt_restart"
|
||||||
elif $opt_edit; then
|
elif $opt_edit; then
|
||||||
editJobs
|
editJobs
|
||||||
elif $opt_print_crontab; then
|
elif $opt_print_crontab; then
|
||||||
|
|
|
||||||
20
test.sh
20
test.sh
|
|
@ -502,6 +502,26 @@ assert_failure "-s and -i are mutually exclusive" $SYSTAB -s -i -c "echo test"
|
||||||
assert_failure "-s and -m are mutually exclusive" $SYSTAB -s -m user@example.com -c "echo test"
|
assert_failure "-s and -m are mutually exclusive" $SYSTAB -s -m user@example.com -c "echo test"
|
||||||
assert_failure "-s and -o are mutually exclusive" $SYSTAB -s -o -c "echo test"
|
assert_failure "-s and -o are mutually exclusive" $SYSTAB -s -o -c "echo test"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Restart (-R)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "${BOLD}--- Restart (-R) ---${RESET}"
|
||||||
|
|
||||||
|
assert_output "restart timer job by ID" "Restarted:" $SYSTAB -R "$id_recurring"
|
||||||
|
assert_output "restart timer job by name" "Restarted:" $SYSTAB -R mytest
|
||||||
|
assert_last_output_contains "restart by name shows name" "(mytest)"
|
||||||
|
assert_output "restart service job" "Restarted:" $SYSTAB -R "$id_svc"
|
||||||
|
|
||||||
|
$SYSTAB -D "$id_recurring"
|
||||||
|
assert_failure "restart disabled job fails" $SYSTAB -R "$id_recurring"
|
||||||
|
$SYSTAB -E "$id_recurring"
|
||||||
|
|
||||||
|
assert_failure "restart nonexistent job fails" $SYSTAB -R "zzzzzz"
|
||||||
|
assert_failure "-R and -D are mutually exclusive" $SYSTAB -R "$id_recurring" -D "$id_recurring"
|
||||||
|
assert_failure "-R cannot be combined with job creation" $SYSTAB -R "$id_recurring" -t daily -c "echo test"
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Clean
|
# Clean
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue