11package os
22
33import (
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
3135var (
@@ -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
335340func 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+ }
0 commit comments