ucl/ucl/builtins/os.go
Leon Mika ebd8c61956
All checks were successful
Build / build (push) Successful in 2m17s
Added additional builtins for strings and lists
2025-10-27 22:05:14 +11:00

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
}