101 lines
1.8 KiB
Go
101 lines
1.8 KiB
Go
package builtins
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"ucl.lmika.dev/ucl"
|
|
)
|
|
|
|
type OSProvider interface {
|
|
LookupEnv(string) (string, bool)
|
|
Exec(ctx context.Context, cmd string, args ...string) (*exec.Cmd, error)
|
|
}
|
|
|
|
type osHandlers struct {
|
|
provider OSProvider
|
|
}
|
|
|
|
func OS() ucl.Module {
|
|
osh := osHandlers{
|
|
provider: builtinOSProvider{},
|
|
}
|
|
|
|
return ucl.Module{
|
|
Name: "os",
|
|
Builtins: map[string]ucl.BuiltinHandler{
|
|
"env": osh.env,
|
|
"exec": osh.exec,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (oh osHandlers) env(ctx context.Context, args ucl.CallArgs) (any, error) {
|
|
var envName string
|
|
if err := args.Bind(&envName); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
val, ok := oh.provider.LookupEnv(envName)
|
|
if ok {
|
|
return val, nil
|
|
}
|
|
|
|
var defValue any
|
|
if err := args.Bind(&defValue); err == nil {
|
|
return defValue, nil
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
func (oh osHandlers) exec(ctx context.Context, args ucl.CallArgs) (any, error) {
|
|
var cmdArgs []string
|
|
|
|
for args.NArgs() > 0 {
|
|
var s string
|
|
if err := args.Bind(&s); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cmdArgs = append(cmdArgs, s)
|
|
}
|
|
|
|
if len(cmdArgs) == 0 {
|
|
return nil, errors.New("expected command")
|
|
}
|
|
|
|
cmd, err := oh.provider.Exec(ctx, cmdArgs[0], cmdArgs[1:]...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if args.HasSwitch("in") {
|
|
var inVal string
|
|
if err := args.BindSwitch("in", &inVal); err != nil {
|
|
return nil, err
|
|
}
|
|
cmd.Stdin = strings.NewReader(inVal)
|
|
}
|
|
|
|
res, err := cmd.Output()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return string(res), nil
|
|
}
|
|
|
|
type builtinOSProvider struct{}
|
|
|
|
func (builtinOSProvider) LookupEnv(key string) (string, bool) {
|
|
return os.LookupEnv(key)
|
|
}
|
|
|
|
func (builtinOSProvider) Exec(ctx context.Context, name string, args ...string) (*exec.Cmd, error) {
|
|
return exec.CommandContext(ctx, name, args...), nil
|
|
}
|