Skip to content

Commit 6aa9bd7

Browse files
glaukiol1sbinet
authored andcommitted
stdlib/os: first import
author glaukiol1 <[email protected]> committer Sebastien Binet <[email protected]>
1 parent 7e10deb commit 6aa9bd7

File tree

5 files changed

+435
-0
lines changed

5 files changed

+435
-0
lines changed

py/util.go

+32
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package py
77
import (
88
"errors"
99
"strconv"
10+
"strings"
1011
)
1112

1213
var (
@@ -204,3 +205,34 @@ func loadValue(src Object, data interface{}) error {
204205
}
205206
return nil
206207
}
208+
209+
// Println prints the provided strings to gpython's stdout.
210+
func Println(self Object, args ...string) bool {
211+
sysModule, err := self.(*Module).Context.GetModule("sys")
212+
if err != nil {
213+
return false
214+
}
215+
stdout := sysModule.Globals["stdout"]
216+
write, err := GetAttrString(stdout, "write")
217+
if err != nil {
218+
return false
219+
}
220+
call, ok := write.(I__call__)
221+
if !ok {
222+
return false
223+
}
224+
for _, v := range args {
225+
if !strings.Contains(v, "\n") {
226+
v += " "
227+
}
228+
_, err := call.M__call__(Tuple{String(v)}, nil)
229+
if err != nil {
230+
return false
231+
}
232+
}
233+
_, err = call.M__call__(Tuple{String("\n")}, nil) // newline
234+
if err != nil {
235+
return false
236+
}
237+
return true
238+
}

