98 lines
2 KiB
Go
98 lines
2 KiB
Go
package gonf
|
|
|
|
import (
|
|
"bytes"
|
|
"log/slog"
|
|
"os/exec"
|
|
)
|
|
|
|
var commands []*CommandPromise
|
|
|
|
func init() {
|
|
commands = make([]*CommandPromise, 0)
|
|
}
|
|
|
|
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: DECLARED,
|
|
}
|
|
}
|
|
|
|
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 = append(c.chain, p...)
|
|
return c
|
|
}
|
|
|
|
func (c *CommandPromise) Promise() *CommandPromise {
|
|
if c.status == DECLARED {
|
|
c.status = PROMISED
|
|
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()
|
|
}
|
|
}
|
|
|
|
func (c CommandPromise) Status() Status {
|
|
return c.status
|
|
}
|
|
|
|
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
|
|
}
|