diff --git a/go.mod b/go.mod
index 6023dca994..c99fefc9a3 100644
--- a/go.mod
+++ b/go.mod
@@ -22,9 +22,8 @@ require (
github.com/jedisct1/go-sieve-cache v0.1.9
github.com/jedisct1/xsecretbox v0.0.0-20241212092125-3afc4917ac41
github.com/k-sone/critbitgo v1.4.0
- github.com/kardianos/service v1.2.4
+ github.com/kardianos/service v1.3.0
github.com/lifenjoiner/dhcpdns v0.0.7
- github.com/miekg/dns v1.1.72
github.com/powerman/check v1.9.1
github.com/quic-go/quic-go v0.60.0
golang.org/x/crypto v0.53.0
@@ -45,10 +44,7 @@ require (
github.com/quic-go/qpack v0.6.0 // indirect
github.com/smartystreets/goconvey v1.8.1 // indirect
go.uber.org/mock v0.6.0 // indirect
- golang.org/x/mod v0.37.0 // indirect
- golang.org/x/sync v0.21.0 // indirect
golang.org/x/text v0.38.0 // indirect
- golang.org/x/tools v0.46.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3 // indirect
google.golang.org/grpc v1.81.1 // indirect
google.golang.org/protobuf v1.36.11 // indirect
diff --git a/go.sum b/go.sum
index f71fbb346a..54c292a91e 100644
--- a/go.sum
+++ b/go.sum
@@ -54,12 +54,10 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE=
github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s=
-github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk=
-github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc=
+github.com/kardianos/service v1.3.0 h1:/LGy+xPP2TM+GLTiCZ2di7cy0Jd/qrawlTUfqKYFdTI=
+github.com/kardianos/service v1.3.0/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc=
github.com/lifenjoiner/dhcpdns v0.0.7 h1:VJM2aFWHU9V7M5v4UYYNaHhIHZkbdvSI6WGGpq6/TNQ=
github.com/lifenjoiner/dhcpdns v0.0.7/go.mod h1:BixeaGeafYzDIuDCYIUbSOdi4m+TScpzI9cZGYgzgSk=
-github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
-github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
@@ -84,18 +82,12 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
-golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
-golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
-golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
-golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
-golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk=
-golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3 h1:phvBWCAQMGN1945mp5fjCXP6jEF0+a0+4TjokS4sxNY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
diff --git a/vendor/github.com/kardianos/service/service.go b/vendor/github.com/kardianos/service/service.go
index 130fc22d48..adef097e15 100644
--- a/vendor/github.com/kardianos/service/service.go
+++ b/vendor/github.com/kardianos/service/service.go
@@ -231,6 +231,53 @@ func New(i Interface, c *Config) (Service, error) {
// - OnFailureDelayDuration string ( "1s" ) - Delay before restarting the service, time.Duration string.
//
// - OnFailureResetPeriod int ( 10 ) - Reset period for errors, seconds.
+//
+// # Custom service-file templates
+//
+// The LaunchdConfig, SystemdScript, UpstartScript, SysvScript, RCSScript, and
+// OpenRCScript options each supply a template used to render the service file
+// in place of the built-in one. Set one by placing the template string in
+// Config.Option under the matching key:
+//
+// c := &service.Config{
+// Name: "myservice",
+// Option: service.KeyValue{
+// "SystemdScript": myScript, // template string, syntax below
+// },
+// }
+//
+// SysvScript is also the key read by the procd, AIX, FreeBSD, and Solaris
+// backends; the key set available to a custom script is whatever the active
+// init system passes (see below).
+//
+// Templates are rendered by a small built-in engine (not text/template). The
+// supported actions are:
+//
+// - {{Key}} substitute a value.
+// - {{Key | fn | fn}} substitute, piped through function(s).
+// - {{if Key}}…{{end}} include the body when Key is non-empty.
+// - {{if Key}}…{{else}}…{{end}} with an else branch.
+// - {{range Key}}…{{.}}…{{end}} repeat the body once per item of a list
+// value, with {{.}} bound to the current item.
+// - {{- …}} and {{… -}} trim whitespace before or after the action.
+//
+// Every value is a string or a list of strings; a list is also truthy in
+// {{if}} when non-empty. There is no dotted field access and no arithmetic or
+// boolean functions — any such logic is resolved before rendering. The exact
+// keys and pipeline functions available for a given platform are precisely
+// those used by that platform's default template, so read the corresponding
+// source constant to see them: launchdConfig (darwin), systemdScript,
+// upstartScript, sysvScript, rcsScript, openRCScript, procdScript, svcConfig
+// (AIX), rcScript (FreeBSD), and manifest (Solaris).
+//
+// Compatibility: earlier versions parsed these options with the standard
+// library text/template. Custom scripts written for that engine — using dotted
+// fields such as {{.Name}}, the and/or/not/eq/gt functions, or method calls —
+// must be rewritten in the syntax above; they will otherwise fail to render
+// with an "unknown template key" error. text/template was removed because it
+// reaches reflect.Value.MethodByName, which forces the linker into a
+// conservative mode that defeats dead-code elimination and substantially
+// inflates binaries importing this package.
type KeyValue map[string]interface{}
// bool returns the value of the given name, assuming the value is a boolean.
diff --git a/vendor/github.com/kardianos/service/service_aix.go b/vendor/github.com/kardianos/service/service_aix.go
index de7a907272..eda2aa4b1d 100644
--- a/vendor/github.com/kardianos/service/service_aix.go
+++ b/vendor/github.com/kardianos/service/service_aix.go
@@ -18,7 +18,6 @@ import (
"strconv"
"strings"
"syscall"
- "text/template"
"time"
)
@@ -96,21 +95,13 @@ func (s *aixService) Platform() string {
return version
}
-func (s *aixService) template() *template.Template {
- functions := template.FuncMap{
- "bool": func(v bool) string {
- if v {
- return "true"
- }
- return "false"
- },
- }
+var svcConfigTemplate = mustParse(svcConfig)
- customConfig := s.Option.string(optionSysvScript, "")
- if customConfig != "" {
- return template.Must(template.New("").Funcs(functions).Parse(customConfig))
+func (s *aixService) template() (*tmpl, error) {
+ if custom := s.Option.string(optionSysvScript, ""); custom != "" {
+ return parseTemplate(custom)
}
- return template.Must(template.New("").Funcs(functions).Parse(svcConfig))
+ return svcConfigTemplate, nil
}
func (s *aixService) configPath() (string, error) {
@@ -147,15 +138,20 @@ func (s *aixService) Install() error {
}
defer f.Close()
- to := struct {
- *Config
- Path string
- }{
- Config: s.Config,
- Path: path,
+ data := map[string]any{
+ "Name": s.Config.Name,
+ "Path": path,
}
- if err = s.template().Execute(f, &to); err != nil {
+ t, err := s.template()
+ if err != nil {
+ return err
+ }
+ out, err := t.render(data, nil)
+ if err != nil {
+ return err
+ }
+ if _, err = f.WriteString(out); err != nil {
return err
}
@@ -271,13 +267,13 @@ func (s *aixService) SystemLogger(errs chan<- error) (Logger, error) {
return newSysLogger(s.Name, errs)
}
-var svcConfig = `#!/bin/ksh
+const svcConfig = `#!/bin/ksh
case "$1" in
start)
- startsrc -s {{.Name}}
+ startsrc -s {{Name}}
;;
stop)
- stopsrc -s {{.Name}}
+ stopsrc -s {{Name}}
;;
*)
echo "Usage: $0 {start|stop}"
diff --git a/vendor/github.com/kardianos/service/service_darwin.go b/vendor/github.com/kardianos/service/service_darwin.go
index 727ef2cb31..4d8fd9fb05 100644
--- a/vendor/github.com/kardianos/service/service_darwin.go
+++ b/vendor/github.com/kardianos/service/service_darwin.go
@@ -14,7 +14,6 @@ import (
"regexp"
"strings"
"syscall"
- "text/template"
"time"
)
@@ -134,22 +133,38 @@ func (s *darwinLaunchdService) getLogPath(logDir, logType string) string {
return fmt.Sprintf("%s/%s.%s.log", logDir, s.Name, logType)
}
-func (s *darwinLaunchdService) template() *template.Template {
- functions := template.FuncMap{
- "bool": func(v bool) string {
- if v {
- return "true"
- }
- return "false"
- },
- }
+// plistEscaper matches text/template's html escaper, which the launchd plist
+// was previously rendered with.
+var plistEscaper = strings.NewReplacer(
+ `&`, "&",
+ `'`, "'",
+ `<`, "<",
+ `>`, ">",
+ `"`, """,
+)
+
+// launchdFuncs is the pipeline function map for the launchd plist: html escapes
+// a value for XML.
+var launchdFuncs = map[string]tmplFunc{
+ "html": func(s string) (string, error) { return plistEscaper.Replace(s), nil },
+}
- customConfig := s.Option.string(optionLaunchdConfig, "")
+var launchdTemplate = mustParse(launchdConfig)
+
+func (s *darwinLaunchdService) template() (*tmpl, error) {
+ if custom := s.Option.string(optionLaunchdConfig, ""); custom != "" {
+ return parseTemplate(custom)
+ }
+ return launchdTemplate, nil
+}
- if customConfig != "" {
- return template.Must(template.New("").Funcs(functions).Parse(customConfig))
+// launchdBool renders a Go bool as the "true"/"false" element name used in the
+// plist (previously the text/template "bool" function).
+func launchdBool(v bool) string {
+ if v {
+ return "true"
}
- return template.Must(template.New("").Funcs(functions).Parse(launchdConfig))
+ return "false"
}
func (s *darwinLaunchdService) Install() error {
@@ -182,25 +197,37 @@ func (s *darwinLaunchdService) Install() error {
}
stdOutPath, stdErrPath, _ := s.getLogPaths()
- var to = &struct {
- *Config
- Path string
-
- KeepAlive, RunAtLoad bool
- SessionCreate bool
- StandardOutPath string
- StandardErrorPath string
- }{
- Config: s.Config,
- Path: path,
- KeepAlive: s.Option.bool(optionKeepAlive, optionKeepAliveDefault),
- RunAtLoad: s.Option.bool(optionRunAtLoad, optionRunAtLoadDefault),
- SessionCreate: s.Option.bool(optionSessionCreate, optionSessionCreateDefault),
- StandardOutPath: stdOutPath,
- StandardErrorPath: stdErrPath,
+
+ c := s.Config
+ data := map[string]any{
+ "Name": c.Name,
+ "Path": path,
+ "Arguments": c.Arguments,
+ "ChRoot": c.ChRoot,
+ "UserName": c.UserName,
+ "WorkingDirectory": c.WorkingDirectory,
+ "KeepAlive": launchdBool(s.Option.bool(optionKeepAlive, optionKeepAliveDefault)),
+ "RunAtLoad": launchdBool(s.Option.bool(optionRunAtLoad, optionRunAtLoadDefault)),
+ "SessionCreate": launchdBool(s.Option.bool(optionSessionCreate, optionSessionCreateDefault)),
+ "StandardOutPath": stdOutPath,
+ "StandardErrorPath": stdErrPath,
+ // Each entry is the two escaped plist lines for one variable.
+ "EnvVars": envVars(c.EnvVars, func(k, v string) string {
+ return "\t\t" + plistEscaper.Replace(k) + "\n" +
+ "\t\t" + plistEscaper.Replace(v) + ""
+ }),
}
- return s.template().Execute(f, to)
+ t, err := s.template()
+ if err != nil {
+ return err
+ }
+ out, err := t.render(data, launchdFuncs)
+ if err != nil {
+ return err
+ }
+ _, err = f.WriteString(out)
+ return err
}
func (s *darwinLaunchdService) Uninstall() error {
@@ -290,58 +317,39 @@ func (s *darwinLaunchdService) SystemLogger(errs chan<- error) (Logger, error) {
return newSysLogger(s.Name, errs)
}
-var launchdConfig = `
+const launchdConfig = `
Disabled
- {{- if .EnvVars}}
- EnvironmentVariables
+ {{if EnvVars}}EnvironmentVariables
- {{- range $k, $v := .EnvVars}}
- {{html $k}}
- {{html $v}}
- {{- end}}
-
- {{- end}}
- KeepAlive
- <{{bool .KeepAlive}}/>
+{{range EnvVars}}{{.}}
+{{end}}
+ {{end}}KeepAlive
+ <{{KeepAlive}}/>
Label
- {{html .Name}}
+ {{Name | html}}
ProgramArguments
- {{html .Path}}
- {{- if .Config.Arguments}}
- {{- range .Config.Arguments}}
- {{html .}}
- {{- end}}
- {{- end}}
-
- {{- if .ChRoot}}
- RootDirectory
- {{html .ChRoot}}
- {{- end}}
- RunAtLoad
- <{{bool .RunAtLoad}}/>
+ {{Path | html}}
+{{range Arguments}} {{. | html}}
+{{end}}
+ {{if ChRoot}}RootDirectory
+ {{ChRoot | html}}
+ {{end}}RunAtLoad
+ <{{RunAtLoad}}/>
SessionCreate
- <{{bool .SessionCreate}}/>
- {{- if .StandardErrorPath}}
- StandardErrorPath
- {{html .StandardErrorPath}}
- {{- end}}
- {{- if .StandardOutPath}}
- StandardOutPath
- {{html .StandardOutPath}}
- {{- end}}
- {{- if .UserName}}
- UserName
- {{html .UserName}}
- {{- end}}
- {{- if .WorkingDirectory}}
- WorkingDirectory
- {{html .WorkingDirectory}}
- {{- end}}
-
+ <{{SessionCreate}}/>
+ {{if StandardErrorPath}}StandardErrorPath
+ {{StandardErrorPath | html}}
+ {{end}}{{if StandardOutPath}}StandardOutPath
+ {{StandardOutPath | html}}
+ {{end}}{{if UserName}}UserName
+ {{UserName | html}}
+ {{end}}{{if WorkingDirectory}}WorkingDirectory
+ {{WorkingDirectory | html}}
+ {{end}}
`
diff --git a/vendor/github.com/kardianos/service/service_freebsd.go b/vendor/github.com/kardianos/service/service_freebsd.go
index 752f5feb85..4570773039 100644
--- a/vendor/github.com/kardianos/service/service_freebsd.go
+++ b/vendor/github.com/kardianos/service/service_freebsd.go
@@ -10,7 +10,6 @@ import (
"os/signal"
"path/filepath"
"syscall"
- "text/template"
)
const version = "freebsd"
@@ -70,23 +69,13 @@ func (s *freebsdService) Platform() string {
return version
}
-func (s *freebsdService) template() *template.Template {
- functions := template.FuncMap{
- "bool": func(v bool) string {
- if v {
- return "true"
- }
- return "false"
- },
- }
-
- customConfig := s.Option.string(optionSysvScript, "")
+var rcTemplate = mustParse(rcScript)
- if customConfig != "" {
- return template.Must(template.New("").Funcs(functions).Parse(customConfig))
- } else {
- return template.Must(template.New("").Funcs(functions).Parse(rcScript))
+func (s *freebsdService) template() (*tmpl, error) {
+ if custom := s.Option.string(optionSysvScript, ""); custom != "" {
+ return parseTemplate(custom)
}
+ return rcTemplate, nil
}
func (s *freebsdService) configPath() (cp string, err error) {
@@ -120,18 +109,25 @@ func (s *freebsdService) Install() error {
}
defer f.Close()
- var to = &struct {
- *Config
- Path string
- }{
- s.Config,
- path,
+ c := s.Config
+ data := map[string]any{
+ "Name": c.Name,
+ "Path": path,
+ "Arguments": c.Arguments,
+ "WorkingDirectory": c.WorkingDirectory,
}
- err = s.template().Execute(f, to)
+ t, err := s.template()
if err != nil {
return err
}
+ out, err := t.render(data, nil)
+ if err != nil {
+ return err
+ }
+ if _, err = f.WriteString(out); err != nil {
+ return err
+ }
if err = os.Chmod(confPath, 0755); err != nil {
return err
@@ -207,20 +203,20 @@ func (s *freebsdService) SystemLogger(errs chan<- error) (Logger, error) {
return newSysLogger(s.Name, errs)
}
-var rcScript = `#!/bin/sh
+const rcScript = `#!/bin/sh
-# PROVIDE: {{.Name}}
+# PROVIDE: {{Name}}
# REQUIRE: SERVERS
# KEYWORD: shutdown
. /etc/rc.subr
-name="{{.Name}}"
-{{.Name}}_env="IS_DAEMON=1"
+name="{{Name}}"
+{{Name}}_env="IS_DAEMON=1"
pidfile="/var/run/${name}.pid"
command="/usr/sbin/daemon"
-daemon_args="-P ${pidfile} -r -t \"${name}: daemon\"{{if .WorkingDirectory}} -c {{.WorkingDirectory}}{{end}}"
-command_args="${daemon_args} {{.Path}}{{range .Arguments}} {{.}}{{end}}"
+daemon_args="-P ${pidfile} -r -t \"${name}: daemon\"{{if WorkingDirectory}} -c {{WorkingDirectory}}{{end}}"
+command_args="${daemon_args} {{Path}}{{range Arguments}} {{.}}{{end}}"
run_rc_command "$1"
`
diff --git a/vendor/github.com/kardianos/service/service_linux.go b/vendor/github.com/kardianos/service/service_linux.go
index edd5a0abd3..ea32181768 100644
--- a/vendor/github.com/kardianos/service/service_linux.go
+++ b/vendor/github.com/kardianos/service/service_linux.go
@@ -209,11 +209,19 @@ func isInContainerCGroup(cgroupPath string) (bool, error) {
return false, nil
}
-var tf = map[string]interface{}{
- "cmd": func(s string) string {
- return `"` + strings.Replace(s, `"`, `\"`, -1) + `"`
- },
- "cmdEscape": func(s string) string {
- return strings.Replace(s, " ", `\x20`, -1)
- },
+// cmdQuote and cmdEscape are the plain string transforms used when building
+// service files. They are also exposed to custom user templates through tfs.
+func cmdQuote(s string) string {
+ return `"` + strings.ReplaceAll(s, `"`, `\"`) + `"`
+}
+
+func cmdEscape(s string) string {
+ return strings.ReplaceAll(s, " ", `\x20`)
+}
+
+// tfs is the string-only function map for the mini template engine, exposing
+// the cmd/cmdEscape pipeline functions to the built-in and custom templates.
+var tfs = map[string]tmplFunc{
+ "cmd": func(s string) (string, error) { return cmdQuote(s), nil },
+ "cmdEscape": func(s string) (string, error) { return cmdEscape(s), nil },
}
diff --git a/vendor/github.com/kardianos/service/service_openrc_linux.go b/vendor/github.com/kardianos/service/service_openrc_linux.go
index c678e3aef6..1f12a085dd 100644
--- a/vendor/github.com/kardianos/service/service_openrc_linux.go
+++ b/vendor/github.com/kardianos/service/service_openrc_linux.go
@@ -9,7 +9,6 @@ import (
"os/signal"
"regexp"
"syscall"
- "text/template"
"time"
)
@@ -55,13 +54,13 @@ func (s *openrc) Platform() string {
return s.platform
}
-func (s *openrc) template() *template.Template {
- customScript := s.Option.string(optionOpenRCScript, "")
+var openRCTemplate = mustParse(openRCScript)
- if customScript != "" {
- return template.Must(template.New("").Funcs(tf).Parse(customScript))
+func (s *openrc) template() (*tmpl, error) {
+ if custom := s.Option.string(optionOpenRCScript, ""); custom != "" {
+ return parseTemplate(custom)
}
- return template.Must(template.New("").Funcs(tf).Parse(openRCScript))
+ return openRCTemplate, nil
}
func newOpenRCService(i Interface, platform string, c *Config) (Service, error) {
@@ -110,20 +109,36 @@ func (s *openrc) Install() error {
return err
}
- var to = &struct {
- *Config
- Path string
- LogDirectory string
- }{
- s.Config,
- path,
- s.Option.string(optionLogDirectory, defaultLogDirectory),
+ c := s.Config
+
+ // depend() lists each dependency on its own tab-indented line; bake the
+ // tab in here so the template is a plain {{range}}.
+ deps := make([]string, len(c.Dependencies))
+ for i, d := range c.Dependencies {
+ deps[i] = "\t" + d
+ }
+
+ data := map[string]any{
+ "DisplayName": c.DisplayName,
+ "Description": c.Description,
+ "Path": path,
+ "Arguments": c.Arguments,
+ "Dependencies": deps,
+ "LogDirectory": s.Option.string(optionLogDirectory, defaultLogDirectory),
+ "EnvVars": envVars(c.EnvVars, func(k, v string) string { return "export " + k + "=" + v }),
}
- err = s.template().Execute(f, to)
+ t, err := s.template()
+ if err != nil {
+ return err
+ }
+ out, err := t.render(data, tfs)
if err != nil {
return err
}
+ if _, err = f.WriteString(out); err != nil {
+ return err
+ }
// run rc-update
return s.runAction("add")
}
@@ -221,23 +236,16 @@ func (s *openrc) run(action string, args ...string) error {
const openRCScript = `#!/sbin/openrc-run
supervisor=supervise-daemon
-name="{{.DisplayName}}"
-description="{{.Description}}"
-command={{.Path|cmdEscape}}
-{{- if .Arguments }}
-command_args="{{range .Arguments}}{{.}} {{end}}"
-{{- end }}
-name=$(basename $(readlink -f $command))
-supervise_daemon_args="--stdout {{.LogDirectory}}/${name}.log --stderr {{.LogDirectory}}/${name}.err"
-
-{{range $k, $v := .EnvVars -}}
-export {{$k}}={{$v}}
-{{end -}}
-
-{{- if .Dependencies }}
-depend() {
-{{- range $i, $dep := .Dependencies}}
-{{"\t"}}{{$dep}}{{end}}
-}
-{{- end}}
-`
+name="{{DisplayName}}"
+description="{{Description}}"
+command={{Path | cmdEscape}}
+{{if Arguments}}command_args="{{range Arguments}}{{.}} {{end}}"
+{{end}}name=$(basename $(readlink -f $command))
+supervise_daemon_args="--stdout {{LogDirectory}}/${name}.log --stderr {{LogDirectory}}/${name}.err"
+
+{{range EnvVars}}{{.}}
+{{end}}
+{{if Dependencies}}depend() {
+{{range Dependencies}}{{.}}
+{{end}}}
+{{end}}`
diff --git a/vendor/github.com/kardianos/service/service_procd_linux.go b/vendor/github.com/kardianos/service/service_procd_linux.go
index 3213784cd1..9de40c8d64 100644
--- a/vendor/github.com/kardianos/service/service_procd_linux.go
+++ b/vendor/github.com/kardianos/service/service_procd_linux.go
@@ -9,7 +9,6 @@ import (
"os"
"os/exec"
"strings"
- "text/template"
"time"
)
@@ -39,13 +38,13 @@ func newProcdService(i Interface, platform string, c *Config) (Service, error) {
return p, nil
}
-func (p *procd) template() *template.Template {
- customScript := p.Option.string(optionSysvScript, "")
+var procdTemplate = mustParse(procdScript)
- if customScript != "" {
- return template.Must(template.New("").Funcs(tf).Parse(customScript))
+func (p *procd) template() (*tmpl, error) {
+ if custom := p.Option.string(optionSysvScript, ""); custom != "" {
+ return parseTemplate(custom)
}
- return template.Must(template.New("").Funcs(tf).Parse(procdScript))
+ return procdTemplate, nil
}
func (p *procd) Install() error {
@@ -69,20 +68,24 @@ func (p *procd) Install() error {
return err
}
- var to = &struct {
- *Config
- Path string
- LogDirectory string
- }{
- p.Config,
- path,
- p.Option.string(optionLogDirectory, defaultLogDirectory),
+ c := p.Config
+ data := map[string]any{
+ "Path": path,
+ "Name": c.Name,
+ "Arguments": c.Arguments,
}
- err = p.template().Execute(f, to)
+ t, err := p.template()
if err != nil {
return err
}
+ out, err := t.render(data, tfs)
+ if err != nil {
+ return err
+ }
+ if _, err = f.WriteString(out); err != nil {
+ return err
+ }
if err = os.Chmod(confPath, 0755); err != nil {
return err
@@ -151,8 +154,8 @@ USE_PROCD=1
START=21
# Before network stops
STOP=89
-cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}"
-name="{{.Name}}"
+cmd="{{Path}}{{range Arguments}} {{. | cmd}}{{end}}"
+name="{{Name}}"
pid_file="/var/run/${name}.pid"
start_service() {
diff --git a/vendor/github.com/kardianos/service/service_rcs_linux.go b/vendor/github.com/kardianos/service/service_rcs_linux.go
index 0fca97dcdd..cabf5b1d22 100644
--- a/vendor/github.com/kardianos/service/service_rcs_linux.go
+++ b/vendor/github.com/kardianos/service/service_rcs_linux.go
@@ -14,7 +14,6 @@ import (
"regexp"
"strings"
"syscall"
- "text/template"
"time"
)
@@ -85,13 +84,13 @@ func (s *rcs) configPath() (cp string, err error) {
return
}
-func (s *rcs) template() *template.Template {
- customScript := s.Option.string(optionRCSScript, "")
+var rcsTemplate = mustParse(rcsScript)
- if customScript != "" {
- return template.Must(template.New("").Funcs(tf).Parse(customScript))
+func (s *rcs) template() (*tmpl, error) {
+ if custom := s.Option.string(optionRCSScript, ""); custom != "" {
+ return parseTemplate(custom)
}
- return template.Must(template.New("").Funcs(tf).Parse(rcsScript))
+ return rcsTemplate, nil
}
func (s *rcs) Install() error {
@@ -115,20 +114,28 @@ func (s *rcs) Install() error {
return err
}
- var to = &struct {
- *Config
- Path string
- LogDirectory string
- }{
- s.Config,
- path,
- s.Option.string(optionLogDirectory, defaultLogDirectory),
+ c := s.Config
+ data := map[string]any{
+ "Description": c.Description,
+ "DisplayName": c.DisplayName,
+ "Name": c.Name,
+ "Path": path,
+ "Arguments": c.Arguments,
+ "WorkingDirectory": c.WorkingDirectory,
+ "LogDirectory": s.Option.string(optionLogDirectory, defaultLogDirectory),
}
- err = s.template().Execute(f, to)
+ t, err := s.template()
if err != nil {
return err
}
+ out, err := t.render(data, tfs)
+ if err != nil {
+ return err
+ }
+ if _, err = f.WriteString(out); err != nil {
+ return err
+ }
if err = os.Chmod(confPath, 0755); err != nil {
return err
@@ -216,25 +223,25 @@ func (s *rcs) Restart() error {
const rcsScript = `#!/bin/sh
# For RedHat and cousins:
# chkconfig: - 99 01
-# description: {{.Description}}
-# processname: {{.Path}}
+# description: {{Description}}
+# processname: {{Path}}
### BEGIN INIT INFO
-# Provides: {{.Path}}
+# Provides: {{Path}}
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
-# Short-Description: {{.DisplayName}}
-# Description: {{.Description}}
+# Short-Description: {{DisplayName}}
+# Description: {{Description}}
### END INIT INFO
-cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}"
+cmd="{{Path}}{{range Arguments}} {{. | cmd}}{{end}}"
-name={{.Name}}
+name={{Name}}
pid_file="/var/run/$name.pid"
-stdout_log="{{.LogDirectory}}/$name.log"
-stderr_log="{{.LogDirectory}}/$name.err"
+stdout_log="{{LogDirectory}}/$name.log"
+stderr_log="{{LogDirectory}}/$name.err"
[ -e /etc/sysconfig/$name ] && . /etc/sysconfig/$name
@@ -252,7 +259,7 @@ case "$1" in
echo "Already started"
else
echo "Starting $name"
- {{if .WorkingDirectory}}cd '{{.WorkingDirectory}}'{{end}}
+ {{if WorkingDirectory}}cd '{{WorkingDirectory}}'{{end}}
$cmd >> "$stdout_log" 2>> "$stderr_log" &
echo $! > "$pid_file"
if ! is_running; then
diff --git a/vendor/github.com/kardianos/service/service_solaris.go b/vendor/github.com/kardianos/service/service_solaris.go
index 55e0074062..96ac4513f9 100644
--- a/vendor/github.com/kardianos/service/service_solaris.go
+++ b/vendor/github.com/kardianos/service/service_solaris.go
@@ -12,7 +12,6 @@ import (
"os/signal"
"regexp"
"syscall"
- "text/template"
"time"
)
@@ -79,23 +78,13 @@ func (s *solarisService) Platform() string {
return version
}
-func (s *solarisService) template() *template.Template {
- functions := template.FuncMap{
- "bool": func(v bool) string {
- if v {
- return "true"
- }
- return "false"
- },
- }
-
- customConfig := s.Option.string(optionSysvScript, "")
+var manifestTemplate = mustParse(manifest)
- if customConfig != "" {
- return template.Must(template.New("").Funcs(functions).Parse(customConfig))
- } else {
- return template.Must(template.New("").Funcs(functions).Parse(manifest))
+func (s *solarisService) template() (*tmpl, error) {
+ if custom := s.Option.string(optionSysvScript, ""); custom != "" {
+ return parseTemplate(custom)
}
+ return manifestTemplate, nil
}
func (s *solarisService) configPath() (string, error) {
@@ -132,19 +121,22 @@ func (s *solarisService) Install() error {
if err := xml.EscapeText(escaped, []byte(s.DisplayName)); err == nil {
Display = escaped.String()
}
- var to = &struct {
- *Config
- Prefix string
- Display string
- Path string
- }{
- s.Config,
- s.Prefix,
- Display,
- path,
+ data := map[string]any{
+ "Name": s.Config.Name,
+ "Prefix": s.Prefix,
+ "Display": Display,
+ "Path": path,
}
- err = s.template().Execute(f, to)
+ t, err := s.template()
+ if err != nil {
+ return err
+ }
+ out, err := t.render(data, nil)
+ if err != nil {
+ return err
+ }
+ _, err = f.WriteString(out)
if err != nil {
return err
}
@@ -241,12 +233,12 @@ func (s *solarisService) SystemLogger(errs chan<- error) (Logger, error) {
return newSysLogger(s.Name, errs)
}
-var manifest = `
+const manifest = `
-
+
@@ -278,13 +270,13 @@ var manifest = `