stdlib/os/os.go

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
// Copyright 2022 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// OS Module
6+
7+
package os
8+
9+
import (
10+
"os"
11+
"os/exec"
12+
"runtime"
13+
"strings"
14+
15+
"github.com/go-python/gpython/py"
16+
)
17+
18+
// getsep returns the common path seperator: '/' for anything but windows, '\' for windows
19+
func getsep() py.String {
20+
if runtime.GOOS != "windows" {
21+
return py.String("/")
22+
}
23+
return py.String("\\")
24+
}
25+
26+
// getname returns the operating system name: posix/nt/java
27+
func getname() py.String {
28+
if runtime.GOOS == "windows" {
29+
return py.String("nt")
30+
}
31+
if runtime.GOOS == "android" {
32+
return py.String("java")
33+
}
34+
return py.String("posix")
35+
}
36+
37+
// getpathsep returns the seperator used in $PATH. This is ';' for windows and ':' for posix
38+
func getpathsep() py.String {
39+
if runtime.GOOS == "windows" {
40+
return py.String(";")
41+
}
42+
return py.String(":")
43+
}
44+
45+
// getlinesep returns the line seperator (newline character). This is '\r\n' for windows and '\n' for posix
46+
func getlinesep() py.String {
47+
if runtime.GOOS == "windows" {
48+
return py.String("\r\n")
49+
}
50+
return py.String("\n")
51+
}
52+
53+
// getdefpath returns the default search path for executables. This is ':/bin:/usr/bin' in posix and 'C:\\bin' in windows
54+
func getdefpath() py.String {
55+
if runtime.GOOS == "windows" {
56+
return py.String("C:\\bin")
57+
}
58+
return py.String(":/bin:/usr/bin")
59+
}
60+
61+
// getdevnull returns the file path of the null device. This is '/dev/null' for posix and 'nul' for windows.
62+
func getdevnull() py.String {
63+
if runtime.GOOS == "windows" {
64+
return py.String("nul")
65+
}
66+
return py.String("/dev/null")
67+
}
68+
69+
// getaltsep returns the alternative path seperator. This is set to '/' on Windows systems where sep is a backslash
70+
func getaltsep() py.Object {
71+
if runtime.GOOS == "windows" {
72+
return py.String("/")
73+
}
74+
return py.None
75+
}
76+
77+
func init() {
78+
methods := []*py.Method{
79+
py.MustNewMethod("getcwd", getCwd, 0, "Get the current working directory"),
80+
py.MustNewMethod("getcwdb", getCwdb, 0, "Get the current working directory in a byte slice"),
81+
py.MustNewMethod("chdir", chdir, 0, "Change the current working directory"),
82+
py.MustNewMethod("getenv", getenv, 0, "Return the value of the environment variable key if it exists, or default if it doesn’t. key, default and the result are str."),
83+
py.MustNewMethod("getpid", getpid, 0, "Return the current process id."),
84+
py.MustNewMethod("putenv", putenv, 0, "Set the environment variable named key to the string value."),
85+
py.MustNewMethod("unsetenv", unsetenv, 0, "Unset (delete) the environment variable named key."),
86+
py.MustNewMethod("_exit", _exit, 0, "Immediate program termination."),
87+
py.MustNewMethod("system", system, 0, "Run shell commands, prints stdout directly to deault"),
88+
}
89+
globals := py.StringDict{
90+
"error": py.OSError,
91+
"environ": getEnvVariables(),
92+
"sep": getsep(),
93+
"name": getname(),
94+
"curdir": py.String("."),
95+
"pardir": py.String(".."),
96+
"extsep": py.String("."),
97+
"altsep": getaltsep(),
98+
"pathsep": getpathsep(),
99+
"linesep": getlinesep(),
100+
"defpath": getdefpath(),
101+
"devnull": getdevnull(),
102+
}
103+
104+
py.RegisterModule(&py.ModuleImpl{
105+
Info: py.ModuleInfo{
106+
Name: "os",
107+
Doc: "Miscellaneous operating system interfaces",
108+
},
109+
Methods: methods,
110+
Globals: globals,
111+
})
112+
}
113+
114+
// getEnvVariables returns the dictionary of environment variables.
115+
func getEnvVariables() py.StringDict {
116+
vs := os.Environ()
117+
dict := py.NewStringDictSized(len(vs))
118+
for _, evar := range vs {
119+
key_value := strings.SplitN(evar, "=", 2) // returns a []string containing [key,value]
120+
dict.M__setitem__(py.String(key_value[0]), py.String(key_value[1]))
121+
}
122+
123+
return dict
124+
}
125+
126+
// getCwd returns the current working directory.
127+
func getCwd(self py.Object, args py.Tuple) (py.Object, error) {
128+
dir, err := os.Getwd()
129+
if err != nil {
130+
return nil, py.ExceptionNewf(py.OSError, "Unable to get current working directory.")
131+
}
132+
return py.String(dir), nil
133+
}
134+
135+
// getCwdb returns the current working directory as a byte list.
136+
func getCwdb(self py.Object, args py.Tuple) (py.Object, error) {
137+
dir, err := os.Getwd()
138+
if err != nil {
139+
return nil, py.ExceptionNewf(py.OSError, "Unable to get current working directory.")
140+
}
141+
return py.Bytes(dir), nil
142+
}
143+
144+
// chdir changes the current working directory to the provided path.
145+
func chdir(self py.Object, args py.Tuple) (py.Object, error) {
146+
if len(args) == 0 {
147+
return nil, py.ExceptionNewf(py.TypeError, "Missing required argument 'path' (pos 1)")
148+
}
149+
dir, ok := args[0].(py.String)
150+
if !ok {
151+
return nil, py.ExceptionNewf(py.TypeError, "str expected, not "+args[0].Type().Name)
152+
}
153+
err := os.Chdir(string(dir))
154+
if err != nil {
155+
return nil, py.ExceptionNewf(py.NotADirectoryError, "Couldn't change cwd; "+err.Error())
156+
}
157+
return py.None, nil
158+
}
159+
160+
// getenv returns the value of the environment variable key.
161+
// If no such environment variable exists and a default value was provided, that value is returned.
162+
func getenv(self py.Object, args py.Tuple) (py.Object, error) {
163+
if len(args) < 1 {
164+
return nil, py.ExceptionNewf(py.TypeError, "missing one required argument: 'name:str'")
165+
}
166+
k, ok := args[0].(py.String)
167+
if !ok {
168+
return nil, py.ExceptionNewf(py.TypeError, "str expected (pos 1), not "+args[0].Type().Name)
169+
}
170+
v, ok := os.LookupEnv(string(k))
171+
if ok {
172+
return py.String(v), nil
173+
}
174+
if len(args) == 2 {
175+
return args[1], nil
176+
}
177+
return py.None, nil
178+
}
179+
180+
// getpid returns the current process id.
181+
func getpid(self py.Object, args py.Tuple) (py.Object, error) {
182+
return py.Int(os.Getpid()), nil
183+
}
184+
185+
// putenv sets the value of an environment variable named by the key.
186+
func putenv(self py.Object, args py.Tuple) (py.Object, error) {
187+
if len(args) != 2 {
188+
return nil, py.ExceptionNewf(py.TypeError, "missing required arguments: 'key:str' and 'value:str'")
189+
}
190+
k, ok := args[0].(py.String)
191+
if !ok {
192+
return nil, py.ExceptionNewf(py.TypeError, "str expected (pos 1), not "+args[0].Type().Name)
193+
}
194+
v, ok := args[1].(py.String)
195+
if !ok {
196+
return nil, py.ExceptionNewf(py.TypeError, "str expected (pos 2), not "+args[1].Type().Name)
197+
}
198+
err := os.Setenv(string(k), string(v))
199+
if err != nil {
200+
return nil, py.ExceptionNewf(py.OSError, "Unable to set enviroment variable")
201+
}
202+
return py.None, nil
203+
}
204+
205+
// Unset (delete) the environment variable named key.
206+
func unsetenv(self py.Object, args py.Tuple) (py.Object, error) {
207+
if len(args) != 1 {
208+
return nil, py.ExceptionNewf(py.TypeError, "missing one required argument: 'key:str'")
209+
}
210+
k, ok := args[0].(py.String)
211+
if !ok {
212+
return nil, py.ExceptionNewf(py.TypeError, "str expected (pos 1), not "+args[0].Type().Name)
213+
}
214+
err := os.Unsetenv(string(k))
215+
if err != nil {
216+
return nil, py.ExceptionNewf(py.OSError, "Unable to unset enviroment variable")
217+
}
218+
return py.None, nil
219+
}
220+
221+
// os._exit() immediate program termination; unlike sys.exit(), which raises a SystemExit, this function will termninate the program immediately.
222+
func _exit(self py.Object, args py.Tuple) (py.Object, error) { // can never return
223+
if len(args) == 0 {
224+
os.Exit(0)
225+
}
226+
arg, ok := args[0].(py.Int)
227+
if !ok {
228+
return nil, py.ExceptionNewf(py.TypeError, "expected int (pos 1), not "+args[0].Type().Name)
229+
}
230+
os.Exit(int(arg))
231+
return nil, nil
232+
}
233+
234+
// os.system(command string) this function runs a shell command and directs the output to standard output.
235+
func system(self py.Object, args py.Tuple) (py.Object, error) {
236+
if len(args) != 1 {
237+
return nil, py.ExceptionNewf(py.TypeError, "missing one required argument: 'command:str'")
238+
}
239+
arg, ok := args[0].(py.String)
240+
if !ok {
241+
return nil, py.ExceptionNewf(py.TypeError, "str expected (pos 1), not "+args[0].Type().Name)
242+
}
243+
244+
var command *exec.Cmd
245+
if runtime.GOOS != "windows" {
246+
command = exec.Command("/bin/sh", "-c", string(arg))
247+
} else {
248+
command = exec.Command("cmd.exe", string(arg))
249+
}
250+
outb, err := command.CombinedOutput() // - commbinedoutput to get both stderr and stdout -
251+
if err != nil {
252+
return nil, py.ExceptionNewf(py.OSError, err.Error())
253+
}
254+
ok = py.Println(self, string(outb))
255+
if !ok {
256+
return py.Int(1), nil
257+
}
258+
259+
return py.Int(0), nil
260+
}

0 commit comments

Comments
 (0)