/
module.go
152 lines (125 loc) · 4.2 KB
/
module.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package runtime
import (
"errors"
"fmt"
"log"
"go.starlark.net/starlark"
"github.com/FuzzyMonkeyCo/monkey/pkg/modeler"
openapi3 "github.com/FuzzyMonkeyCo/monkey/pkg/modeler/openapiv3"
"github.com/FuzzyMonkeyCo/monkey/pkg/resetter"
"github.com/FuzzyMonkeyCo/monkey/pkg/resetter/shell"
"github.com/FuzzyMonkeyCo/monkey/pkg/tags"
)
const (
moduleBuiltins = 2
moduleModelers = 1
moduleResetters = 1
moduleAttrs = moduleBuiltins + moduleModelers + moduleResetters
)
type module struct {
attrs map[string]*starlark.Builtin
}
var _ starlark.HasAttrs = (*module)(nil)
func (rt *Runtime) newModule() (m *module) {
m = &module{
attrs: make(map[string]*starlark.Builtin, moduleAttrs),
}
modelMaker := func(modelerName string, maker modeler.Maker) *starlark.Builtin {
f := rt.modelMakerBuiltin(modelerName, maker)
b := starlark.NewBuiltin(modelerName, f)
return b.BindReceiver(m)
}
m.attrs["openapi3"] = modelMaker(openapi3.Name, openapi3.New)
resetterMaker := func(resetterName string, maker resetter.Maker) *starlark.Builtin {
f := rt.resetterMakerBuiltin(resetterName, maker)
b := starlark.NewBuiltin(resetterName, f)
return b.BindReceiver(m)
}
m.attrs["shell"] = resetterMaker(shell.Name, shell.New)
m.attrs["check"] = starlark.NewBuiltin("check", rt.bCheck).BindReceiver(m)
m.attrs["env"] = starlark.NewBuiltin("env", rt.bEnv).BindReceiver(m)
return
}
func (m *module) AttrNames() []string {
return []string{
"check",
"env",
"openapi3",
"shell",
}
}
func (m *module) Attr(name string) (starlark.Value, error) {
if v := m.attrs[name]; v != nil {
return v, nil
}
return nil, nil // no such method
}
func (m *module) String() string { return "monkey" }
func (m *module) Type() string { return "monkey" }
func (m *module) Freeze() {}
func (m *module) Truth() starlark.Bool { return true }
func (m *module) Hash() (uint32, error) { return 0, errors.New("unhashable type: monkey") }
type builtin func(th *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (ret starlark.Value, err error)
func (rt *Runtime) modelMakerBuiltin(modelerName string, maker modeler.Maker) builtin {
return func(th *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (ret starlark.Value, err error) {
log.Printf("[DBG] registering new %s model", modelerName)
ret = starlark.None
if len(args) != 0 {
err = fmt.Errorf("%s(...) does not take positional arguments, only named ones", b.Name())
log.Println("[ERR]", err)
return
}
var model modeler.Interface
if model, err = maker(kwargs); err != nil {
log.Println("[ERR]", b.Name(), err)
return
}
modelName := model.Name()
if err = tags.LegalName(modelName); err != nil {
log.Println("[ERR]", b.Name(), err)
return
}
if _, ok := rt.models[modelName]; ok {
err = fmt.Errorf("a model named %s already exists", modelName)
log.Println("[ERR]", err)
return
}
rt.models[modelName] = model
if len(rt.modelsNames) == 1 { // TODO: support >1 models
err = fmt.Errorf("cannot define model %s as another (%s) already exists", modelName, rt.modelsNames[0])
log.Println("[ERR]", err)
return
}
rt.modelsNames = append(rt.modelsNames, modelName)
return
}
}
func (rt *Runtime) resetterMakerBuiltin(resetterName string, maker resetter.Maker) builtin {
return func(th *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (ret starlark.Value, err error) {
log.Printf("[DBG] registering new %s resetter", resetterName)
ret = starlark.None
if len(args) != 0 {
err = fmt.Errorf("%s(...) does not take positional arguments, only named ones", b.Name())
log.Println("[ERR]", err)
return
}
var rsttr resetter.Interface
if rsttr, err = maker(kwargs); err != nil {
log.Println("[ERR]", b.Name(), err)
return
}
rsttrName := rsttr.Name()
if err = tags.LegalName(rsttrName); err != nil {
log.Println("[ERR]", b.Name(), err)
return
}
if _, ok := rt.resetters[rsttrName]; ok {
err = fmt.Errorf("a resetter named %s already exists", rsttrName)
log.Println("[ERR]", err)
return
}
rt.resetters[rsttrName] = rsttr
rt.resettersNames = append(rt.resettersNames, rsttrName)
return
}
}