Skip to content

Commit c5a4c28

Browse files
committed
2 parents 17e2ec1 + 6d006b2 commit c5a4c28

15 files changed

Lines changed: 476 additions & 29 deletions

File tree

scripts/bash/systemd-service-manager/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@
2020

2121
- `--project <path>`:指定项目根目录,默认使用当前目录。
2222
- `--dry-run`:只输出计划生成或安装的结果,不真正写入 systemd unit。
23+
- `--start`:给 `install` 使用,安装完成后立即启动目标 unit。
2324
- `--follow`:只给 `logs` 使用,持续跟随日志输出。
2425

26+
## Notes
27+
28+
- `start` / `stop` / `restart` / `status` / `logs` 这类命令依赖目标 unit 已经先执行过 `install`
29+
- `install` / `start` / `stop` / `restart` / `enable` / `disable` 这类 system scope 写操作在非 root 下会自动通过 `sudo` 重新执行脚本本身,因此不要求你手工把 `sudo` 写在命令前。
30+
2531
## Build
2632

2733
```bash
@@ -41,6 +47,7 @@ bash scripts/bash/systemd-service-manager/build.sh
4147
systemd-service-manager init
4248
systemd-service-manager list --project /path/to/app
4349
systemd-service-manager install service api --project /path/to/app
50+
systemd-service-manager install api --project /path/to/app --start
4451
systemd-service-manager install timer cleanup --project /path/to/app --dry-run
4552
systemd-service-manager logs service api --project /path/to/app --follow
4653
```

scripts/bash/systemd-service-manager/commands/disable.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ ssm_cmd_disable() {
1111
local target_name="${2:-}"
1212
ssm_load_target_context "${target_kind}" "${target_name}"
1313
ssm_systemctl "${SSM_ACTIVE_SCOPE}" disable "${SSM_ACTIVE_UNIT}"
14+
printf 'disabled=%s\n' "${SSM_ACTIVE_UNIT}"
15+
ssm_print_unit_summary "${SSM_ACTIVE_NAME}" "${SSM_ACTIVE_SCOPE}" "${SSM_ACTIVE_UNIT}"
1416
}

scripts/bash/systemd-service-manager/commands/enable.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ ssm_cmd_enable() {
1111
local target_name="${2:-}"
1212
ssm_load_target_context "${target_kind}" "${target_name}"
1313
ssm_systemctl "${SSM_ACTIVE_SCOPE}" enable "${SSM_ACTIVE_UNIT}"
14+
printf 'enabled=%s\n' "${SSM_ACTIVE_UNIT}"
15+
ssm_print_unit_summary "${SSM_ACTIVE_NAME}" "${SSM_ACTIVE_SCOPE}" "${SSM_ACTIVE_UNIT}"
1416
}

scripts/bash/systemd-service-manager/commands/install.sh

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,25 @@ SSM_CMD_INSTALL_LOADED=1
99
ssm_cmd_install() {
1010
local target_kind="${1:-}"
1111
local target_name="${2:-}"
12-
[[ -n "${target_kind}" ]] || ssm_die "Missing install target kind"
13-
[[ -n "${target_name}" ]] || ssm_die "Missing install target name"
12+
[[ -n "${target_kind}" ]] || ssm_die "Missing install target"
1413

1514
local project_dir
1615
project_dir="$(ssm_find_project_dir "${SSM_CLI_PROJECT_DIR:-}")"
16+
ssm_resolve_target_spec "${project_dir}" "${target_kind}" "${target_name}"
1717
local render_dir
1818
render_dir="$(mktemp -d)"
1919
trap 'rm -rf '"'"${render_dir}"'"'' RETURN
2020

2121
local source_file=""
2222
local scope="system"
2323

24-
case "${target_kind}" in
24+
case "${SSM_RESOLVED_TARGET_KIND}" in
2525
service)
26-
ssm_parse_service_config "${project_dir}" "${target_name}"
26+
ssm_parse_service_config "${project_dir}" "${SSM_RESOLVED_TARGET_NAME}"
2727
ssm_require_safe_name "UNIT_PREFIX" "${UNIT_PREFIX}"
28-
source_file="$(ssm_service_config_path "${project_dir}" "${target_name}")"
28+
source_file="$(ssm_service_config_path "${project_dir}" "${SSM_RESOLVED_TARGET_NAME}")"
2929
scope="${SSM_SERVICE_SCOPE}"
30-
local service_unit_file="${render_dir}/$(ssm_service_unit_name "${target_name}")"
30+
local service_unit_file="${render_dir}/$(ssm_service_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
3131
ssm_render_service_unit "${source_file}" >"${service_unit_file}"
3232
ssm_verify_unit_file "${service_unit_file}" || ssm_die "systemd-analyze verify failed for ${service_unit_file}"
3333
if [[ "${SSM_CLI_DRY_RUN}" == "1" ]]; then
@@ -37,18 +37,24 @@ ssm_cmd_install() {
3737
mkdir -p "$(ssm_unit_dir_for_scope "${scope}")"
3838
cp "${service_unit_file}" "$(ssm_unit_dir_for_scope "${scope}")/"
3939
ssm_daemon_reload "${scope}"
40+
printf 'installed=%s\n' "$(ssm_service_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
41+
if [[ "${SSM_CLI_START_AFTER_INSTALL}" == "1" ]]; then
42+
ssm_systemctl "${scope}" start "$(ssm_service_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
43+
printf 'started=%s\n' "$(ssm_service_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
44+
fi
45+
ssm_print_unit_summary "${SSM_RESOLVED_TARGET_NAME}" "${scope}" "$(ssm_service_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
4046
;;
4147
timer)
42-
ssm_parse_timer_config "${project_dir}" "${target_name}"
48+
ssm_parse_timer_config "${project_dir}" "${SSM_RESOLVED_TARGET_NAME}"
4349
ssm_require_safe_name "UNIT_PREFIX" "${UNIT_PREFIX}"
44-
source_file="$(ssm_timer_config_path "${project_dir}" "${target_name}")"
50+
source_file="$(ssm_timer_config_path "${project_dir}" "${SSM_RESOLVED_TARGET_NAME}")"
4551
scope="${SSM_TIMER_SCOPE}"
4652
local schedule_block
4753
schedule_block="$(ssm_resolve_schedule "${SCHEDULE}")"
4854
local task_unit_name
49-
task_unit_name="$(ssm_timer_task_unit_name "${target_name}")"
55+
task_unit_name="$(ssm_timer_task_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
5056
local task_unit_file="${render_dir}/${task_unit_name}"
51-
local timer_unit_file="${render_dir}/$(ssm_timer_unit_name "${target_name}")"
57+
local timer_unit_file="${render_dir}/$(ssm_timer_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
5258
local task_exec_command=""
5359

