Skip to content

Commit 5963327

Browse files
authored
[feat] add new lib: runtime, add docs for runtime and string (#47)
* Migrate * local methods * duration time * for runtime * ut fn * go ver * basic docs * for string doc * update docs and examples * for err it * for ppid and uid * for gid * refine lint
1 parent cab0c90 commit 5963327

File tree

7 files changed

+294
-2
lines changed

7 files changed

+294
-2
lines changed

config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
libjson "github.com/1set/starlet/lib/json"
99
librand "github.com/1set/starlet/lib/random"
1010
libre "github.com/1set/starlet/lib/re"
11+
librt "github.com/1set/starlet/lib/runtime"
1112
libstr "github.com/1set/starlet/lib/string"
1213
stdmath "go.starlark.net/lib/math"
1314
stdtime "go.starlark.net/lib/time"
@@ -43,6 +44,7 @@ var allBuiltinModules = ModuleLoaderMap{
4344
librand.ModuleName: librand.LoadModule,
4445
libjson.ModuleName: libjson.LoadModule,
4546
libstr.ModuleName: libstr.LoadModule,
47+
librt.ModuleName: librt.LoadModule,
4648
}
4749

4850
// GetAllBuiltinModuleNames returns a list of all builtin module names.

lib/runtime/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# runtime
2+
3+
`runtime` is a Starlark module provides Go and app runtime information.
4+
5+
## Functions
6+
7+
### `uptime()`
8+
9+
Returns the uptime of the current process in `time.duration`.
10+
11+
#### Examples
12+
13+
**basic**
14+
15+
Returns the uptime of the current process immediately.
16+
17+
```python
18+
load("runtime", "uptime")
19+
print(uptime())
20+
# Output: 883.583µs
21+
```

lib/runtime/runtime.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Package runtime implements the Starlark module for Go and app runtime information.
2+
package runtime
3+
4+
import (
5+
"os"
6+
grt "runtime"
7+
"sync"
8+
"time"
9+
10+
stdtime "go.starlark.net/lib/time"
11+
"go.starlark.net/starlark"
12+
"go.starlark.net/starlarkstruct"
13+
)
14+
15+
// ModuleName defines the expected name for this Module when used in starlark's load() function, eg: load('base64', 'encode')
16+
const ModuleName = "runtime"
17+
18+
var (
19+
once sync.Once
20+
moduleData starlark.StringDict
21+
)
22+
23+
// LoadModule loads the runtime module. It is concurrency-safe and idempotent.
24+
func LoadModule() (md starlark.StringDict, err error) {
25+
once.Do(func() {
26+
var host, pwd string
27+
if host, err = os.Hostname(); err != nil {
28+
return
29+
}
30+
if pwd, err = os.Getwd(); err != nil {
31+
return
32+
}
33+
moduleData = starlark.StringDict{
34+
ModuleName: &starlarkstruct.Module{
35+
Name: ModuleName,
36+
Members: starlark.StringDict{
37+
"hostname": starlark.String(host),
38+
"workdir": starlark.String(pwd),
39+
"os": starlark.String(grt.GOOS),
40+
"arch": starlark.String(grt.GOARCH),
41+
"gover": starlark.String(grt.Version()),
42+
"pid": starlark.MakeInt(os.Getpid()),
43+
"ppid": starlark.MakeInt(os.Getppid()),
44+
"uid": starlark.MakeInt(os.Getuid()),
45+
"gid": starlark.MakeInt(os.Getgid()),
46+
"app_start": stdtime.Time(appStart),
47+
"uptime": starlark.NewBuiltin(ModuleName+".uptime", getUpTime),
48+
},
49+
},
50+
}
51+
})
52+
return moduleData, err
53+
}
54+
55+
var (
56+
appStart = time.Now()
57+
)
58+
59+
// getUpTime returns time elapsed since the app started.
60+
func getUpTime(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
61+
return stdtime.Duration(time.Since(appStart)), nil
62+
}

lib/runtime/runtime_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package runtime_test
2+
3+
import (
4+
"testing"
5+
6+
itn "github.com/1set/starlet/internal"
7+
rt "github.com/1set/starlet/lib/runtime"
8+
)
9+
10+
func TestLoadModule_Runtime(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
script string
14+
wantErr string
15+
}{
16+
{
17+
name: `host`,
18+
script: itn.HereDoc(`
19+
load('runtime', 'hostname', 'workdir', 'os', 'arch', 'gover')
20+
ss = [hostname, workdir, os, arch, gover]
21+
print(ss)
22+
_ = [assert.eq(type(s), "string") for s in ss]
23+
`),
24+
},
25+
{
26+
name: `process`,
27+
script: itn.HereDoc(`
28+
load('runtime', 'pid', 'ppid', 'uid', 'gid')
29+
si = [pid, ppid, uid, gid]
30+
print(si)
31+
_ = [assert.eq(type(s), "int") for s in si]
32+
`),
33+
},
34+
{
35+
name: `app`,
36+
script: itn.HereDoc(`
37+
load('runtime', s='app_start', ut='uptime')
38+
assert.eq(type(s), "time.time")
39+
u = ut()
40+
assert.eq(type(u), "time.duration")
41+
print(s, u)
42+
`),
43+
},
44+
}
45+
for _, tt := range tests {
46+
t.Run(tt.name, func(t *testing.T) {
47+
res, err := itn.ExecModuleWithErrorTest(t, rt.ModuleName, rt.LoadModule, tt.script, tt.wantErr)
48+
if (err != nil) != (tt.wantErr != "") {
49+
t.Errorf("runtime(%q) expects error = '%v', actual error = '%v', result = %v", tt.name, tt.wantErr, err, res)
50+
return
51+
}
52+
})
53+
}
54+
}

