asdf/execute/execute.go
Trevor Brown 778ab34a6f feat(golang-rewrite): create RunCallback method for Plugin struct
* Create `plugins.New` function, updating existing code to use it
* Add another test for `hook.Run` function
* Enable `plugin_add_command.bats` tests for Go implementation of asdf
* Add `RunCallback` method to `Plugin` struct
* Update `plugins.Add` function to run `post-plugin-add` plugin callback script
* Handle Bash expression and scripts properly in `execute` package so `$@` is always set
2024-12-18 11:32:01 -05:00

75 lines
1.9 KiB
Go

// Package execute is a simple package that wraps the os/exec Command features
// for convenient use in asdf. It was inspired by
// https://github.com/chen-keinan/go-command-eval
package execute
import (
"fmt"
"io"
"os/exec"
"strings"
)
// Command represents a Bash command that can be executed by asdf
type Command struct {
Command string
Expression string
Args []string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
Env map[string]string
}
// New takes a string containing the path to a Bash script, and a slice of
// string arguments and returns a Command struct
func New(command string, args []string) Command {
return Command{Command: command, Args: args}
}
// NewExpression takes a string containing a Bash expression and a slice of
// string arguments and returns a Command struct
func NewExpression(expression string, args []string) Command {
return Command{Expression: expression, Args: args}
}
// Run executes a Command with Bash and returns the error if there is one
func (c Command) Run() error {
var command string
if c.Expression != "" {
// Expressions need to be invoked inside a Bash function, so variables like
// $0 and $@ are available
command = fmt.Sprintf("fn() { %s; }; fn %s", c.Expression, formatArgString(c.Args))
} else {
// Scripts can be invoked directly, with args provided
command = fmt.Sprintf("%s %s", c.Command, formatArgString(c.Args))
}
cmd := exec.Command("bash", "-c", command)
cmd.Env = mapToSlice(c.Env)
cmd.Stdin = c.Stdin
// Capture stdout and stderr
cmd.Stdout = c.Stdout
cmd.Stderr = c.Stderr
return cmd.Run()
}
func formatArgString(args []string) string {
var newArgs []string
for _, str := range args {
newArgs = append(newArgs, fmt.Sprintf("\"%s\"", str))
}
return strings.Join(newArgs, " ")
}
func mapToSlice(env map[string]string) (slice []string) {
for key, value := range env {
slice = append(slice, fmt.Sprintf("%s=%s", key, value))
}
return slice
}