Skip to content

Commit 4d4f105

Browse files
committed
starlark/module: os, added command function
1 parent e2a245a commit 4d4f105

File tree

5 files changed

+127
-1
lines changed

5 files changed

+127
-1
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/docker/distribution v2.7.1+incompatible // indirect
99
github.com/docker/go-metrics v0.0.1 // indirect
1010
github.com/go-git/go-git/v5 v5.0.0
11+
github.com/gobs/args v0.0.0-20180315064131-86002b4df18c
1112
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
1213
github.com/hashicorp/go-hclog v0.11.0
1314
github.com/hashicorp/go-plugin v1.0.1-0.20190610192547-a1bc61569a26

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
211211
github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
212212
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
213213
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
214+
github.com/gobs/args v0.0.0-20180315064131-86002b4df18c h1:3r/O0iUDMwVJx8XCrjcUvfmfbVP3poiT+1dLyYzx8+w=
215+
github.com/gobs/args v0.0.0-20180315064131-86002b4df18c/go.mod h1:ZpqkpUmnBz2Jz7hMGSPRbHtYC82FP/IZ1Y7A2riYH0s=
214216
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
215217
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
216218
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=

starlark/module/os/os.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package os
22

33
import (
4+
"fmt"
45
"io/ioutil"
56
"os"
7+
"os/exec"
68
"sync"
79

10+
gobs "github.com/gobs/args"
811
"go.starlark.net/starlark"
912
"go.starlark.net/starlarkstruct"
1013
)
@@ -26,6 +29,7 @@ const (
2629
removeAllFuncName = "remove_all"
2730
renameFuncName = "rename"
2831
tempDirFuncName = "temp_dir"
32+
commandFuncName = "command"
2933
)
3034

3135
var (
@@ -57,6 +61,7 @@ func LoadModule() (starlark.StringDict, error) {
5761
removeAllFuncName: starlark.NewBuiltin(mkdirFuncName, RemoveAll),
5862
renameFuncName: starlark.NewBuiltin(renameFuncName, Rename),
5963
tempDirFuncName: starlark.NewBuiltin(tempDirFuncName, TempDir),
64+
commandFuncName: starlark.NewBuiltin(commandFuncName, Command),
6065
},
6166
},
6267
}
@@ -335,3 +340,97 @@ func Rename(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, k
335340
func TempDir(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
336341
return starlark.String(os.TempDir()), nil
337342
}
343+
344+
// Command runs the command and returns its standard output.
345+
//
346+
// outline: os
347+
// functions:
348+
// command(command, shell?, dir?, combined?, env?)
349+
// runs the command and returns its standard output. If the exit code
350+
// it different to zero, an error is triggered.
351+
// params:
352+
// shell bool
353+
// if True execute the command inside of a shell.
354+
// dir string
355+
// working directory of the command.
356+
// combined bool
357+
// if True returns combined standard output and standard error.
358+
// env list
359+
// specifies the environment of the process, each value of the list
360+
// should follow the pattern "key=value".
361+
func Command(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
362+
var (
363+
command string
364+
env *starlark.List
365+
dir string
366+
combined bool
367+
shell bool
368+
)
369+
370+
err := starlark.UnpackArgs(renameFuncName, args, kwargs,
371+
"command", &command,
372+
"env?", &env,
373+
"dir?", &dir,
374+
"combined?", &combined,
375+
"shell?", &shell,
376+
)
377+
378+
if err != nil {
379+
return nil, err
380+
}
381+
382+
if shell {
383+
command = fmt.Sprintf("sh -c %q", command)
384+
}
385+
386+
cmdArgs := gobs.GetArgs(command)
387+
bin, err := exec.LookPath(cmdArgs[0])
388+
if err != nil {
389+
return nil, err
390+
}
391+
392+
environment, err := unpackListArg(renameFuncName, "env", env)
393+
if err != nil {
394+
return nil, err
395+
}
396+
397+
cmd := &exec.Cmd{
398+
Path: bin,
399+
Args: cmdArgs,
400+
Env: append(os.Environ(), environment...),
401+
Dir: dir,
402+
}
403+
404+
var output []byte
405+
if combined {
406+
output, err = cmd.CombinedOutput()
407+
} else {
408+
output, err = cmd.Output()
409+
}
410+
411+
if len(output) >= 1 && output[len(output)-1] == '\n' {
412+
output = output[:len(output)-1]
413+
}
414+
415+
return starlark.String(output), err
416+
}
417+
418+
func unpackListArg(fnName, argName string, l *starlark.List) ([]string, error) {
419+
if l == nil {
420+
return []string{}, nil
421+
}
422+
423+
output := make([]string, l.Len())
424+
for i := 0; i < l.Len(); i++ {
425+
s, ok := l.Index(i).(starlark.String)
426+
if ok {
427+
output[i] = s.GoString()
428+
continue
429+
}
430+
431+
return nil, fmt.Errorf("%s: parameter %q expected string at index %d", fnName, argName, i)
432+
433+
}
434+
435+
return output, nil
436+
}

starlark/module/os/os_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ func TestFile(t *testing.T) {
1717
}
1818

1919
resolve.AllowFloat = true
20+
resolve.AllowGlobalReassign = true
21+
resolve.AllowLambda = true
22+
2023
thread := &starlark.Thread{Load: testdata.NewLoader(LoadModule, ModuleName)}
2124
starlarktest.SetReporter(thread, t)
2225

starlark/module/os/testdata/test.star

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,25 @@ os.rename("foo", "bar")
3333
os.remove_all("bar")
3434

3535
def deleteNotExistant(): os.remove("foo")
36-
assert.fails(deleteNotExistant, "remove foo: no such file or directory")
36+
assert.fails(deleteNotExistant, "remove foo: no such file or directory")
37+
38+
# test command
39+
temp = os.temp_dir() + "/example-dir"
40+
os.mkdir_all(temp + "/foo/bar", 0o755)
41+
os.chdir(temp)
42+
43+
assert.eq(os.command("ls -1"), "foo")
44+
45+
# test command dir
46+
assert.eq(os.command("ls -1", dir="foo"), "bar")
47+
48+
# test command shell and env
49+
assert.eq(os.command("echo $FOO", shell=True, env=["FOO=foo"]), "foo")
50+
51+
# test command combined
52+
assert.ne(os.command("not-exists || true", shell=True, combined=True), "")
53+
54+
# test command error
55+
assert.fails(lambda: os.command("not-exists"), "executable file not found")
56+
57+
os.remove_all(temp)

0 commit comments

Comments
 (0)