2022-09-17 19:19:45 +00:00
|
|
|
// Package externalcmd allows to launch external commands.
|
2020-10-13 22:02:55 +00:00
|
|
|
package externalcmd
|
2020-09-19 15:49:44 +00:00
|
|
|
|
|
|
|
import (
|
2023-05-27 17:28:07 +00:00
|
|
|
"errors"
|
2022-01-25 13:55:50 +00:00
|
|
|
"strings"
|
2020-10-31 15:36:09 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-07-04 16:13:49 +00:00
|
|
|
restartPause = 5 * time.Second
|
2020-09-19 15:49:44 +00:00
|
|
|
)
|
|
|
|
|
2023-05-27 17:28:07 +00:00
|
|
|
var errTerminated = errors.New("terminated")
|
|
|
|
|
2020-11-21 12:35:33 +00:00
|
|
|
// Environment is a Cmd environment.
|
2021-12-08 19:50:09 +00:00
|
|
|
type Environment map[string]string
|
2020-11-01 16:33:06 +00:00
|
|
|
|
2020-11-21 12:35:33 +00:00
|
|
|
// Cmd is an external command.
|
|
|
|
type Cmd struct {
|
2021-12-21 11:39:32 +00:00
|
|
|
pool *Pool
|
2020-11-01 16:33:06 +00:00
|
|
|
cmdstr string
|
|
|
|
restart bool
|
|
|
|
env Environment
|
2023-05-27 17:28:07 +00:00
|
|
|
onExit func(error)
|
2020-10-31 15:36:09 +00:00
|
|
|
|
|
|
|
// in
|
|
|
|
terminate chan struct{}
|
|
|
|
}
|
|
|
|
|
2021-12-21 11:39:32 +00:00
|
|
|
// NewCmd allocates a Cmd.
|
|
|
|
func NewCmd(
|
|
|
|
pool *Pool,
|
2021-12-08 20:23:45 +00:00
|
|
|
cmdstr string,
|
|
|
|
restart bool,
|
|
|
|
env Environment,
|
2023-05-27 17:28:07 +00:00
|
|
|
onExit func(error),
|
2021-12-08 20:23:45 +00:00
|
|
|
) *Cmd {
|
2023-05-27 16:20:06 +00:00
|
|
|
// replace variables in both Linux and Windows, in order to allow using the
|
|
|
|
// same commands on both of them.
|
2022-01-25 13:55:50 +00:00
|
|
|
for key, val := range env {
|
|
|
|
cmdstr = strings.ReplaceAll(cmdstr, "$"+key, val)
|
|
|
|
}
|
|
|
|
|
2020-11-21 12:35:33 +00:00
|
|
|
e := &Cmd{
|
2021-12-21 11:39:32 +00:00
|
|
|
pool: pool,
|
2020-10-31 15:36:09 +00:00
|
|
|
cmdstr: cmdstr,
|
|
|
|
restart: restart,
|
2020-11-01 16:33:06 +00:00
|
|
|
env: env,
|
2021-12-08 20:23:45 +00:00
|
|
|
onExit: onExit,
|
2020-10-31 15:36:09 +00:00
|
|
|
terminate: make(chan struct{}),
|
|
|
|
}
|
|
|
|
|
2021-12-21 11:39:32 +00:00
|
|
|
pool.wg.Add(1)
|
|
|
|
|
2020-10-31 15:36:09 +00:00
|
|
|
go e.run()
|
2021-08-01 14:58:46 +00:00
|
|
|
|
2020-10-31 15:36:09 +00:00
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2021-12-21 11:39:32 +00:00
|
|
|
// Close closes the command. It doesn't wait for the command to exit.
|
2020-11-21 12:35:33 +00:00
|
|
|
func (e *Cmd) Close() {
|
2020-10-31 15:36:09 +00:00
|
|
|
close(e.terminate)
|
|
|
|
}
|
|
|
|
|
2020-11-21 12:35:33 +00:00
|
|
|
func (e *Cmd) run() {
|
2021-12-21 11:39:32 +00:00
|
|
|
defer e.pool.wg.Done()
|
2020-10-31 15:36:09 +00:00
|
|
|
|
|
|
|
for {
|
2023-05-27 17:28:07 +00:00
|
|
|
err := e.runOSSpecific()
|
|
|
|
if err == errTerminated {
|
|
|
|
return
|
2020-10-31 16:03:03 +00:00
|
|
|
}
|
2023-05-27 16:20:06 +00:00
|
|
|
|
2023-05-27 17:28:07 +00:00
|
|
|
e.onExit(err)
|
2023-05-27 16:20:06 +00:00
|
|
|
|
2023-05-27 17:28:07 +00:00
|
|
|
if !e.restart {
|
|
|
|
<-e.terminate
|
|
|
|
return
|
|
|
|
}
|
2023-05-27 16:20:06 +00:00
|
|
|
|
2023-05-27 17:28:07 +00:00
|
|
|
select {
|
|
|
|
case <-time.After(restartPause):
|
|
|
|
case <-e.terminate:
|
|
|
|
return
|
|
|
|
}
|
2023-05-27 16:20:06 +00:00
|
|
|
}
|
|
|
|
}
|