5460
if [[ "${TARGET_TYPE}" == "service" ]]; then
@@ -78,6 +84,12 @@ ssm_cmd_install() {
7884
cp "${task_unit_file}" "$(ssm_unit_dir_for_scope "${scope}")/"
7985
cp "${timer_unit_file}" "$(ssm_unit_dir_for_scope "${scope}")/"
8086
ssm_daemon_reload "${scope}"
87+
printf 'installed=%s\n' "$(ssm_timer_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
88+
if [[ "${SSM_CLI_START_AFTER_INSTALL}" == "1" ]]; then
89+
ssm_systemctl "${scope}" start "$(ssm_timer_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
90+
printf 'started=%s\n' "$(ssm_timer_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
91+
fi
92+
ssm_print_unit_summary "${SSM_RESOLVED_TARGET_NAME}" "${scope}" "$(ssm_timer_unit_name "${SSM_RESOLVED_TARGET_NAME}")"
8193
;;
8294
*)
8395
ssm_die "Unknown install target kind: ${target_kind}"

scripts/bash/systemd-service-manager/commands/restart.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ ssm_cmd_restart() {
1111
local target_name="${2:-}"
1212
ssm_load_target_context "${target_kind}" "${target_name}"
1313
ssm_systemctl "${SSM_ACTIVE_SCOPE}" restart "${SSM_ACTIVE_UNIT}"
14+
printf 'restarted=%s\n' "${SSM_ACTIVE_UNIT}"
15+
ssm_print_unit_summary "${SSM_ACTIVE_NAME}" "${SSM_ACTIVE_SCOPE}" "${SSM_ACTIVE_UNIT}"
1416
}

scripts/bash/systemd-service-manager/commands/start.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ ssm_cmd_start() {
1111
local target_name="${2:-}"
1212
ssm_load_target_context "${target_kind}" "${target_name}"
1313
ssm_systemctl "${SSM_ACTIVE_SCOPE}" start "${SSM_ACTIVE_UNIT}"
14+
printf 'started=%s\n' "${SSM_ACTIVE_UNIT}"
15+
ssm_print_unit_summary "${SSM_ACTIVE_NAME}" "${SSM_ACTIVE_SCOPE}" "${SSM_ACTIVE_UNIT}"
1416
}

scripts/bash/systemd-service-manager/commands/status.sh

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,5 @@ ssm_cmd_status() {
1010
local target_kind="${1:-}"
1111
local target_name="${2:-}"
1212
ssm_load_target_context "${target_kind}" "${target_name}"
13-
14-
local enabled_state=""
15-
local active_state=""
16-
enabled_state="$(ssm_systemctl "${SSM_ACTIVE_SCOPE}" is-enabled "${SSM_ACTIVE_UNIT}" 2>/dev/null || true)"
17-
active_state="$(ssm_systemctl "${SSM_ACTIVE_SCOPE}" is-active "${SSM_ACTIVE_UNIT}" 2>/dev/null || true)"
18-
19-
printf 'name=%s\n' "${target_name}"
20-
printf 'unit=%s\n' "${SSM_ACTIVE_UNIT}"
21-
printf 'scope=%s\n' "${SSM_ACTIVE_SCOPE}"
22-
printf 'installed=%s\n' "$(ssm_is_unit_installed "${SSM_ACTIVE_SCOPE}" "${SSM_ACTIVE_UNIT}")"
23-
printf 'enabled=%s\n' "${enabled_state:-unknown}"
24-
printf 'active=%s\n' "${active_state:-unknown}"
13+
ssm_print_unit_summary "${SSM_ACTIVE_NAME}" "${SSM_ACTIVE_SCOPE}" "${SSM_ACTIVE_UNIT}"
2514
}

