From 9d98c56603e8666c7d66dd890574052a7df2731d Mon Sep 17 00:00:00 2001 From: bdm-oslandia Date: Fri, 6 Dec 2024 11:38:33 +0100 Subject: [PATCH] fix: apply corrections from golangci-lint --- .golangci.yml | 30 ++++++++++++++++++++++++++ console.go | 9 ++++++-- example/logging/main.go | 23 +++++++++++++------- example/runner/runner.go | 44 +++++++++++++++++++++++---------------- example/simple/main.go | 12 ++++++----- example/stopPause/main.go | 12 ++++++----- service.go | 37 +++++++++++++++++++------------- service_aix.go | 5 ++--- service_freebsd.go | 9 ++++---- service_linux.go | 32 ++++++++++++++++------------ service_linux_test.go | 34 +++++++++++++++--------------- service_openrc_linux.go | 35 ++++++++++++++----------------- service_rcs_linux.go | 37 ++++++++++++++++---------------- service_systemd_linux.go | 32 ++++++++++++++-------------- service_sysv_linux.go | 27 ++++++++++++------------ service_test.go | 15 +++++++------ service_unix.go | 24 +++++++++++---------- service_upstart_linux.go | 34 ++++++++++++++++-------------- servicetest_unix_test.go | 12 +++++------ version.go | 8 +++---- 20 files changed, 272 insertions(+), 199 deletions(-) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..6028d40f --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,30 @@ +linters: + # Enable all available linters. + # Default: false + enable-all: true + # Disable specific linter + # https://golangci-lint.run/usage/linters/#disabled-by-default + disable: + - copyloopvar # we use a too old go version + - intrange # we use a too old go version + - execinquery # deprecated + - exportloopref # deprecated + # - depguard + # - gci + # - godox + # - gofumpt + - gomnd + - wsl + - wrapcheck # old code => no wrapped error + - varnamelen + - paralleltest + - ireturn + - mnd + - testpackage + - err113 # old code => no wrapped error + - stylecheck + - cyclop + # - revive + - nlreturn + - exhaustruct + diff --git a/console.go b/console.go index ff033753..c752ffbd 100644 --- a/console.go +++ b/console.go @@ -10,13 +10,13 @@ import ( ) // ConsoleLogger logs to the std err. -var ConsoleLogger = consoleLogger{} +var ConsoleLogger = consoleLogger{} //nolint:gochecknoglobals type consoleLogger struct { info, warn, err *log.Logger } -func init() { +func init() { //nolint:gochecknoinits ConsoleLogger.info = log.New(os.Stderr, "I: ", log.Ltime) ConsoleLogger.warn = log.New(os.Stderr, "W: ", log.Ltime) ConsoleLogger.err = log.New(os.Stderr, "E: ", log.Ltime) @@ -26,22 +26,27 @@ func (c consoleLogger) Error(v ...interface{}) error { c.err.Print(v...) return nil } + func (c consoleLogger) Warning(v ...interface{}) error { c.warn.Print(v...) return nil } + func (c consoleLogger) Info(v ...interface{}) error { c.info.Print(v...) return nil } + func (c consoleLogger) Errorf(format string, a ...interface{}) error { c.err.Printf(format, a...) return nil } + func (c consoleLogger) Warningf(format string, a ...interface{}) error { c.warn.Printf(format, a...) return nil } + func (c consoleLogger) Infof(format string, a ...interface{}) error { c.info.Printf(format, a...) return nil diff --git a/example/logging/main.go b/example/logging/main.go index 976c7459..045488ac 100644 --- a/example/logging/main.go +++ b/example/logging/main.go @@ -10,10 +10,10 @@ import ( "log" "time" - "github.com/kardianos/service" + "github.com/kardianos/service" //nolint:depguard ) -var logger service.Logger +var logger service.Logger //nolint:gochecknoglobals // Program structures. // @@ -22,7 +22,8 @@ type program struct { exit chan struct{} } -func (p *program) Start(s service.Service) error { +//nolint:errcheck +func (p *program) Start(_ service.Service) error { if service.Interactive() { logger.Info("Running in terminal.") } else { @@ -34,6 +35,8 @@ func (p *program) Start(s service.Service) error { go p.run() return nil } + +//nolint:errcheck,unparam func (p *program) run() error { logger.Infof("I'm running %v.", service.Platform()) ticker := time.NewTicker(2 * time.Second) @@ -47,7 +50,9 @@ func (p *program) run() error { } } } -func (p *program) Stop(s service.Service) error { + +//nolint:errcheck +func (p *program) Stop(_ service.Service) error { // Any work in Stop should be quick, usually a few seconds at most. logger.Info("I'm Stopping!") close(p.exit) @@ -74,7 +79,8 @@ func main() { Description: "This is an example Go service that outputs log messages.", Dependencies: []string{ "Requires=network.target", - "After=network-online.target syslog.target"}, + "After=network-online.target syslog.target", + }, Option: options, } @@ -101,13 +107,16 @@ func main() { if len(*svcFlag) != 0 { err := service.Control(s, *svcFlag) if err != nil { - log.Printf("Valid actions: %q\n", service.ControlAction) + log.Printf("Valid actions: %q\n", []string{ + service.ControlActionStart, service.ControlActionStop, + service.ControlActionRestart, service.ControlActionInstall, service.ControlActionUninstall, + }) log.Fatal(err) } return } err = s.Run() if err != nil { - logger.Error(err) + _ = logger.Error(err) } } diff --git a/example/runner/runner.go b/example/runner/runner.go index 8729cf4e..c0600c7a 100644 --- a/example/runner/runner.go +++ b/example/runner/runner.go @@ -14,22 +14,25 @@ import ( "os/exec" "path/filepath" - "github.com/kardianos/service" + "github.com/kardianos/service" //nolint:depguard ) // Config is the runner app config structure. type Config struct { - Name, DisplayName, Description string + Name string `json:"name"` + DisplayName string `json:"displyName"` + Description string `json:"description"` - Dir string - Exec string - Args []string - Env []string + Dir string `json:"dir"` + Exec string `json:"exec"` + Args []string `json:"args"` + Env []string `json:"env"` - Stderr, Stdout string + Stderr string `json:"stderr"` + Stdout string `json:"stdout"` } -var logger service.Logger +var logger service.Logger //nolint:gochecknoglobals type program struct { exit chan struct{} @@ -40,12 +43,12 @@ type program struct { cmd *exec.Cmd } -func (p *program) Start(s service.Service) error { +func (p *program) Start(_ service.Service) error { // Look for exec. // Verify home directory. fullExec, err := exec.LookPath(p.Exec) if err != nil { - return fmt.Errorf("Failed to find executable %q: %v", p.Exec, err) + return fmt.Errorf("Failed to find executable %q: %w", p.Exec, err) } p.cmd = exec.Command(fullExec, p.Args...) @@ -55,6 +58,8 @@ func (p *program) Start(s service.Service) error { go p.run() return nil } + +//nolint:errcheck func (p *program) run() { logger.Info("Starting ", p.DisplayName) defer func() { @@ -66,16 +71,16 @@ func (p *program) run() { }() if p.Stderr != "" { - f, err := os.OpenFile(p.Stderr, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777) + f, err := os.OpenFile(p.Stderr, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o777) if err != nil { - logger.Warningf("Failed to open std err %q: %v", p.Stderr, err) + logger.Warningf("Failed to open std err %q: %w", p.Stderr, err) return } defer f.Close() p.cmd.Stderr = f } if p.Stdout != "" { - f, err := os.OpenFile(p.Stdout, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777) + f, err := os.OpenFile(p.Stdout, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o777) if err != nil { logger.Warningf("Failed to open std out %q: %v", p.Stdout, err) return @@ -88,10 +93,10 @@ func (p *program) run() { if err != nil { logger.Warningf("Error running: %v", err) } - - return } -func (p *program) Stop(s service.Service) error { + +//nolint:errcheck +func (p *program) Stop(_ service.Service) error { close(p.exit) logger.Info("Stopping ", p.DisplayName) if p.cmd.Process != nil { @@ -181,13 +186,16 @@ func main() { if len(*svcFlag) != 0 { err := service.Control(s, *svcFlag) if err != nil { - log.Printf("Valid actions: %q\n", service.ControlAction) + log.Printf("Valid actions: %q\n", []string{ + service.ControlActionStart, service.ControlActionStop, + service.ControlActionRestart, service.ControlActionInstall, service.ControlActionUninstall, + }) log.Fatal(err) } return } err = s.Run() if err != nil { - logger.Error(err) + _ = logger.Error(err) } } diff --git a/example/simple/main.go b/example/simple/main.go index 2ec9f462..aee51940 100644 --- a/example/simple/main.go +++ b/example/simple/main.go @@ -8,22 +8,24 @@ package main import ( "log" - "github.com/kardianos/service" + "github.com/kardianos/service" //nolint:depguard ) -var logger service.Logger +var logger service.Logger //nolint:gochecknoglobals type program struct{} -func (p *program) Start(s service.Service) error { +func (p *program) Start(_ service.Service) error { // Start should not block. Do the actual work async. go p.run() return nil } + func (p *program) run() { // Do work here } -func (p *program) Stop(s service.Service) error { + +func (p *program) Stop(_ service.Service) error { // Stop should not block. Return with a few seconds. return nil } @@ -46,6 +48,6 @@ func main() { } err = s.Run() if err != nil { - logger.Error(err) + _ = logger.Error(err) } } diff --git a/example/stopPause/main.go b/example/stopPause/main.go index ec7d598e..bdd35eef 100644 --- a/example/stopPause/main.go +++ b/example/stopPause/main.go @@ -10,22 +10,24 @@ import ( "os" "time" - "github.com/kardianos/service" + "github.com/kardianos/service" //nolint:depguard ) -var logger service.Logger +var logger service.Logger //nolint:gochecknoglobals type program struct{} -func (p *program) Start(s service.Service) error { +func (p *program) Start(_ service.Service) error { // Start should not block. Do the actual work async. go p.run() return nil } + func (p *program) run() { // Do work here } -func (p *program) Stop(s service.Service) error { + +func (p *program) Stop(_ service.Service) error { // Stop should not block. Return with a few seconds. <-time.After(time.Second * 13) return nil @@ -57,6 +59,6 @@ func main() { } err = s.Run() if err != nil { - logger.Error(err) + _ = logger.Error(err) } } diff --git a/service.go b/service.go index 130fc22d..6eeeaad4 100644 --- a/service.go +++ b/service.go @@ -99,10 +99,10 @@ const ( optionLogDirectory = "LogDirectory" ) -// Status represents service status as an byte value +// Status represents service status as an byte value. type Status byte -// Status of service represented as an byte +// Status of service represented as an byte. const ( StatusUnknown Status = iota // Status is unable to be determined due to an error or it was not installed. StatusRunning @@ -141,6 +141,7 @@ type Config struct { EnvVars map[string]string } +//nolint:gochecknoglobals var ( system System systemRegistry []System @@ -148,9 +149,9 @@ var ( var ( // ErrNameFieldRequired is returned when Config.Name is empty. - ErrNameFieldRequired = errors.New("Config.Name field is required.") + ErrNameFieldRequired = errors.New("Config.Name field is required.") //nolint:revive // ErrNoServiceSystemDetected is returned when no system was detected. - ErrNoServiceSystemDetected = errors.New("No service system detected.") + ErrNoServiceSystemDetected = errors.New("No service system detected.") //nolint:revive // ErrNotInstalled is returned when the service is not installed. ErrNotInstalled = errors.New("the service is not installed") ) @@ -231,6 +232,8 @@ 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. +// +//nolint:lll type KeyValue map[string]interface{} // bool returns the value of the given name, assuming the value is a boolean. @@ -268,7 +271,7 @@ func (kv KeyValue) string(name string, defaultValue string) string { // float64 returns the value of the given name, assuming the value is a float64. // If the value isn't found or is not of the type, the defaultValue is returned. -func (kv KeyValue) float64(name string, defaultValue float64) float64 { +func (kv KeyValue) float64(name string, defaultValue float64) float64 { //nolint:unused if v, found := kv[name]; found { if castValue, is := v.(float64); is { return castValue @@ -307,7 +310,7 @@ func Interactive() bool { func newSystem() System { for _, choice := range systemRegistry { - if choice.Detect() == false { + if !choice.Detect() { continue } return choice @@ -388,7 +391,7 @@ type Shutdowner interface { // TODO: Add Configure to Service interface. // Service represents a service that can be run or controlled. -type Service interface { +type Service interface { //nolint:interfacebloat // Run should be called shortly after the program entry point. // After Interface.Stop has finished running, Run will stop blocking. // After Run stops blocking, the program must exit shortly after. @@ -434,27 +437,33 @@ type Service interface { } // ControlAction list valid string texts to use in Control. -var ControlAction = [5]string{"start", "stop", "restart", "install", "uninstall"} +const ( + ControlActionStart = "start" + ControlActionStop = "stop" + ControlActionRestart = "restart" + ControlActionInstall = "install" + ControlActionUninstall = "uninstall" +) // Control issues control functions to the service from a given action string. func Control(s Service, action string) error { var err error switch action { - case ControlAction[0]: + case ControlActionStart: err = s.Start() - case ControlAction[1]: + case ControlActionStop: err = s.Stop() - case ControlAction[2]: + case ControlActionRestart: err = s.Restart() - case ControlAction[3]: + case ControlActionInstall: err = s.Install() - case ControlAction[4]: + case ControlActionUninstall: err = s.Uninstall() default: err = fmt.Errorf("Unknown action %s", action) } if err != nil { - return fmt.Errorf("Failed to %s %v: %v", action, s, err) + return fmt.Errorf("Failed to %s %v: %w", action, s, err) } return nil } diff --git a/service_aix.go b/service_aix.go index 2563b753..857716d5 100644 --- a/service_aix.go +++ b/service_aix.go @@ -112,9 +112,8 @@ func (s *aixService) template() *template.Template { } } -func (s *aixService) configPath() (cp string, err error) { - cp = "/etc/rc.d/init.d/" + s.Config.Name - return +func (s *aixService) configPath() (string, error) { + return "/etc/rc.d/init.d/" + s.Config.Name, nil } func (s *aixService) Install() error { diff --git a/service_freebsd.go b/service_freebsd.go index 752f5feb..a4ee0086 100644 --- a/service_freebsd.go +++ b/service_freebsd.go @@ -89,13 +89,12 @@ func (s *freebsdService) template() *template.Template { } } -func (s *freebsdService) configPath() (cp string, err error) { +func (s *freebsdService) configPath() (string, error) { if oserr := os.MkdirAll(configDir, 0755); oserr != nil { - err = oserr - return + return "", oserr } - cp = filepath.Join(configDir, s.Config.Name) - return + + return filepath.Join(configDir, s.Config.Name), nil } func (s *freebsdService) Install() error { diff --git a/service_linux.go b/service_linux.go index 76d29e1a..a3116fc5 100644 --- a/service_linux.go +++ b/service_linux.go @@ -8,14 +8,15 @@ import ( "bufio" "errors" "fmt" - "io/ioutil" "os" "strings" ) -var cgroupFile = "/proc/1/cgroup" -var mountInfoFile = "/proc/self/mountinfo" -var dockerEnvFile = "/.dockerenv" +var ( + cgroupFile = "/proc/1/cgroup" //nolint:gochecknoglobals + mountInfoFile = "/proc/self/mountinfo" //nolint:gochecknoglobals + dockerEnvFile = "/.dockerenv" //nolint:gochecknoglobals +) type linuxSystemService struct { name string @@ -27,17 +28,20 @@ type linuxSystemService struct { func (sc linuxSystemService) String() string { return sc.name } + func (sc linuxSystemService) Detect() bool { return sc.detect() } + func (sc linuxSystemService) Interactive() bool { return sc.interactive() } + func (sc linuxSystemService) New(i Interface, c *Config) (Service, error) { return sc.new(i, sc.String(), c) } -func init() { +func init() { //nolint:gochecknoinits ChooseSystem(linuxSystemService{ name: "linux-systemd", detect: isSystemd, @@ -88,7 +92,7 @@ func init() { func binaryName(pid int) (string, error) { statPath := fmt.Sprintf("/proc/%d/stat", pid) - dataBytes, err := ioutil.ReadFile(statPath) + dataBytes, err := os.ReadFile(statPath) if err != nil { return "", err } @@ -200,11 +204,13 @@ 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) - }, +func getTemplateFunctions() map[string]interface{} { + return map[string]interface{}{ + "cmd": func(s string) string { + return `"` + strings.ReplaceAll(s, `"`, `\"`) + `"` + }, + "cmdEscape": func(s string) string { + return strings.ReplaceAll(s, " ", `\x20`) + }, + } } diff --git a/service_linux_test.go b/service_linux_test.go index ab3dd6c9..419bc845 100644 --- a/service_linux_test.go +++ b/service_linux_test.go @@ -6,29 +6,28 @@ package service import ( "errors" - "io/ioutil" "os" "testing" ) -// createTestCgroupFiles creates mock files for tests +// createTestCgroupFiles creates mock files for tests. func createTestCgroupFiles() (*os.File, *os.File, error) { // docker cgroup setup - hDockerGrp, err := ioutil.TempFile("", "*") + hDockerGrp, err := os.CreateTemp("", "*") if err != nil { return nil, nil, errors.New("docker tempfile create failed") } - _, err = hDockerGrp.Write([]byte(dockerCgroup)) + _, err = hDockerGrp.WriteString(dockerCgroup) if err != nil { return nil, nil, errors.New("docker tempfile write failed") } // linux cgroup setup - hLinuxGrp, err := ioutil.TempFile("", "*") + hLinuxGrp, err := os.CreateTemp("", "*") if err != nil { return nil, nil, errors.New("\"normal\" tempfile create failed") } - _, err = hLinuxGrp.Write([]byte(linuxCgroup)) + _, err = hLinuxGrp.WriteString(linuxCgroup) if err != nil { return nil, nil, errors.New("\"normal\" tempfile write failed") } @@ -36,14 +35,14 @@ func createTestCgroupFiles() (*os.File, *os.File, error) { return hDockerGrp, hLinuxGrp, nil } -// createTestMountInfoFiles creates mock files for tests +// createTestMountInfoFiles creates mock files for tests. func createTestMountInfoFiles() (*os.File, *os.File, error) { // docker cgroup setup hDockerGrp, err := os.CreateTemp("", "*") if err != nil { return nil, nil, errors.New("docker tempfile create failed") } - _, err = hDockerGrp.Write([]byte(dockerMountInfo)) + _, err = hDockerGrp.WriteString(dockerMountInfo) if err != nil { return nil, nil, errors.New("docker tempfile write failed") } @@ -53,7 +52,7 @@ func createTestMountInfoFiles() (*os.File, *os.File, error) { if err != nil { return nil, nil, errors.New("\"normal\" tempfile create failed") } - _, err = hLinuxGrp.Write([]byte(linuxMountInfo)) + _, err = hLinuxGrp.WriteString(linuxMountInfo) if err != nil { return nil, nil, errors.New("\"normal\" tempfile write failed") } @@ -61,14 +60,13 @@ func createTestMountInfoFiles() (*os.File, *os.File, error) { return hDockerGrp, hLinuxGrp, nil } -// removeTestFile closes and removes the provided file +// removeTestFile closes and removes the provided file. func removeTestFile(hFile *os.File) { hFile.Close() os.Remove(hFile.Name()) } -func Test_isInContainerCGroup(t *testing.T) { - +func Test_isInContainerCGroup(t *testing.T) { //nolint:dupl // setup hDockerGrp, hLinuxGrp, err := createTestCgroupFiles() if err != nil { @@ -106,8 +104,8 @@ func Test_isInContainerCGroup(t *testing.T) { }) } } -func Test_isInContainerMountInfo(t *testing.T) { +func Test_isInContainerMountInfo(t *testing.T) { //nolint:dupl // setup hDockerGrp, hLinuxGrp, err := createTestMountInfoFiles() if err != nil { @@ -147,7 +145,6 @@ func Test_isInContainerMountInfo(t *testing.T) { } func Test_isInContainerDockerEnv(t *testing.T) { - // TEST type args struct { filePath string @@ -176,7 +173,6 @@ func Test_isInContainerDockerEnv(t *testing.T) { } func Test_isInteractive(t *testing.T) { - // setup hDockerGrp, hLinuxGrp, err := createTestCgroupFiles() if err != nil { @@ -199,7 +195,8 @@ func Test_isInteractive(t *testing.T) { want bool wantErr bool }{ - {"docker", + { + "docker", func() { strStack <- cgroupFile cgroupFile = hDockerGrp.Name() @@ -209,7 +206,8 @@ func Test_isInteractive(t *testing.T) { }, true, false, }, - {"linux", + { + "linux", func() { strStack <- cgroupFile cgroupFile = hLinuxGrp.Name() @@ -264,6 +262,7 @@ const ( 1:name=systemd:/init.scope 0::/init.scope` + //nolint:lll,dupword dockerMountInfo = `3860 3859 0:159 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 3861 3857 0:160 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro 3862 3861 0:29 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw @@ -277,6 +276,7 @@ const ( 3777 3858 0:157 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw 3778 3858 0:157 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw` + //nolint:lll,dupword linuxMountInfo = `183 28 0:44 / /run/credentials/systemd-tmpfiles-setup.service ro,nosuid,nodev,noexec,relatime,nosymfollow shared:103 - tmpfs tmpfs rw,size=1024k,nr_inodes=1024,mode=700,inode64,noswap 129 36 0:45 / /proc/sys/fs/binfmt_misc rw,nosuid,nodev,noexec,relatime shared:105 - binfmt_misc binfmt_misc rw 407 28 0:48 / /run/credentials/systemd-resolved.service ro,nosuid,nodev,noexec,relatime,nosymfollow shared:107 - tmpfs tmpfs rw,size=1024k,nr_inodes=1024,mode=700,inode64,noswap diff --git a/service_openrc_linux.go b/service_openrc_linux.go index c678e3ae..7005f40a 100644 --- a/service_openrc_linux.go +++ b/service_openrc_linux.go @@ -25,15 +25,13 @@ func isOpenRC() bool { defer filerc.Close() buf := new(bytes.Buffer) - buf.ReadFrom(filerc) + _, _ = buf.ReadFrom(filerc) contents := buf.String() re := regexp.MustCompile(`::sysinit:.*openrc.*sysinit`) matches := re.FindStringSubmatch(contents) - if len(matches) > 0 { - return true - } - return false + + return len(matches) > 0 } return false } @@ -59,9 +57,9 @@ func (s *openrc) template() *template.Template { customScript := s.Option.string(optionOpenRCScript, "") if customScript != "" { - return template.Must(template.New("").Funcs(tf).Parse(customScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(customScript)) } - return template.Must(template.New("").Funcs(tf).Parse(openRCScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(openRCScript)) } func newOpenRCService(i Interface, platform string, c *Config) (Service, error) { @@ -75,13 +73,12 @@ func newOpenRCService(i Interface, platform string, c *Config) (Service, error) var errNoUserServiceOpenRC = errors.New("user services are not supported on OpenRC") -func (s *openrc) configPath() (cp string, err error) { +func (s *openrc) configPath() (string, error) { if s.Option.bool(optionUserService, optionUserServiceDefault) { - err = errNoUserServiceOpenRC - return + return "", errNoUserServiceOpenRC } - cp = "/etc/init.d/" + s.Config.Name - return + + return "/etc/init.d/" + s.Config.Name, nil } func (s *openrc) Install() error { @@ -100,7 +97,7 @@ func (s *openrc) Install() error { } defer f.Close() - err = os.Chmod(confPath, 0755) + err = os.Chmod(confPath, 0o755) if err != nil { return err } @@ -110,7 +107,7 @@ func (s *openrc) Install() error { return err } - var to = &struct { + to := &struct { *Config Path string LogDirectory string @@ -150,14 +147,14 @@ func (s *openrc) SystemLogger(errs chan<- error) (Logger, error) { return newSysLogger(s.Name, errs) } -func (s *openrc) Run() (err error) { - err = s.i.Start(s) +func (s *openrc) Run() error { + err := s.i.Start(s) if err != nil { return err } s.Option.funcSingle(optionRunWait, func() { - var sigChan = make(chan os.Signal, 3) + sigChan := make(chan os.Signal, 3) signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) <-sigChan })() @@ -185,7 +182,7 @@ func (s *openrc) Status() (Status, error) { case exitCode == 3: return StatusStopped, nil default: - return StatusUnknown, fmt.Errorf("unknown error: %v - %v", out, err) + return StatusUnknown, fmt.Errorf("unknown error: %v - %w", out, err) } } else { return StatusUnknown, err @@ -236,7 +233,7 @@ export {{$k}}={{$v}} {{- if .Dependencies }} depend() { -{{- range $i, $dep := .Dependencies}} +{{- range $i, $dep := .Dependencies}} {{"\t"}}{{$dep}}{{end}} } {{- end}} diff --git a/service_rcs_linux.go b/service_rcs_linux.go index 0fca97dc..4354ce80 100644 --- a/service_rcs_linux.go +++ b/service_rcs_linux.go @@ -39,15 +39,13 @@ func isRCS() bool { defer filerc.Close() buf := new(bytes.Buffer) - buf.ReadFrom(filerc) + _, _ = buf.ReadFrom(filerc) contents := buf.String() re := regexp.MustCompile(`::sysinit:.*rcS`) matches := re.FindStringSubmatch(contents) - if len(matches) > 0 { - return true - } - return false + + return len(matches) > 0 } return false } @@ -73,25 +71,24 @@ func (s *rcs) Platform() string { return s.platform } -// todo -var errNoUserServiceRCS = errors.New("User services are not supported on rcS.") +// todo. +var errNoUserServiceRCS = errors.New("User services are not supported on rcS.") //nolint:revive -func (s *rcs) configPath() (cp string, err error) { +func (s *rcs) configPath() (string, error) { if s.Option.bool(optionUserService, optionUserServiceDefault) { - err = errNoUserServiceRCS - return + return "", errNoUserServiceRCS } - cp = "/etc/init.d/" + s.Config.Name - return + + return "/etc/init.d/" + s.Config.Name, nil } func (s *rcs) template() *template.Template { customScript := s.Option.string(optionRCSScript, "") if customScript != "" { - return template.Must(template.New("").Funcs(tf).Parse(customScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(customScript)) } - return template.Must(template.New("").Funcs(tf).Parse(rcsScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(rcsScript)) } func (s *rcs) Install() error { @@ -115,7 +112,7 @@ func (s *rcs) Install() error { return err } - var to = &struct { + to := &struct { *Config Path string LogDirectory string @@ -130,7 +127,7 @@ func (s *rcs) Install() error { return err } - if err = os.Chmod(confPath, 0755); err != nil { + if err = os.Chmod(confPath, 0o755); err != nil { return err } @@ -161,18 +158,19 @@ func (s *rcs) Logger(errs chan<- error) (Logger, error) { } return s.SystemLogger(errs) } + func (s *rcs) SystemLogger(errs chan<- error) (Logger, error) { return newSysLogger(s.Name, errs) } -func (s *rcs) Run() (err error) { - err = s.i.Start(s) +func (s *rcs) Run() error { + err := s.i.Start(s) if err != nil { return err } s.Option.funcSingle(optionRunWait, func() { - var sigChan = make(chan os.Signal, 3) + sigChan := make(chan os.Signal, 3) signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) <-sigChan })() @@ -213,6 +211,7 @@ func (s *rcs) Restart() error { return s.Start() } +//nolint:dupword const rcsScript = `#!/bin/sh # For RedHat and cousins: # chkconfig: - 99 01 diff --git a/service_systemd_linux.go b/service_systemd_linux.go index e9fb4d65..a7e3944b 100644 --- a/service_systemd_linux.go +++ b/service_systemd_linux.go @@ -34,7 +34,7 @@ func isSystemd() bool { defer filerc.Close() buf := new(bytes.Buffer) - buf.ReadFrom(filerc) + _, _ = buf.ReadFrom(filerc) contents := buf.String() if strings.Trim(contents, " \r\n") == "systemd" { @@ -71,22 +71,21 @@ func (s *systemd) Platform() string { return s.platform } -func (s *systemd) configPath() (cp string, err error) { +func (s *systemd) configPath() (string, error) { if !s.isUserService() { - cp = "/etc/systemd/system/" + s.unitName() - return + return "/etc/systemd/system/" + s.unitName(), nil } homeDir, err := os.UserHomeDir() if err != nil { - return + return "", err } systemdUserDir := filepath.Join(homeDir, ".config/systemd/user") err = os.MkdirAll(systemdUserDir, os.ModePerm) if err != nil { - return + return "", err } - cp = filepath.Join(systemdUserDir, s.unitName()) - return + + return filepath.Join(systemdUserDir, s.unitName()), nil } func (s *systemd) unitName() string { @@ -131,9 +130,9 @@ func (s *systemd) template() *template.Template { customScript := s.Option.string(optionSystemdScript, "") if customScript != "" { - return template.Must(template.New("").Funcs(tf).Parse(customScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(customScript)) } - return template.Must(template.New("").Funcs(tf).Parse(systemdScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(systemdScript)) } func (s *systemd) isUserService() bool { @@ -150,7 +149,7 @@ func (s *systemd) Install() error { return fmt.Errorf("Init already exists: %s", confPath) } - f, err := os.OpenFile(confPath, os.O_WRONLY|os.O_CREATE, 0644) + f, err := os.OpenFile(confPath, os.O_WRONLY|os.O_CREATE, 0o644) if err != nil { return err } @@ -161,7 +160,7 @@ func (s *systemd) Install() error { return err } - var to = &struct { + to := &struct { *Config Path string HasOutputFileSupport bool @@ -219,18 +218,19 @@ func (s *systemd) Logger(errs chan<- error) (Logger, error) { } return s.SystemLogger(errs) } + func (s *systemd) SystemLogger(errs chan<- error) (Logger, error) { return newSysLogger(s.Name, errs) } -func (s *systemd) Run() (err error) { - err = s.i.Start(s) +func (s *systemd) Run() error { + err := s.i.Start(s) if err != nil { return err } s.Option.funcSingle(optionRunWait, func() { - var sigChan = make(chan os.Signal, 3) + sigChan := make(chan os.Signal, 3) signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) <-sigChan })() @@ -301,7 +301,7 @@ func (s *systemd) runAction(action string) error { const systemdScript = `[Unit] Description={{.Description}} ConditionFileIsExecutable={{.Path|cmdEscape}} -{{range $i, $dep := .Dependencies}} +{{range $i, $dep := .Dependencies}} {{$dep}} {{end}} [Service] diff --git a/service_sysv_linux.go b/service_sysv_linux.go index 5a98a514..41aa8d71 100644 --- a/service_sysv_linux.go +++ b/service_sysv_linux.go @@ -42,24 +42,23 @@ func (s *sysv) Platform() string { return s.platform } -var errNoUserServiceSystemV = errors.New("User services are not supported on SystemV.") +var errNoUserServiceSystemV = errors.New("User services are not supported on SystemV.") //nolint:revive -func (s *sysv) configPath() (cp string, err error) { +func (s *sysv) configPath() (string, error) { if s.Option.bool(optionUserService, optionUserServiceDefault) { - err = errNoUserServiceSystemV - return + return "", errNoUserServiceSystemV } - cp = "/etc/init.d/" + s.Config.Name - return + + return "/etc/init.d/" + s.Config.Name, nil } func (s *sysv) template() *template.Template { customScript := s.Option.string(optionSysvScript, "") if customScript != "" { - return template.Must(template.New("").Funcs(tf).Parse(customScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(customScript)) } - return template.Must(template.New("").Funcs(tf).Parse(sysvScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(sysvScript)) } func (s *sysv) Install() error { @@ -83,7 +82,7 @@ func (s *sysv) Install() error { return err } - var to = &struct { + to := &struct { *Config Path string LogDirectory string @@ -98,7 +97,7 @@ func (s *sysv) Install() error { return err } - if err = os.Chmod(confPath, 0755); err != nil { + if err = os.Chmod(confPath, 0o755); err != nil { return err } for _, i := range [...]string{"2", "3", "4", "5"} { @@ -132,18 +131,19 @@ func (s *sysv) Logger(errs chan<- error) (Logger, error) { } return s.SystemLogger(errs) } + func (s *sysv) SystemLogger(errs chan<- error) (Logger, error) { return newSysLogger(s.Name, errs) } -func (s *sysv) Run() (err error) { - err = s.i.Start(s) +func (s *sysv) Run() error { + err := s.i.Start(s) if err != nil { return err } s.Option.funcSingle(optionRunWait, func() { - var sigChan = make(chan os.Signal, 3) + sigChan := make(chan os.Signal, 3) signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) <-sigChan })() @@ -184,6 +184,7 @@ func (s *sysv) Restart() error { return s.Start() } +//nolint:dupword const sysvScript = `#!/bin/sh # For RedHat and cousins: # chkconfig: - 99 01 diff --git a/service_test.go b/service_test.go index 886b0cfb..f7dcebfd 100644 --- a/service_test.go +++ b/service_test.go @@ -5,11 +5,12 @@ package service_test import ( + "log" "os" "testing" "time" - "github.com/kardianos/service" + "github.com/kardianos/service" //nolint:depguard ) func TestRunInterrupt(t *testing.T) { @@ -24,7 +25,7 @@ func TestRunInterrupt(t *testing.T) { go func() { <-time.After(1 * time.Second) - interruptProcess(t) + interruptProcess() }() go func() { @@ -32,7 +33,7 @@ func TestRunInterrupt(t *testing.T) { <-time.After(200 * time.Millisecond) } if p.numStopped == 0 { - t.Fatal("Run() hasn't been stopped") + log.Fatal("Run() hasn't been stopped") } }() @@ -43,7 +44,7 @@ func TestRunInterrupt(t *testing.T) { const testInstallEnv = "TEST_USER_INSTALL" -// Should always run, without asking for any permission +// Should always run, without asking for any permission. func TestUserRunInterrupt(t *testing.T) { if os.Getenv(testInstallEnv) != "1" { t.Skipf("env %q is not set to 1", testInstallEnv) @@ -73,14 +74,16 @@ type program struct { numStopped int } -func (p *program) Start(s service.Service) error { +func (p *program) Start(_ service.Service) error { go p.run() return nil } + func (p *program) run() { // Do work here } -func (p *program) Stop(s service.Service) error { + +func (p *program) Stop(_ service.Service) error { p.numStopped++ return nil } diff --git a/service_unix.go b/service_unix.go index 96582532..8e211ac4 100644 --- a/service_unix.go +++ b/service_unix.go @@ -11,7 +11,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "log/syslog" "os/exec" "syscall" @@ -42,18 +41,23 @@ func (s sysLogger) send(err error) error { func (s sysLogger) Error(v ...interface{}) error { return s.send(s.Writer.Err(fmt.Sprint(v...))) } + func (s sysLogger) Warning(v ...interface{}) error { return s.send(s.Writer.Warning(fmt.Sprint(v...))) } + func (s sysLogger) Info(v ...interface{}) error { return s.send(s.Writer.Info(fmt.Sprint(v...))) } + func (s sysLogger) Errorf(format string, a ...interface{}) error { return s.send(s.Writer.Err(fmt.Sprintf(format, a...))) } + func (s sysLogger) Warningf(format string, a ...interface{}) error { return s.send(s.Writer.Warning(fmt.Sprintf(format, a...))) } + func (s sysLogger) Infof(format string, a ...interface{}) error { return s.send(s.Writer.Info(fmt.Sprintf(format, a...))) } @@ -77,41 +81,39 @@ func runCommand(command string, readStdout bool, arguments ...string) (int, stri if readStdout { // Connect pipe to read Stdout stdout, err = cmd.StdoutPipe() - if err != nil { // Failed to connect pipe - return 0, "", fmt.Errorf("%q failed to connect stdout pipe: %v", command, err) + return 0, "", fmt.Errorf("%q failed to connect stdout pipe: %w", command, err) } } // Connect pipe to read Stderr stderr, err := cmd.StderrPipe() - if err != nil { // Failed to connect pipe - return 0, "", fmt.Errorf("%q failed to connect stderr pipe: %v", command, err) + return 0, "", fmt.Errorf("%q failed to connect stderr pipe: %w", command, err) } // Do not use cmd.Run() if err := cmd.Start(); err != nil { // Problem while copying stdin, stdout, or stderr - return 0, "", fmt.Errorf("%q failed: %v", command, err) + return 0, "", fmt.Errorf("%q failed: %w", command, err) } // Zero exit status // Darwin: launchctl can fail with a zero exit status, - // so check for emtpy stderr + // so check for empty stderr if command == "launchctl" { - slurp, _ := ioutil.ReadAll(stderr) + slurp, _ := io.ReadAll(stderr) if len(slurp) > 0 && !bytes.HasSuffix(slurp, []byte("Operation now in progress\n")) { return 0, "", fmt.Errorf("%q failed with stderr: %s", command, slurp) } } if readStdout { - out, err := ioutil.ReadAll(stdout) + out, err := io.ReadAll(stdout) if err != nil { - return 0, "", fmt.Errorf("%q failed while attempting to read stdout: %v", command, err) + return 0, "", fmt.Errorf("%q failed while attempting to read stdout: %w", command, err) } else if len(out) > 0 { output = string(out) } @@ -125,7 +127,7 @@ func runCommand(command string, readStdout bool, arguments ...string) (int, stri } // An error occurred and there is no exit status. - return 0, output, fmt.Errorf("%q failed: %v", command, err) + return 0, output, fmt.Errorf("%q failed: %w", command, err) } return 0, output, nil diff --git a/service_upstart_linux.go b/service_upstart_linux.go index 42b947cb..98a54cb8 100644 --- a/service_upstart_linux.go +++ b/service_upstart_linux.go @@ -59,15 +59,14 @@ func (s *upstart) Platform() string { // Upstart has some support for user services in graphical sessions. // Due to the mix of actual support for user services over versions, just don't bother. // Upstart will be replaced by systemd in most cases anyway. -var errNoUserServiceUpstart = errors.New("User services are not supported on Upstart.") +var errNoUserServiceUpstart = errors.New("User services are not supported on Upstart.") //nolint:revive -func (s *upstart) configPath() (cp string, err error) { +func (s *upstart) configPath() (string, error) { if s.Option.bool(optionUserService, optionUserServiceDefault) { - err = errNoUserServiceUpstart - return + return "", errNoUserServiceUpstart } - cp = "/etc/init/" + s.Config.Name + ".conf" - return + + return "/etc/init/" + s.Config.Name + ".conf", nil } func (s *upstart) hasKillStanza() bool { @@ -119,10 +118,10 @@ func (s *upstart) template() *template.Template { customScript := s.Option.string(optionUpstartScript, "") if customScript != "" { - return template.Must(template.New("").Funcs(tf).Parse(customScript)) - } else { - return template.Must(template.New("").Funcs(tf).Parse(upstartScript)) + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(customScript)) } + + return template.Must(template.New("").Funcs(getTemplateFunctions()).Parse(upstartScript)) } func (s *upstart) Install() error { @@ -146,7 +145,7 @@ func (s *upstart) Install() error { return err } - var to = &struct { + to := &struct { *Config Path string HasKillStanza bool @@ -182,18 +181,19 @@ func (s *upstart) Logger(errs chan<- error) (Logger, error) { } return s.SystemLogger(errs) } + func (s *upstart) SystemLogger(errs chan<- error) (Logger, error) { return newSysLogger(s.Name, errs) } -func (s *upstart) Run() (err error) { - err = s.i.Start(s) +func (s *upstart) Run() error { + err := s.i.Start(s) if err != nil { return err } s.Option.funcSingle(optionRunWait, func() { - var sigChan = make(chan os.Signal, 3) + sigChan := make(chan os.Signal, 3) signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) <-sigChan })() @@ -208,9 +208,9 @@ func (s *upstart) Status() (Status, error) { } switch { - case strings.HasPrefix(out, fmt.Sprintf("%s start/running", s.Name)): + case strings.HasPrefix(out, s.Name+" start/running"): return StatusRunning, nil - case strings.HasPrefix(out, fmt.Sprintf("%s stop/waiting", s.Name)): + case strings.HasPrefix(out, s.Name+" stop/waiting"): return StatusStopped, nil default: return StatusUnknown, ErrNotInstalled @@ -231,6 +231,8 @@ func (s *upstart) Restart() error { // The upstart script should stop with an INT or the Go runtime will terminate // the program before the Stop handler can run. +// +//nolint:lll,dupword const upstartScript = `# {{.Description}} {{if .DisplayName}}description "{{.DisplayName}}"{{end}} @@ -259,7 +261,7 @@ script stdout_log="{{.LogDirectory}}/{{.Name}}.out" stderr_log="{{.LogDirectory}}/{{.Name}}.err" {{end}} - + if [ -f "/etc/sysconfig/{{.Name}}" ]; then set -a source /etc/sysconfig/{{.Name}} diff --git a/servicetest_unix_test.go b/servicetest_unix_test.go index c4b0b3de..24cb4ac7 100644 --- a/servicetest_unix_test.go +++ b/servicetest_unix_test.go @@ -2,23 +2,23 @@ // Use of this source code is governed by a zlib-style // license that can be found in the LICENSE file. -//go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +//go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris || aix || ppc64 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris aix ppc64 package service_test import ( + "log" "os" - "testing" ) -func interruptProcess(t *testing.T) { +func interruptProcess() { pid := os.Getpid() p, err := os.FindProcess(pid) if err != nil { - t.Fatalf("FindProcess: %s", err) + log.Fatalf("FindProcess: %s", err) } if err := p.Signal(os.Interrupt); err != nil { - t.Fatalf("Signal: %s", err) + log.Fatalf("Signal: %s", err) } } diff --git a/version.go b/version.go index a7a2f3a1..2994f0ff 100644 --- a/version.go +++ b/version.go @@ -6,9 +6,9 @@ import ( "strings" ) -// versionAtMost will return true if the provided version is less than or equal to max -func versionAtMost(version, max []int) (bool, error) { - if comp, err := versionCompare(version, max); err != nil { +// versionAtMost will return true if the provided version is less than or equal to max. +func versionAtMost(version, maxVersion []int) (bool, error) { + if comp, err := versionCompare(version, maxVersion); err != nil { return false, err } else if comp == 1 { return false, nil @@ -21,7 +21,7 @@ func versionAtMost(version, max []int) (bool, error) { // Return values are as follows // -1 - v1 is less than v2 // 0 - v1 is equal to v2 -// 1 - v1 is greater than v2 +// 1 - v1 is greater than v2. func versionCompare(v1, v2 []int) (int, error) { if len(v1) != len(v2) { return 0, errors.New("version length mismatch")