diff options
Diffstat (limited to 'pkg/commands.go')
-rw-r--r-- | pkg/commands.go | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/pkg/commands.go b/pkg/commands.go new file mode 100644 index 0000000..b5a11ca --- /dev/null +++ b/pkg/commands.go @@ -0,0 +1,95 @@ +package gonf + +import ( + "bytes" + "log/slog" + "os/exec" +) + +// ----- Globals --------------------------------------------------------------- +var commands []*CommandPromise + +// ----- Init ------------------------------------------------------------------ +func init() { + commands = make([]*CommandPromise, 0) +} + +// ----- Public ---------------------------------------------------------------- +func Command(cmd string, args ...string) *CommandPromise { + return CommandWithEnv([]string{}, cmd, args...) +} + +func CommandWithEnv(env []string, cmd string, args ...string) *CommandPromise { + return &CommandPromise{ + args: args, + chain: nil, + cmd: cmd, + env: env, + err: nil, + Status: PROMISED, + } +} + +type CommandPromise struct { + args []string + chain []Promise + cmd string + env []string + err error + Status Status + Stdout bytes.Buffer + Stderr bytes.Buffer +} + +func (c *CommandPromise) IfRepaired(p ...Promise) Promise { + c.chain = p + return c +} + +func (c *CommandPromise) Promise() Promise { + commands = append(commands, c) + return c +} + +func (c *CommandPromise) Resolve() { + cmd := exec.Command(c.cmd, c.args...) + for _, e := range c.env { + cmd.Env = append(cmd.Environ(), e) + } + cmd.Stdout = &c.Stdout + cmd.Stderr = &c.Stderr + + if c.err = cmd.Run(); c.err != nil { + c.Status = BROKEN + slog.Error("command", "args", c.args, "cmd", c.cmd, "env", c.env, "err", c.err, "stdout", c.Stdout.String(), "stderr", c.Stderr.String(), "status", c.Status) + return + } + if c.Stdout.Len() == 0 && c.Stderr.Len() > 0 { + c.Status = BROKEN + slog.Error("command", "args", c.args, "cmd", c.cmd, "env", c.env, "stdout", c.Stdout.String(), "stderr", c.Stderr.String(), "status", c.Status) + return + } + c.Status = REPAIRED + slog.Info("command", "args", c.args, "cmd", c.cmd, "env", c.env, "stderr", c.Stderr.String(), "status", c.Status) + // TODO add a notion of repaired? + for _, p := range c.chain { + p.Resolve() + } +} + +// ----- Internal -------------------------------------------------------------- +func resolveCommands() (status Status) { + status = KEPT + for _, c := range commands { + if c.Status == PROMISED { + c.Resolve() + switch c.Status { + case BROKEN: + return BROKEN + case REPAIRED: + status = REPAIRED + } + } + } + return +} |