/
cmdrunner.go
84 lines (73 loc) · 2.8 KB
/
cmdrunner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package cmdrunner
import (
"os/exec"
)
// Use a singleton instance because there are many modules that may want access
// and having it all go through a shared object like the config or server would
// add a lot of complexity.
var commandRunner CommandRunner
// CommandRunner is an interface for executing commands.
// It gives the option to change the way commands are run server-wide.
type CommandRunner interface {
Command(string, ...string) *exec.Cmd
CombinedOutput(string, ...string) ([]byte, error)
}
// prependableCommandRunner is an implementation of CommandRunner.
// It gives the option for all commands that are run to be prepended by another command
// and arguments.
type prependableCommandRunner struct {
prependCmd string
prependArgs []string
}
// PrependCommandsWith updates the commandRunner singleton to have the configured prepended args and command.
func PrependCommandsWith(prependCmd string, prependArgs ...string) {
commandRunner = &prependableCommandRunner{
prependCmd: prependCmd,
prependArgs: prependArgs,
}
}
// CombinedOutput calls CombinedOutput on the defined commandRunner,
// or the default implementation in the exec package if there's no commandRunner defined.
func CombinedOutput(command string, args ...string) ([]byte, error) {
if commandRunner == nil {
return exec.Command(command, args...).CombinedOutput()
}
return commandRunner.CombinedOutput(command, args...)
}
// CombinedOutput returns the combined output of the command, given the prepended cmd/args that were defined.
func (c *prependableCommandRunner) CombinedOutput(command string, args ...string) ([]byte, error) {
return c.Command(command, args...).CombinedOutput()
}
// Command calls Command on the defined commandRunner,
// or the default implementation in the exec package if there's no commandRunner defined.
func Command(cmd string, args ...string) *exec.Cmd {
if commandRunner == nil {
return exec.Command(cmd, args...)
}
return commandRunner.Command(cmd, args...)
}
// Command creates an exec.Cmd object. If prependCmd is defined, the command will be prependCmd
// and the args will be prependArgs + cmd + args.
// Otherwise, cmd and args will be as inputted.
func (c *prependableCommandRunner) Command(cmd string, args ...string) *exec.Cmd {
realCmd := cmd
realArgs := args
if c.prependCmd != "" {
realCmd = c.prependCmd
realArgs = c.prependArgs
realArgs = append(realArgs, cmd)
realArgs = append(realArgs, args...)
}
return exec.Command(realCmd, realArgs...)
}
// GetPrependendCmd returns the prepended command if one is configured, else the empty string
func GetPrependedCmd() string {
if c, ok := commandRunner.(*prependableCommandRunner); ok {
return c.prependCmd
}
return ""
}
// ResetPrependedCmd resets the singleton for more reliable unit testing
func ResetPrependedCmd() {
commandRunner = nil
}