Added os:exec builtin (#2)
All checks were successful
Build / build (push) Successful in 2m39s
All checks were successful
Build / build (push) Successful in 2m39s
Co-authored-by: Leon Mika <lmika@lmika.com> Reviewed-on: #2
This commit is contained in:
parent
7c76e61b08
commit
dd516feed4
|
|
@ -2,20 +2,32 @@ package builtins
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"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{}
|
||||
osh := osHandlers{
|
||||
provider: builtinOSProvider{},
|
||||
}
|
||||
|
||||
return ucl.Module{
|
||||
Name: "os",
|
||||
Builtins: map[string]ucl.BuiltinHandler{
|
||||
"env": osh.env,
|
||||
"exec": osh.exec,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +38,7 @@ func (oh osHandlers) env(ctx context.Context, args ucl.CallArgs) (any, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
val, ok := os.LookupEnv(envName)
|
||||
val, ok := oh.provider.LookupEnv(envName)
|
||||
if ok {
|
||||
return val, nil
|
||||
}
|
||||
|
|
@ -38,3 +50,42 @@ func (oh osHandlers) env(ctx context.Context, args ucl.CallArgs) (any, error) {
|
|||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ package builtins_test
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"ucl.lmika.dev/ucl"
|
||||
"ucl.lmika.dev/ucl/builtins"
|
||||
)
|
||||
|
|
@ -34,3 +36,25 @@ func TestOS_Env(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOS_Exec(t *testing.T) {
|
||||
tests := []struct {
|
||||
descr string
|
||||
eval string
|
||||
want any
|
||||
}{
|
||||
{descr: "run command 1", eval: `os:exec "echo" "hello, world"`, want: "hello, world\n"},
|
||||
{descr: "run command 1", eval: `os:exec "date" "+%Y%m%d"`, want: time.Now().Format("20060102") + "\n"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.descr, func(t *testing.T) {
|
||||
inst := ucl.New(
|
||||
ucl.WithModule(builtins.OS()),
|
||||
)
|
||||
res, err := inst.EvalString(context.Background(), tt.eval)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue