// Copyright 2024 Matthew Rich . All rights reserved. package resource import ( _ "context" "encoding/json" "fmt" "gopkg.in/yaml.v3" "io" "log/slog" _ "net/url" _ "os" "os/exec" "strings" "text/template" ) type CommandExecutor func(value any) ([]byte, error) type CommandExtractAttributes func(output []byte, target any) error type CommandArg string type Command struct { Path string `json:"path" yaml:"path"` Args []CommandArg `json:"args" yaml:"args"` Executor CommandExecutor `json:"-" yaml:"-"` Extractor CommandExtractAttributes `json:"-" yaml:"-"` } func NewCommand() *Command { c := &Command{} c.Executor = func(value any) ([]byte, error) { args, err := c.Template(value) if err != nil { return nil, err } cmd := exec.Command(c.Path, args...) stderr, pipeErr := cmd.StderrPipe() if pipeErr != nil { return nil, pipeErr } output, err := cmd.Output() stdErrOutput, _ := io.ReadAll(stderr) slog.Info("execute()", "path", c.Path, "args", args, "output", output, "error", stdErrOutput) return output, err } return c } func (c *Command) Load(r io.Reader) error { decoder := NewYAMLDecoder(r) return decoder.Decode(c) } func (c *Command) LoadDecl(yamlResourceDeclaration string) error { decoder := NewYAMLStringDecoder(yamlResourceDeclaration) return decoder.Decode(c) } func (c *Command) Template(value any) ([]string, error) { var args []string = make([]string, len(c.Args)) for i, arg := range c.Args { var commandLineArg strings.Builder err := template.Must(template.New(fmt.Sprintf("arg%d", i)).Parse(string(arg))).Execute(&commandLineArg, value) if err != nil { return nil, err } args[i] = commandLineArg.String() } return args, nil } func (c *Command) Execute(value any) ([]byte, error) { return c.Executor(value) } func (c *CommandArg) UnmarshalValue(value string) error { *c = CommandArg(value) return nil } func (c *CommandArg) UnmarshalJSON(data []byte) error { var s string if unmarshalRouteTypeErr := json.Unmarshal(data, &s); unmarshalRouteTypeErr != nil { return unmarshalRouteTypeErr } return c.UnmarshalValue(s) } func (c *CommandArg) UnmarshalYAML(value *yaml.Node) error { var s string if err := value.Decode(&s); err != nil { return err } return c.UnmarshalValue(s) }