github.com/mcuadros/ascode@v1.3.1/starlark/module/os/os.go (about)

     1  package os
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"sync"
     9  
    10  	gobs "github.com/gobs/args"
    11  	"go.starlark.net/starlark"
    12  	"go.starlark.net/starlarkstruct"
    13  )
    14  
    15  const (
    16  	// ModuleName defines the expected name for this Module when used
    17  	// in starlark's load() function, eg: load('io/ioutil', 'json')
    18  	ModuleName = "os"
    19  
    20  	getwdFuncName     = "getwd"
    21  	chdirFuncName     = "chdir"
    22  	getenvFuncName    = "getenv"
    23  	setenvFuncName    = "setenv"
    24  	writeFileFuncName = "write_file"
    25  	readFileFuncName  = "read_file"
    26  	mkdirFuncName     = "mkdir"
    27  	mkdirAllFuncName  = "mkdir_all"
    28  	removeFuncName    = "remove"
    29  	removeAllFuncName = "remove_all"
    30  	renameFuncName    = "rename"
    31  	tempDirFuncName   = "temp_dir"
    32  	commandFuncName   = "command"
    33  )
    34  
    35  var (
    36  	once         sync.Once
    37  	ioutilModule starlark.StringDict
    38  )
    39  
    40  // LoadModule loads the os module.
    41  // It is concurrency-safe and idempotent.
    42  //
    43  //   outline: os
    44  //     os provides a platform-independent interface to operating system functionality.
    45  //     path: os
    46  func LoadModule() (starlark.StringDict, error) {
    47  	once.Do(func() {
    48  		ioutilModule = starlark.StringDict{
    49  			"os": &starlarkstruct.Module{
    50  				Name: "os",
    51  				Members: starlark.StringDict{
    52  					chdirFuncName:     starlark.NewBuiltin(chdirFuncName, Chdir),
    53  					getwdFuncName:     starlark.NewBuiltin(getwdFuncName, Getwd),
    54  					setenvFuncName:    starlark.NewBuiltin(setenvFuncName, Setenv),
    55  					getenvFuncName:    starlark.NewBuiltin(getenvFuncName, Getenv),
    56  					writeFileFuncName: starlark.NewBuiltin(writeFileFuncName, WriteFile),
    57  					readFileFuncName:  starlark.NewBuiltin(readFileFuncName, ReadFile),
    58  					mkdirFuncName:     starlark.NewBuiltin(mkdirFuncName, Mkdir),
    59  					mkdirAllFuncName:  starlark.NewBuiltin(mkdirAllFuncName, MkdirAll),
    60  					removeFuncName:    starlark.NewBuiltin(mkdirFuncName, Remove),
    61  					removeAllFuncName: starlark.NewBuiltin(mkdirFuncName, RemoveAll),
    62  					renameFuncName:    starlark.NewBuiltin(renameFuncName, Rename),
    63  					tempDirFuncName:   starlark.NewBuiltin(tempDirFuncName, TempDir),
    64  					commandFuncName:   starlark.NewBuiltin(commandFuncName, Command),
    65  				},
    66  			},
    67  		}
    68  	})
    69  
    70  	return ioutilModule, nil
    71  }
    72  
    73  // Chdir changes the current working directory to the named directory.
    74  //
    75  //   outline: os
    76  //     functions:
    77  //       chdir(dir)
    78  //         changes the current working directory to the named directory.
    79  //         params:
    80  //           dir string
    81  //             target dir
    82  func Chdir(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
    83  	var dir string
    84  
    85  	err := starlark.UnpackArgs(chdirFuncName, args, kwargs, "dir", &dir)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	return starlark.None, os.Chdir(dir)
    91  }
    92  
    93  // Getwd returns a rooted path name corresponding to the current directory.
    94  //
    95  //   outline: os
    96  //     functions:
    97  //       getwd() dir
    98  //         returns a rooted path name corresponding to the current directory.
    99  func Getwd(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   100  	dir, err := os.Getwd()
   101  	return starlark.String(dir), err
   102  }
   103  
   104  // Setenv sets the value of the environment variable named by the key. It returns an error, if any.
   105  //
   106  //   outline: os
   107  //     functions:
   108  //       setenv(key, value) dir
   109  //         sets the value of the environment variable named by the key.
   110  //         params:
   111  //           key string
   112  //             name of the environment variable
   113  //           value string
   114  //             value of the environment variable
   115  func Setenv(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   116  	var (
   117  		key   string
   118  		value string
   119  	)
   120  
   121  	err := starlark.UnpackArgs(setenvFuncName, args, kwargs, "key", &key, "value", &value)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	return starlark.None, os.Setenv(key, value)
   127  }
   128  
   129  // Getenv retrieves the value of the environment variable named by the key.
   130  //
   131  //   outline: os
   132  //     functions:
   133  //       getenv(key) dir
   134  //         retrieves the value of the environment variable named by the key.
   135  //         params:
   136  //           key string
   137  //             name of the environment variable
   138  func Getenv(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   139  	var (
   140  		key string
   141  		def string
   142  	)
   143  
   144  	err := starlark.UnpackArgs(getenvFuncName, args, kwargs, "key", &key, "default?", &def)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	value := os.Getenv(key)
   150  	if value == "" {
   151  		value = def
   152  	}
   153  
   154  	return starlark.String(value), nil
   155  }
   156  
   157  // WriteFile writes data to a file named by filename. If the file does not
   158  // exist, WriteFile creates it with permissions perm; otherwise WriteFile
   159  // truncates it before writing.
   160  //
   161  //   outline: os
   162  //     functions:
   163  //       write_file(filename, data, perms=0o644)
   164  //         retrieves the value of the environment variable named by the key.
   165  //         params:
   166  //           filename string
   167  //             name of the file to be written
   168  //           data string
   169  //              content to be witten to the file
   170  //           perms int
   171  //              optional, permission of the file
   172  func WriteFile(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   173  	var (
   174  		filename string
   175  		content  string
   176  		perms    = 0644
   177  	)
   178  
   179  	err := starlark.UnpackArgs(writeFileFuncName, args, kwargs, "filename", &filename, "content", &content, "perms?", &perms)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  
   184  	return starlark.None, ioutil.WriteFile(filename, []byte(content), os.FileMode(perms))
   185  }
   186  
   187  // ReadFile reads the file named by filename and returns the contents.
   188  //
   189  //   outline: os
   190  //     functions:
   191  //       read_file(filename) string
   192  //         reads the file named by filename and returns the contents.
   193  //         params:
   194  //           filename string
   195  //             name of the file to be written
   196  //           data string
   197  //              content to be witten to the file
   198  //           perms int
   199  //              optional, permission of the file
   200  func ReadFile(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   201  	var filename string
   202  
   203  	err := starlark.UnpackArgs(readFileFuncName, args, kwargs, "filename", &filename)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	data, err := ioutil.ReadFile(filename)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	return starlark.String(string(data)), nil
   214  }
   215  
   216  // Mkdir creates a new directory with the specified name and permission bits (before umask).
   217  //
   218  //   outline: os
   219  //     functions:
   220  //       mkdir(name, perms=0o777)
   221  //         creates a new directory with the specified name and permission bits (before umask).
   222  //         params:
   223  //           name string
   224  //             name of the folder to be created
   225  //           perms int
   226  //              optional, permission of the folder
   227  func Mkdir(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   228  	var (
   229  		name  string
   230  		perms = 0777
   231  	)
   232  
   233  	err := starlark.UnpackArgs(mkdirFuncName, args, kwargs, "name", &name, "perms?", &perms)
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  
   238  	return starlark.None, os.Mkdir(name, os.FileMode(perms))
   239  }
   240  
   241  // MkdirAll creates a directory named path, along with any necessary parents.
   242  //
   243  //   outline: os
   244  //     functions:
   245  //       mkdir_all(name, perms=0o777)
   246  //         creates a new directory with the specified name and permission bits (before umask).
   247  //         params:
   248  //           name string
   249  //             name of the folder to be created
   250  //           perms int
   251  //              optional, permission of the folder
   252  func MkdirAll(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   253  	var (
   254  		path  string
   255  		perms = 0777
   256  	)
   257  
   258  	err := starlark.UnpackArgs(mkdirAllFuncName, args, kwargs, "path", &path, "perms?", &perms)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	return starlark.None, os.MkdirAll(path, os.FileMode(perms))
   264  }
   265  
   266  // Remove removes the named file or (empty) directory.
   267  //
   268  //   outline: os
   269  //     functions:
   270  //       remove(name)
   271  //         removes the named file or (empty) directory.
   272  //         params:
   273  //           name string
   274  //             name of the file or directory to be deleted
   275  func Remove(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   276  	var name string
   277  
   278  	err := starlark.UnpackArgs(removeFuncName, args, kwargs, "name", &name)
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	return starlark.None, os.Remove(name)
   284  }
   285  
   286  // RemoveAll removes path and any children it contains.
   287  //
   288  //   outline: os
   289  //     functions:
   290  //       remove_all(path)
   291  //         removes path and any children it contains. It removes everything it
   292  //         can but returns the first error it encounters.
   293  //         params:
   294  //           name string
   295  //             path to be deleted
   296  func RemoveAll(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   297  	var path string
   298  
   299  	err := starlark.UnpackArgs(removeAllFuncName, args, kwargs, "path", &path)
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  
   304  	return starlark.None, os.RemoveAll(path)
   305  }
   306  
   307  // Rename renames (moves) oldpath to newpath. If
   308  //
   309  //   outline: os
   310  //     functions:
   311  //       rename(oldpath, newpath)
   312  //         renames (moves) oldpath to newpath. If newpath already exists and is
   313  //         not a directory, Rename replaces it. OS-specific restrictions may
   314  //         apply when oldpath and newpath are in different directories.
   315  //         params:
   316  //           oldpath string
   317  //             old path
   318  //           newpath string
   319  //             new path
   320  func Rename(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   321  	var (
   322  		oldpath string
   323  		newpath string
   324  	)
   325  
   326  	err := starlark.UnpackArgs(renameFuncName, args, kwargs, "oldpath", &oldpath, "newpath", &newpath)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  
   331  	return starlark.None, os.Rename(oldpath, newpath)
   332  }
   333  
   334  // TempDir returns the default directory to use for temporary files.
   335  //
   336  //   outline: os
   337  //     functions:
   338  //       temp_dir()
   339  //         returns the default directory to use for temporary files.
   340  func TempDir(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
   341  	return starlark.String(os.TempDir()), nil
   342  }
   343  
   344  // Command runs the command and returns its standard output.
   345  //
   346  //   outline: os
   347  //     functions:
   348  //       command(command, shell=False, dir="", combined=False, 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  }