feat: script and exec runtimes with configurable shell

Add runtime: script (shell file, default /bin/bash, optional stop_script) and runtime: exec (executable with args, optional stop_executable). Both support service_type simple|oneshot and working_dir.
This commit is contained in:
2026-10-12 19:45:54 +02:00
parent 173b4b2523
commit 95143dd998
5 changed files with 251 additions and 1 deletions
+46
View File
@@ -87,6 +87,15 @@ func ServiceName(u config.Unit, prefix, suffix string) string {
// Generate produces the .service file content for a unit.
func Generate(u config.Unit, prefix, suffix string) (string, error) {
if u.Command == "" {
if u.IsScript() && u.Script == "" {
return "", fmt.Errorf("unit %s: runtime script requires 'script' (or 'command')", u.Name)
}
if u.IsExec() && u.Executable == "" {
return "", fmt.Errorf("unit %s: runtime exec requires 'executable' (or 'command')", u.Name)
}
}
data := templateData{
ServiceName: ServiceName(u, prefix, suffix),
Unit: u,
@@ -96,6 +105,16 @@ func Generate(u config.Unit, prefix, suffix string) (string, error) {
}
switch {
case u.IsScript() && u.Command == "":
data.ExecStart, data.ExecStop = buildScriptCommands(u)
data.Label = filepath.Base(u.ShellPath()) + " script"
data.WorkingDir = u.WorkingDir
data.ServiceType = serviceType(u)
case u.IsExec() && u.Command == "":
data.ExecStart, data.ExecStop = buildExecutableCommands(u)
data.Label = "executable"
data.WorkingDir = u.WorkingDir
data.ServiceType = serviceType(u)
case u.IsStack() && u.Command == "" && StackMode(u) == StackModeCompose:
data.ExecStart, data.ExecStop = buildComposeCommands(u)
data.Label = "podman-compose stack"
@@ -134,6 +153,33 @@ func runtimeService(runtime string) string {
return ""
}
func serviceType(u config.Unit) string {
if u.ServiceType == "oneshot" {
return "oneshot"
}
return "simple"
}
func buildScriptCommands(u config.Unit) (start, stop string) {
shell := quoteArg(u.ShellPath())
start = shell + " " + quoteArg(u.Script)
if u.StopScript != "" {
stop = shell + " " + quoteArg(u.StopScript)
}
return start, stop
}
func buildExecutableCommands(u config.Unit) (start, stop string) {
parts := []string{quoteArg(u.Executable)}
for _, a := range u.Args {
parts = append(parts, quoteArg(a))
}
if u.StopExecutable != "" {
stop = quoteArg(u.StopExecutable)
}
return strings.Join(parts, " "), stop
}
func buildExecCommands(u config.Unit) (start, stop string) {
// If a custom command is provided, use it directly
if u.Command != "" {