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 }