Skip to content

Commit e145b4e

Browse files
authored
Misc Fixes and Improvements (#3)
* for starlet new v010 * less dep * update go sum * simple * save mod names * fast convert * __mod tests * refine load mod tetss * add summary * more testings * for complex testing * for getter modules * no modules * update readme
1 parent cab9a77 commit e145b4e

File tree

12 files changed

+315
-95
lines changed

12 files changed

+315
-95
lines changed

.github/workflows/build.yml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,25 @@ jobs:
6767
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
6868
run:
6969
bash <(curl -Ls https://coverage.codacy.com/get.sh) report --force-coverage-parser go -r coverage.txt
70-
- name: Analyze
70+
- name: Analyze on Linux
7171
if: ${{ runner.os == 'Linux' }}
7272
run: |
73-
# tokei -- count
73+
# Setup
7474
wget -cqL https://github.com/XAMPPRocky/tokei/releases/download/v12.1.2/tokei-i686-unknown-linux-musl.tar.gz -O tokei.tgz
7575
tar zxf tokei.tgz tokei && chmod +x tokei && $SUDO mv tokei /usr/local/bin && rm tokei.tgz
76-
echo "=== Tokei Result ==="
77-
tokei
78-
# revive -- lint
79-
wget -cqL https://github.com/mgechev/revive/releases/download/v1.2.4/revive_1.2.4_Linux_x86_64.tar.gz -O revive.tgz
76+
wget -cqL https://github.com/mgechev/revive/releases/download/v1.3.7/revive_linux_amd64.tar.gz -O revive.tgz
8077
tar zxf revive.tgz revive && chmod +x revive && $SUDO mv revive /usr/local/bin && rm revive.tgz
8178
wget -cqL https://raw.githubusercontent.com/1set/meta/master/revive.toml -O revive.toml
82-
echo "=== Revive Result ==="
83-
revive -config revive.toml -formatter friendly ./...
79+
# Analyze
80+
echo "# Analysis on Linux" > $GITHUB_STEP_SUMMARY
81+
uname -a >> $GITHUB_STEP_SUMMARY
82+
# --- count lines of code
83+
echo "## Tokei Result" >> $GITHUB_STEP_SUMMARY
84+
printf '\n```\n' >> $GITHUB_STEP_SUMMARY
85+
tokei >> $GITHUB_STEP_SUMMARY
86+
printf '```\n\n' >> $GITHUB_STEP_SUMMARY
87+
# --- lint
88+
echo "## Revive Result" >> $GITHUB_STEP_SUMMARY
89+
printf '\n```\n' >> $GITHUB_STEP_SUMMARY
90+
revive -config revive.toml -formatter friendly ./... >> $GITHUB_STEP_SUMMARY
91+
printf '```\n\n' >> $GITHUB_STEP_SUMMARY

README.md

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,88 @@
1-
# 🥡 starbox - Another Starlark runtime in a box
1+
# :takeout_box: Starbox - Another Starlark runtime in a box
22

33
[![godoc](https://pkg.go.dev/badge/github.com/1set/starbox.svg)](https://pkg.go.dev/github.com/1set/starbox)
44
[![codecov](https://codecov.io/github/1set/starbox/graph/badge.svg?token=8v1rqUSOfD)](https://codecov.io/github/1set/starbox)
55
[![codacy](https://app.codacy.com/project/badge/Grade/c706bea001fa48d3a958f609c7463200)](https://app.codacy.com/gh/1set/starbox/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
66
[![codeclimate](https://api.codeclimate.com/v1/badges/23baa9f82df1c504d2da/maintainability)](https://codeclimate.com/github/1set/starbox/maintainability)
77
[![go report](https://goreportcard.com/badge/github.com/1set/starbox)](https://goreportcard.com/report/github.com/1set/starbox)
88

9-
Starlark in a box -- a simple Starlark REPL and script runner.
9+
*Starbox* is a pragmatic Go wrapper around the [*Starlark in Go*](https://github.com/google/starlark-go) project, making it easier to execute Starlark scripts, exchange data between Go and Starlark, and call functions across the Go-Starlark boundary. With a focus on simplicity and usability, *Starbox* aims to provide an enhanced experience for developers integrating Starlark scripting into their Go applications.
1010

11-
It provides three main features:
11+
## 🚀 Key Features
1212

13-
- **Execute** a Starlark script file or REPL
14-
- **Data** exchange between Starlark and Go
15-
- **Function** call from Starlark to Go, or vice versa
13+
A host of powerful features are provided to supercharge your Starlark scripting experience:
14+
15+
- **Streamlined Script Execution**: Simplifies setting up and running Starlark scripts, offering a seamless interface for both script execution and interactive REPL sessions.
16+
- **Efficient Data Interchange**: Enables robust and smooth data exchange between Go and Starlark, enhancing the interoperability and simplifying the integration process.
17+
- **Versatile Module Management**: Extends Starlark's capabilities with a suite of built-in functions and the ability to load custom and override existing modules, covering functionalities from data processing to HTTP handling and file manipulation.
18+
- **Cross-Language Function Calls:** Leverage the power of both languages by calling Go functions from Starlark and vice versa, creating powerful integrations.
19+
- **Integrated HTTP Context**: Facilitates handling HTTP requests and responses within Starlark scripts, catering to web application development and server-side scripting.
20+
- **Collective Memory Sharing**: Introduces a shared memory concept, enabling data sharing across different script executions and instances, fostering a more connected and dynamic scripting environment.
21+
- **Advanced Scripting Tools:** Utilize features like REPL for interactive exploration and debugging, along with script caching for improved performance.
22+
23+
## 📦 Installation
24+
25+
To include `starbox` in your Go project, use the following command:
26+
27+
```bash
28+
go get github.com/1set/starbox
29+
```
30+
31+
## ⚙️ Usage
32+
33+
Here's a quick example of how you can use Starbox:
34+
35+
```go
36+
import "github.com/1set/starbox"
37+
38+
// Define your box with global variables and modules
39+
box := starbox.New("quick")
40+
box.AddKeyValue("greet", func(name string) string {
41+
return fmt.Sprintf("Hello, %s!", name)
42+
})
43+
box.AddNamedModules("random")
44+
45+
// Run a Starlark script
46+
script := starbox.HereDoc(`
47+
target = random.choice(["World", "Starlark", "Starbox"])
48+
text = greet(target)
49+
print("Starlark:", text)
50+
print(__modules__)
51+
`)
52+
res, err := box.Run(script)
53+
54+
// Check for errors and results
55+
if err != nil {
56+
fmt.Println("Error executing script:", err)
57+
return
58+
}
59+
fmt.Println("Go:", res["text"].(string))
60+
```
61+
62+
This may output:
63+
64+
```
65+
[⭐|quick](15:50:27.677) Starlark: Hello, Starbox!
66+
[⭐|quick](15:50:27.677) ["random"]
67+
Go: Hello, Starbox!
68+
```
69+
70+
## 👥 Contributing
71+
72+
We welcome contributions to the *Starbox* project. If you encounter any issues or have suggestions for improvements, please feel free to open an issue or submit a pull request. Before undertaking any significant changes, please let us know by filing an issue or claiming an existing one to ensure there is no duplication of effort.
73+
74+
## 📜 License
75+
76+
*Starbox* is licensed under the [MIT License](LICENSE).
77+
78+
## 🙌 Credits
79+
80+
This project is inspired by and builds upon several open-source projects:
81+
82+
- [Starlark in Go](https://github.com/google/starlark-go): The official Starlark interpreter in Go, created by Google.
83+
- [Starlight](https://github.com/starlight-go/starlight): A well-known Go wrapper and data conversion tool between Go and Starlark.
84+
- [Starlight Enhanced](https://github.com/1set/starlight): A sophisticated fork of the original Starlight, with bug fixes and enhancement features.
85+
- [Starlib](https://github.com/qri-io/starlib): A collection of third-party libraries for Starlark.
86+
- [Starlet](https://github.com/1set/starlet): A Go wrapper that simplifies usage, offers data conversion, libraries and extensions for Starlark.
87+
88+
We thank the authors and contributors of these projects for their excellent works 🎉

ctor.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"sync"
99
"time"
1010

11-
"bitbucket.org/ai69/amoy"
1211
"github.com/1set/starlet"
1312
"github.com/1set/starlet/dataconv"
1413
libhttp "github.com/1set/starlet/lib/http"
@@ -36,6 +35,7 @@ type Starbox struct {
3635
loadMods starlet.ModuleLoaderMap
3736
scriptMods map[string]string
3837
modFS fs.FS
38+
modNames []string
3939
}
4040

4141
// New creates a new Starbox instance with default settings.
@@ -51,7 +51,7 @@ func newStarMachine(name string) *starlet.Machine {
5151
// m.SetOutputConversionEnabled(true)
5252
m.SetPrintFunc(func(thread *starlark.Thread, msg string) {
5353
prefix := fmt.Sprintf("[⭐|%s](%s)", name, time.Now().UTC().Format(`15:04:05.000`))
54-
amoy.Eprintln(prefix, msg)
54+
eprintln(prefix, msg)
5555
})
5656
return m
5757
}
@@ -63,6 +63,9 @@ func (s *Starbox) String() string {
6363

6464
// GetMachine returns the underlying starlet.Machine instance.
6565
func (s *Starbox) GetMachine() *starlet.Machine {
66+
s.mu.RLock()
67+
defer s.mu.RUnlock()
68+
6669
return s.mac
6770
}
6871

@@ -79,6 +82,14 @@ func (s *Starbox) GetSteps() uint64 {
7982
return 0
8083
}
8184

85+
// GetModuleNames returns the names of the modules loaded after execution.
86+
func (s *Starbox) GetModuleNames() []string {
87+
s.mu.RLock()
88+
defer s.mu.RUnlock()
89+
90+
return s.modNames
91+
}
92+
8293
// SetStructTag sets the custom tag of Go struct fields for Starlark.
8394
// It panics if called after execution.
8495
func (s *Starbox) SetStructTag(tag string) {
@@ -316,6 +327,7 @@ func (s *Starbox) AddStructData(structName string, structData starlark.StringDic
316327

317328
// AddModuleScript creates a module with given module script in virtual filesystem, and adds it to the preload and lazyload registry.
318329
// The given module script can be accessed in script via load("module_name", "key1") or load("module_name.star", "key1") if module name has no ".star" suffix.
330+
// All the module scripts added by this method would be overridden by SetFS() if it's not nil.
319331
// It panics if called after execution.
320332
func (s *Starbox) AddModuleScript(moduleName, moduleScript string) {
321333
s.mu.Lock()

ctor_test.go

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ package starbox_test
33
import (
44
"encoding/json"
55
"fmt"
6+
"reflect"
67
"strings"
78
"testing"
89

9-
"bitbucket.org/ai69/amoy"
1010
"github.com/1set/starbox"
1111
"github.com/1set/starlet"
1212
"github.com/1set/starlet/dataconv"
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
var (
18-
hereDoc = amoy.HereDocf
18+
hereDoc = starbox.HereDocf
1919
noopPrint = func(thread *starlark.Thread, msg string) {
2020
return
2121
}
@@ -159,6 +159,8 @@ func TestSetFS(t *testing.T) {
159159
out, err := b.Run(hereDoc(`
160160
load("test.star", "a", "b")
161161
c = a + b
162+
print(__modules__)
163+
m = len(__modules__)
162164
`))
163165
if err != nil {
164166
t.Error(err)
@@ -168,14 +170,18 @@ func TestSetFS(t *testing.T) {
168170
t.Error("expect not nil, got nil")
169171
return
170172
}
171-
if len(out) != 1 {
172-
t.Errorf("expect 1, got %d", len(out))
173+
if len(out) != 2 {
174+
t.Errorf("expect 2, got %d", len(out))
173175
return
174176
}
175177
if es := int64(30); out["c"] != es {
176178
t.Errorf("expect %d, got %v", es, out["c"])
177179
return
178180
}
181+
if es := int64(0); out["m"] != es {
182+
t.Errorf("expect %d, got %v", es, out["m"])
183+
return
184+
}
179185

180186
// rerun the script with the same virtual filesystem
181187
out, err = b.Run(hereDoc(`
@@ -262,11 +268,12 @@ func TestSetModuleSet(t *testing.T) {
262268
// check for existing modules
263269
for _, m := range tt.hasMod {
264270
b := getBox()
265-
_, err := b.Run(hereDoc(fmt.Sprintf(`print(type(%s))`, m)))
271+
res, err := b.Run(hereDoc(fmt.Sprintf(`print(type(%s)); m = __modules__`, m)))
266272
if err != nil {
267273
t.Errorf("expect nil for existing module %q, got %v", m, err)
268274
return
269275
}
276+
t.Logf("{%s} modules: %v", tt.setName, res["m"])
270277
}
271278

272279
// check for non-existing modules
@@ -426,27 +433,32 @@ func TestAddBuiltin(t *testing.T) {
426433
// 4. Check the output to see if the named modules are present.
427434
func TestAddNamedModules(t *testing.T) {
428435
b := starbox.New("test")
436+
b.AddNamedModules("runtime")
429437
b.AddNamedModules("base64")
430438
b.AddNamedModules("runtime")
431439
out, err := b.Run(hereDoc(`
432440
s = base64.encode('Aloha!')
433441
t = type(runtime.pid)
442+
m = __modules__
434443
`))
435444
if err != nil {
436445
t.Error(err)
437446
}
438447
if out == nil {
439448
t.Error("expect not nil, got nil")
440449
}
441-
if len(out) != 2 {
442-
t.Errorf("expect 2, got %d", len(out))
450+
if len(out) != 3 {
451+
t.Errorf("expect 3, got %d", len(out))
443452
}
444453
if es := `QWxvaGEh`; out["s"] != es {
445454
t.Errorf("expect %q, got %v", es, out["s"])
446455
}
447456
if es := `int`; out["t"] != es {
448457
t.Errorf("expect %q, got %v", es, out["t"])
449458
}
459+
if es := []interface{}{"base64", "runtime"}; !reflect.DeepEqual(out["m"].([]interface{}), es) {
460+
t.Errorf("expect %v, got %v", es, out["m"])
461+
}
450462
}
451463

452464
// TestAddModuleLoader tests the following:
@@ -482,6 +494,7 @@ func TestAddModuleLoader(t *testing.T) {
482494
script string
483495
want int64
484496
}{
497+
{`print(__modules__); c = len(__modules__)`, 2},
485498
{`c = shift(a=10, b=4) + num`, 265},
486499
{`load("mine", "shift", "num"); c = shift(a=10, b=5) * num`, 32500},
487500
{`c = less.plus(a=10, b=4) + less.num + num`, 314},
@@ -524,6 +537,7 @@ func TestAddModuleData(t *testing.T) {
524537
script string
525538
want int64
526539
}{
540+
{`print(__modules__); c = len(__modules__)`, 1},
527541
{`c = data.a + data.b`, 30},
528542
{`load("data", "a", "b"); c = a * b`, 200},
529543
{`load("data", "a", "b"); c = data.c * (a+b)`, 9000},
@@ -569,6 +583,7 @@ func TestAddModuleFunctions(t *testing.T) {
569583
script string
570584
want int64
571585
}{
586+
{`print(__modules__); c = len(__modules__)`, 1},
572587
{`c = data.shift(a=10, b=4) + 100`, 267},
573588
{`load("data", "shift"); c = shift(a=10, b=5) * 10`, 3270},
574589
{`c = int(str(data.shift) == '<built-in function data.shift>')`, 1},
@@ -616,6 +631,7 @@ func TestAddStructData(t *testing.T) {
616631
script string
617632
want int64
618633
}{
634+
{`print(__modules__); c = len(__modules__)`, 1},
619635
{`c = data.A + data.B`, 30},
620636
{`c = data.A * data.B`, 200},
621637
{`c = data.C * (data.A + data.B)`, 9000},
@@ -663,6 +679,7 @@ func TestAddStructFunctions(t *testing.T) {
663679
script string
664680
want int64
665681
}{
682+
{`print(__modules__); c = len(__modules__)`, 1},
666683
{`c = data.shift(a=10, b=4) + 100`, 267},
667684
{`load("data", "shift"); c = shift(a=10, b=5) * 10`, 3270},
668685
{`c = int(str(data.shift) == '<built-in function data.shift>')`, 1},
@@ -707,6 +724,7 @@ func TestAddModuleScript(t *testing.T) {
707724
script string
708725
want int64
709726
}{
727+
{`print(__modules__); c = len(__modules__)`, 1},
710728
{`load("data.star", "a", "b"); c = a * b`, 200},
711729
{`load("data", "shift"); c = shift(2, 10)`, 2058},
712730
}
@@ -730,3 +748,53 @@ func TestAddModuleScript(t *testing.T) {
730748
})
731749
}
732750
}
751+
752+
// TestAddNamedModuleAndModuleScript tests the following:
753+
// 1. Create a new Starbox instance.
754+
// 2. Add named modules and module script.
755+
// 3. Run a script that uses function from the named modules and module script.
756+
// 4. Check the output to see if the named modules and module script conflict.
757+
func TestAddNamedModuleAndModuleScript(t *testing.T) {
758+
b := starbox.New("test")
759+
b.AddNamedModules("base64")
760+
b.AddNamedModules("csv")
761+
b.AddNamedModules("runtime")
762+
b.AddModuleScript("runtime", hereDoc(`
763+
pid = "ABC"
764+
`))
765+
out, err := b.Run(hereDoc(`
766+
v1 = runtime.pid # builtin
767+
print("v1[b]", type(v1), v1)
768+
769+
load("runtime", p2="pid") # builtin
770+
v2 = p2
771+
print("v2[b]", type(v2), v2)
772+
773+
load("runtime.star", p3="pid") # script
774+
v3 = p3
775+
print("v3[s]", type(v3), v3)
776+
777+
s = " ".join([type(v1), type(v2), type(v3)])
778+
m = __modules__
779+
print(__modules__)
780+
`))
781+
if err != nil {
782+
t.Error(err)
783+
}
784+
if out == nil {
785+
t.Error("expect not nil, got nil")
786+
}
787+
if len(out) != 5 {
788+
t.Errorf("expect 5, got %d", len(out))
789+
}
790+
if es := `int int string`; out["s"] != es {
791+
t.Errorf("expect %q, got %v", es, out["s"])
792+
}
793+
if es := []interface{}{"base64", "csv", "runtime", "runtime.star"}; !reflect.DeepEqual(out["m"].([]interface{}), es) {
794+
t.Errorf("expect %v, got %v", es, out["m"])
795+
}
796+
if em := []string{"base64", "csv", "runtime", "runtime.star"}; !reflect.DeepEqual(em, b.GetModuleNames()) {
797+
t.Errorf("expect %v, got %v", em, b.GetModuleNames())
798+
return
799+
}
800+
}

0 commit comments

Comments
 (0)