Skip to content

Commit 8b616d7

Browse files
committed
feat(bash): embed init templates in standalone build
1 parent 447d267 commit 8b616d7

4 files changed

Lines changed: 105 additions & 14 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ bash scripts/bash/systemd-service-manager/build.sh
1313
- `bin/systemd-service-manager`
1414
- `scripts/bash/systemd-service-manager.sh`
1515

16+
打包后的单文件产物内嵌了 `init` 所需模板,因此把脚本单独复制到其他目录后,仍可直接执行 `init` 生成 `deploy/systemd/` 骨架。
17+
1618
## Test
1719

1820
```bash

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,45 @@ mkdir -p "$(dirname "${LOCAL_OUTPUT}")"
4747
TMP_OUTPUT="$(mktemp)"
4848
trap 'rm -f "${TMP_OUTPUT}"' EXIT
4949

50+
emit_embedded_templates() {
51+
local template_name
52+
local template_path
53+
54+
printf '\n# --- embedded templates ---\n'
55+
printf '%s\n' 'ssm_write_embedded_template() {'
56+
printf '%s\n' ' local template_name="$1"'
57+
printf '%s\n' ' local destination="$2"'
58+
printf '%s\n' ' mkdir -p "$(dirname "${destination}")"'
59+
printf '%s\n' ' case "${template_name}" in'
60+
61+
for template_name in \
62+
"README.md" \
63+
"project.conf.example" \
64+
"project.env.example" \
65+
"service.conf.example" \
66+
"service.env.example" \
67+
"timer-service.conf.example" \
68+
"timer-task.conf.example"; do
69+
template_path="${SCRIPT_DIR}/templates/${template_name}"
70+
printf " '%s') cat >\"\${destination}\" <<'SSM_TEMPLATE_EOF'\n" "${template_name}"
71+
cat "${template_path}"
72+
printf '\nSSM_TEMPLATE_EOF\n'
73+
printf '%s\n' ' ;;'
74+
done
75+
76+
printf '%s\n' ' *)'
77+
printf '%s\n' ' return 1'
78+
printf '%s\n' ' ;;'
79+
printf '%s\n' ' esac'
80+
printf '%s\n' '}'
81+
}
82+
5083
{
5184
printf '#!/usr/bin/env bash\n'
5285
printf 'set -Eeuo pipefail\n'
5386
printf '# Auto-generated by scripts/bash/systemd-service-manager/build.sh. Do not edit directly.\n'
5487
printf 'SSM_STANDALONE=1\n'
88+
emit_embedded_templates
5589
for module in "${MODULES[@]}"; do
5690
printf '\n# --- %s ---\n' "$(basename "${module}")"
5791
cat "${module}"

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

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,45 @@ if [[ -n "${SSM_CMD_INIT_LOADED:-}" ]]; then
55
fi
66
SSM_CMD_INIT_LOADED=1
77

8+
# 按“内嵌模板优先、源码模板回退”写出模板文件,兼容单文件分发。
9+
ssm_write_template_file() {
10+
local template_name="$1"
11+
local destination="$2"
12+
13+
if declare -F ssm_write_embedded_template >/dev/null 2>&1; then
14+
if ssm_write_embedded_template "${template_name}" "${destination}"; then
15+
return 0
16+
fi
17+
fi
18+
19+
local template_root="${SSM_MANAGER_HOME}/templates"
20+
cp "${template_root}/${template_name}" "${destination}"
21+
}
22+
823
# 生成项目目录下的 deploy/systemd 骨架,包含 example 与实际可改文件。
924
ssm_cmd_init() {
1025
local project_dir
1126
project_dir="$(ssm_find_project_dir "${SSM_CLI_PROJECT_DIR:-}")"
1227

1328
local config_root
1429
config_root="$(ssm_config_root "${project_dir}")"
15-
local template_root="${SSM_MANAGER_HOME}/templates"
1630

1731
mkdir -p "${config_root}/services" "${config_root}/timers"
1832

19-
cp "${template_root}/README.md" "${config_root}/README.md"
33+
ssm_write_template_file "README.md" "${config_root}/README.md"
2034

21-
cp "${template_root}/project.conf.example" "${config_root}/project.conf.example"
22-
cp "${template_root}/project.env.example" "${config_root}/project.env.example"
23-
cp "${template_root}/project.conf.example" "${config_root}/project.conf"
24-
cp "${template_root}/project.env.example" "${config_root}/project.env"
35+
ssm_write_template_file "project.conf.example" "${config_root}/project.conf.example"
36+
ssm_write_template_file "project.env.example" "${config_root}/project.env.example"
37+
ssm_write_template_file "project.conf.example" "${config_root}/project.conf"
38+
ssm_write_template_file "project.env.example" "${config_root}/project.env"
2539

26-
cp "${template_root}/service.conf.example" "${config_root}/services/api.conf.example"
27-
cp "${template_root}/service.env.example" "${config_root}/services/api.env.example"
28-
cp "${template_root}/service.conf.example" "${config_root}/services/api.conf"
29-
cp "${template_root}/service.env.example" "${config_root}/services/api.env"
40+
ssm_write_template_file "service.conf.example" "${config_root}/services/api.conf.example"
41+
ssm_write_template_file "service.env.example" "${config_root}/services/api.env.example"
42+
ssm_write_template_file "service.conf.example" "${config_root}/services/api.conf"
43+
ssm_write_template_file "service.env.example" "${config_root}/services/api.env"
3044

31-
cp "${template_root}/timer-service.conf.example" "${config_root}/timers/restart-api.conf.example"
32-
cp "${template_root}/timer-service.conf.example" "${config_root}/timers/restart-api.conf"
33-
cp "${template_root}/timer-task.conf.example" "${config_root}/timers/cleanup.conf.example"
34-
cp "${template_root}/timer-task.conf.example" "${config_root}/timers/cleanup.conf"
45+
ssm_write_template_file "timer-service.conf.example" "${config_root}/timers/restart-api.conf.example"
46+
ssm_write_template_file "timer-service.conf.example" "${config_root}/timers/restart-api.conf"
47+
ssm_write_template_file "timer-task.conf.example" "${config_root}/timers/cleanup.conf.example"
48+
ssm_write_template_file "timer-task.conf.example" "${config_root}/timers/cleanup.conf"
3549
}

scripts/bash/systemd-service-manager/tests/init.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import fs from 'node:fs'
2+
import os from 'node:os'
23
import path from 'node:path'
34
import { afterEach, describe, expect, it } from 'vitest'
45
import {
56
cleanupWorkspace,
67
createWorkspace,
78
readText,
9+
runBuild,
10+
runCommand,
811
runSource,
912
} from './test-utils'
1013

@@ -53,4 +56,42 @@ describe('init command', () => {
5356
'DEFAULT_SCOPE=system',
5457
)
5558
})
59+
60+
it('can init from a copied standalone script without colocated templates', async () => {
61+
const workspace = createWorkspace()
62+
workspaces.push(workspace)
63+
64+
const build = await runBuild(workspace)
65+
expect(build.exitCode).toBe(0)
66+
67+
const portableRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ssm-portable-'))
68+
const portableScript = path.join(portableRoot, 'systemd-service-manager.sh')
69+
const projectRoot = path.join(portableRoot, 'demo-app')
70+
71+
fs.copyFileSync(workspace.builtLocal, portableScript)
72+
fs.chmodSync(portableScript, 0o755)
73+
fs.mkdirSync(projectRoot, { recursive: true })
74+
75+
const result = await runCommand(
76+
'bash',
77+
[portableScript, 'init', '--project', projectRoot],
78+
workspace,
79+
{ HOME: workspace.home },
80+
)
81+
82+
expect(result.exitCode).toBe(0)
83+
expect(
84+
fs.existsSync(path.join(projectRoot, 'deploy/systemd/project.conf')),
85+
).toBe(true)
86+
expect(
87+
fs.existsSync(
88+
path.join(projectRoot, 'deploy/systemd/services/api.conf.example'),
89+
),
90+
).toBe(true)
91+
expect(readText(path.join(projectRoot, 'deploy/systemd/README.md'))).toContain(
92+
'DEFAULT_SCOPE=system',
93+
)
94+
95+
fs.rmSync(portableRoot, { recursive: true, force: true })
96+
})
5697
})

0 commit comments

Comments
 (0)