lib/string/README.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# string
2+
3+
`string` provides constants and functions to manipulate strings, it's intended to be a drop-in subset of Python's string module for Starlark.
4+
5+
## Functions
6+
7+
### `length(obj) int`
8+
9+
Returns the length of the object; for string, it returns the number of Unicode code points, instead of bytes like `len()`.
10+
11+
#### Parameters
12+
13+
| name | type | description |
14+
|-------|----------|---------------------------------------------|
15+
| `obj` | `string` | The object whose length is to be calculated |
16+
17+
#### Examples
18+
19+
**String**
20+
21+
Calculate the length of a CJK string.
22+
23+
```python
24+
load("string", "length")
25+
s = "你好"
26+
print(length(s), len(s))
27+
# Output: 2 6
28+
```
29+
30+
**Misc**
31+
32+
Calculate the length of a list, set and map.
33+
34+
```python
35+
load("string", "length")
36+
print(length([1, 2, 3]), length(set([1, 2])), length({1: 2}))
37+
# Output: 3 2 1
38+
```
39+
40+
### `reverse(str) string`
41+
42+
Returns the reversed string of the given value.
43+
44+
#### Parameters
45+
46+
| name | type | description |
47+
|-------|----------|---------------------------------|
48+
| `str` | `string` | A string that is to be reversed |
49+
50+
#### Examples
51+
52+
**String**
53+
54+
Reverse a string.
55+
56+
```python
57+
load("string", "reverse")
58+
s = "123我爱你"
59+
print(reverse(s))
60+
# Output: 你爱我321
61+
```
62+
63+
### `escape(str) string`
64+
65+
Converts the characters "&", "<", ">", '"' and "'" in string to their corresponding HTML entities.
66+
67+
#### Parameters
68+
69+
| name | type | description |
70+
|-------|----------|--------------------------------------|
71+
| `str` | `string` | A string which is to be HTML escaped |
72+
73+
#### Examples
74+
75+
**String**
76+
77+
Escape a string.
78+
79+
```python
80+
load("string", "escape")
81+
s = "Hello<World>"
82+
print(escape(s))
83+
# Output: Hello&lt;World&gt;
84+
```
85+
86+
### `unescape(str) string`
87+
88+
Converts the HTML entities in a string back to their corresponding characters.
89+
90+
#### Parameters
91+
92+
| name | type | description |
93+
|-------|----------|-----------------------|
94+
| `str` | `string` | A HTML escaped string |
95+
96+
#### Examples
97+
98+
**String**
99+
100+
Unescape a string.
101+
102+
```python
103+
load("string", "unescape")
104+
s = "You&amp;Me"
105+
print(unescape(s))
106+
# Output: "You&Me"
107+
```
108+
109+
### `quote(str) string`
110+
111+
Returns a shell-escaped version of the string str. This returns a string that can safely be used as one token in a shell command line.
112+
113+
#### Parameters
114+
115+
| name | type | description |
116+
|-------|----------|--------------------------------|
117+
| `str` | `string` | A string which is to be quoted |
118+
119+
#### Examples
120+
121+
**String**
122+
123+
Quote a string.
124+
125+
```python
126+
load("string", "quote")
127+
s = "Hello World"
128+
print(quote(s))
129+
# Output: "Hello World"
130+
```
131+
132+
### `unquote(str) string`
133+
134+
Returns a shell-unescaped version of the string str. This returns a string that was used as one token in a shell command line.
135+
136+
#### Parameters
137+
138+
| name | type | description |
139+
|-------|----------|----------------------------------|
140+
| `str` | `string` | A string which is to be unquoted |
141+
142+
#### Examples
143+
144+
**String**
145+
146+
Unquote a string.
147+
148+
```python
149+
load("string", "unquote")
150+
s = '"Hello\tWorld"'
151+
print(unquote(s))
152+
World
153+
```

lib/string/string_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func TestLoadModule_String(t *testing.T) {
217217
t.Run(tt.name, func(t *testing.T) {
218218
res, err := itn.ExecModuleWithErrorTest(t, ls.ModuleName, ls.LoadModule, tt.script, tt.wantErr)
219219
if (err != nil) != (tt.wantErr != "") {
220-
t.Errorf("hash(%q) expects error = '%v', actual error = '%v', result = %v", tt.name, tt.wantErr, err, res)
220+
t.Errorf("string(%q) expects error = '%v', actual error = '%v', result = %v", tt.name, tt.wantErr, err, res)
221221
return
222222
}
223223
})

module_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
)
1414

1515
var (
16-
builtinModules = []string{"base64", "go_idiomatic", "hashlib", "http", "json", "math", "random", "re", "string", "struct", "time"}
16+
builtinModules = []string{"base64", "go_idiomatic", "hashlib", "http", "json", "math", "random", "re", "runtime", "string", "struct", "time"}
1717
)
1818

1919
func TestListBuiltinModules(t *testing.T) {

0 commit comments

Comments
 (0)