scripts/bash/systemd-service-manager/commands/stop.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ ssm_cmd_stop() {
1111
local target_name="${2:-}"
1212
ssm_load_target_context "${target_kind}" "${target_name}"
1313
ssm_systemctl "${SSM_ACTIVE_SCOPE}" stop "${SSM_ACTIVE_UNIT}"
14+
printf 'stopped=%s\n' "${SSM_ACTIVE_UNIT}"
15+
ssm_print_unit_summary "${SSM_ACTIVE_NAME}" "${SSM_ACTIVE_SCOPE}" "${SSM_ACTIVE_UNIT}"
1416
}

scripts/bash/systemd-service-manager/common.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,50 @@ ssm_init_environment() {
4848
local script_path="$1"
4949
SSM_MANAGER_HOME="$(ssm_detect_manager_home "${script_path}")"
5050
}
51+
52+
# 返回当前有效 uid;测试可通过环境变量覆写,避免依赖宿主用户身份。
53+
ssm_current_euid() {
54+
if [[ -n "${SSM_TEST_EUID:-}" ]]; then
55+
printf '%s\n' "${SSM_TEST_EUID}"
56+
return 0
57+
fi
58+
59+
id -u
60+
}
61+
62+
# 判断当前是否已经具备 root 权限。
63+
ssm_is_root() {
64+
[[ "$(ssm_current_euid)" == "0" ]]
65+
}
66+
67+
# 把脚本入口解析成绝对路径,兼容 PATH 调用和显式路径调用。
68+
ssm_resolve_executable_path() {
69+
local source_path="$1"
70+
local argv0="$2"
71+
local candidate="${source_path}"
72+
73+
if [[ "${candidate}" != */* ]]; then
74+
candidate="${argv0}"
75+
fi
76+
77+
if [[ "${candidate}" != */* ]]; then
78+
candidate="$(command -v "${candidate}" 2>/dev/null || true)"
79+
fi
80+
81+
[[ -n "${candidate}" ]] || ssm_die "Unable to resolve executable path for elevation"
82+
83+
if command -v realpath >/dev/null 2>&1; then
84+
realpath "${candidate}" 2>/dev/null && return 0
85+
fi
86+
87+
if command -v readlink >/dev/null 2>&1; then
88+
readlink -f "${candidate}" 2>/dev/null && return 0
89+
fi
90+
91+
if [[ "${candidate}" == /* ]]; then
92+
printf '%s\n' "${candidate}"
93+
return 0
94+
fi
95+
96+
printf '%s/%s\n' "${PWD}" "${candidate}"
97+
}

scripts/bash/systemd-service-manager/lib/cli.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,25 @@ Commands:
2727
Common options:
2828
--project <path> 指定项目根目录,默认使用当前目录
2929
--dry-run 只预览将执行的操作,不实际写入 unit
30+
--start 安装完成后立即启动目标 unit
3031
--follow 配合 logs 使用,持续跟随日志输出
3132
33+
Target syntax:
34+
<command> <service|timer> <name> 显式指定目标类型
35+
<command> <name> 当名字只在 service 或 timer 中命中一个时自动推断类型
36+
37+
Notes:
38+
start 前需要目标 unit 已经 install
39+
system scope 的写操作在非 root 下会自动通过 sudo 重新执行
40+
3241
Examples:
3342
systemd-service-manager init
3443
systemd-service-manager list --project /path/to/app
3544
systemd-service-manager install service api --project /path/to/app
45+
systemd-service-manager install api --project /path/to/app
46+
systemd-service-manager install api --project /path/to/app --start
3647
systemd-service-manager install timer cleanup --project /path/to/app --dry-run
48+
systemd-service-manager start api --project /path/to/app
3749
systemd-service-manager logs service api --project /path/to/app --follow
3850
EOF
3951
}
@@ -43,6 +55,7 @@ ssm_parse_common_flags() {
4355
SSM_CLI_PROJECT_DIR=""
4456
SSM_CLI_DRY_RUN=0
4557
SSM_CLI_FOLLOW=0
58+
SSM_CLI_START_AFTER_INSTALL=0
4659
SSM_CLI_POSITIONAL_ARGS=()
4760

4861
while [[ "$#" -gt 0 ]]; do
@@ -56,6 +69,10 @@ ssm_parse_common_flags() {
5669
SSM_CLI_DRY_RUN=1
5770
shift
5871
;;
72+
--start)
73+
SSM_CLI_START_AFTER_INSTALL=1
74+
shift
75+
;;
5976
--follow)
6077
SSM_CLI_FOLLOW=1
6178
shift

0 commit comments

Comments
 (0)