Skip to content

Commit 3c97f94

Browse files
authored
convert compilers to use functional options (#17)
* Refactor compiler creation for machines to use functional options * Add machine-specific options and refactor evaluator creation for Extism, Risor, and Starlark * Refactor machine-specific options: move to respective packages and update evaluator creation * Remove machine-specific options and update type conversions to use 'any' * rename options to compilerOptions * lint-fix * remove extra logger config * move the common data provider setup code to a private function
1 parent e10b776 commit 3c97f94

29 files changed

+1751
-541
lines changed

engine/options/options.go

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ type Config struct {
2020
dataProvider data.Provider
2121
// Loader for the script content
2222
loader loader.Loader
23-
// Machine-specific options
24-
compilerOptions any
2523
}
2624

2725
// Option is a function that modifies Config
@@ -121,12 +119,7 @@ func (c *Config) GetLoader() loader.Loader {
121119
return c.loader
122120
}
123121

124-
// GetCompilerOptions returns the machine-specific compiler options
125-
func (c *Config) GetCompilerOptions() any {
126-
return c.compilerOptions
127-
}
128-
129-
// SetCompilerOptions sets the machine-specific compiler options
130-
func (c *Config) SetCompilerOptions(options any) {
131-
c.compilerOptions = options
122+
// SetLoader sets the loader
123+
func (c *Config) SetLoader(l loader.Loader) {
124+
c.loader = l
132125
}

engine/options/options_test.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,19 +108,16 @@ func TestConfigGetters(t *testing.T) {
108108
testHandler := slog.NewTextHandler(os.Stdout, nil)
109109
testDataProvider := data.NewStaticProvider(map[string]any{"test": "value"})
110110
testLoader := NewMockLoader()
111-
testCompilerOpts := "test-options"
112111

113112
cfg := &Config{
114-
handler: testHandler,
115-
machineType: types.Starlark,
116-
dataProvider: testDataProvider,
117-
loader: testLoader,
118-
compilerOptions: testCompilerOpts,
113+
handler: testHandler,
114+
machineType: types.Starlark,
115+
dataProvider: testDataProvider,
116+
loader: testLoader,
119117
}
120118

121119
require.Equal(t, testHandler, cfg.GetHandler())
122120
require.Equal(t, types.Starlark, cfg.GetMachineType())
123121
require.Equal(t, testDataProvider, cfg.GetDataProvider())
124122
require.Equal(t, testLoader, cfg.GetLoader())
125-
require.Equal(t, testCompilerOpts, cfg.GetCompilerOptions())
126123
}

machines/extism/compiler.go

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,55 @@ type Compiler struct {
2323
logger *slog.Logger
2424
}
2525

26-
type CompilerOptions interface {
27-
GetEntryPointName() string
28-
}
26+
// NewCompiler creates a new Extism WASM Compiler instance with the provided options.
27+
func NewCompiler(opts ...CompilerOption) (*Compiler, error) {
28+
// Initialize config with defaults
29+
cfg := &compilerOptions{}
30+
applyDefaults(cfg)
31+
32+
// Apply all options
33+
for _, opt := range opts {
34+
if err := opt(cfg); err != nil {
35+
return nil, fmt.Errorf("error applying compiler option: %w", err)
36+
}
37+
}
2938

30-
// NewCompiler creates a new Extism WASM Compiler instance. External config of the compiler not
31-
// currently supported.
32-
func NewCompiler(handler slog.Handler, compilerOptions CompilerOptions) *Compiler {
33-
handler, logger := helpers.SetupLogger(handler, "extism", "Compiler")
39+
// Validate the configuration
40+
if err := validate(cfg); err != nil {
41+
return nil, fmt.Errorf("invalid compiler configuration: %w", err)
42+
}
3443

35-
entryPointName := compilerOptions.GetEntryPointName()
36-
if entryPointName == "" {
37-
entryPointName = defaultEntryPoint
44+
var handler slog.Handler
45+
var logger *slog.Logger
46+
47+
// Set up logging based on provided options
48+
if cfg.Logger != nil {
49+
// User provided a custom logger
50+
logger = cfg.Logger
51+
handler = logger.Handler()
52+
} else {
53+
// User provided a handler or we're using the default
54+
handler, logger = helpers.SetupLogger(cfg.LogHandler, "extism", "Compiler")
3855
}
3956

40-
var funcName atomic.Value
41-
funcName.Store(entryPointName)
57+
// Set up entry point name in atomic.Value
58+
var entryPointAtomicValue atomic.Value
59+
entryPointAtomicValue.Store(cfg.EntryPoint)
60+
61+
// Create compile options from config
62+
compileOpts := &compileOptions{
63+
EnableWASI: cfg.EnableWASI,
64+
RuntimeConfig: cfg.RuntimeConfig,
65+
HostFunctions: cfg.HostFunctions,
66+
}
4267

4368
return &Compiler{
44-
entryPointName: funcName,
69+
entryPointName: entryPointAtomicValue,
4570
ctx: context.Background(),
46-
options: withDefaultCompileOptions(),
71+
options: compileOpts,
4772
logHandler: handler,
4873
logger: logger,
49-
}
74+
}, nil
5075
}
5176

5277
func (c *Compiler) String() string {

machines/extism/compilerOptions.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package extism
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
"os"
7+
8+
extismSDK "github.com/extism/go-sdk"
9+
"github.com/tetratelabs/wazero"
10+
)
11+
12+
// compilerOptions holds the configuration for the Extism compiler
13+
type compilerOptions struct {
14+
EntryPoint string
15+
LogHandler slog.Handler
16+
Logger *slog.Logger
17+
EnableWASI bool
18+
RuntimeConfig wazero.RuntimeConfig
19+
HostFunctions []extismSDK.HostFunction
20+
}
21+
22+
// CompilerOption is a function that configures a compilerOptions instance
23+
type CompilerOption func(*compilerOptions) error
24+
25+
// WithEntryPoint creates an option to set the entry point for Extism WASM modules
26+
func WithEntryPoint(entryPoint string) CompilerOption {
27+
return func(cfg *compilerOptions) error {
28+
if entryPoint == "" {
29+
return fmt.Errorf("entry point cannot be empty")
30+
}
31+
cfg.EntryPoint = entryPoint
32+
return nil
33+
}
34+
}
35+
36+
// WithLogHandler creates an option to set the log handler for Extism compiler.
37+
// This is the preferred option for logging configuration as it provides
38+
// more flexibility through the slog.Handler interface.
39+
func WithLogHandler(handler slog.Handler) CompilerOption {
40+
return func(cfg *compilerOptions) error {
41+
if handler == nil {
42+
return fmt.Errorf("log handler cannot be nil")
43+
}
44+
cfg.LogHandler = handler
45+
// Clear logger if handler is explicitly set
46+
cfg.Logger = nil
47+
return nil
48+
}
49+
}
50+
51+
// WithLogger creates an option to set a specific logger for Extism compiler.
52+
// This is less flexible than WithLogHandler but allows users to customize
53+
// their logging group configuration.
54+
func WithLogger(logger *slog.Logger) CompilerOption {
55+
return func(cfg *compilerOptions) error {
56+
if logger == nil {
57+
return fmt.Errorf("logger cannot be nil")
58+
}
59+
cfg.Logger = logger
60+
// Clear handler if logger is explicitly set
61+
cfg.LogHandler = nil
62+
return nil
63+
}
64+
}
65+
66+
// WithWASIEnabled creates an option to enable or disable WASI support
67+
func WithWASIEnabled(enabled bool) CompilerOption {
68+
return func(cfg *compilerOptions) error {
69+
cfg.EnableWASI = enabled
70+
return nil
71+
}
72+
}
73+
74+
// WithRuntimeConfig creates an option to set a custom wazero runtime configuration
75+
func WithRuntimeConfig(config wazero.RuntimeConfig) CompilerOption {
76+
return func(cfg *compilerOptions) error {
77+
if config == nil {
78+
return fmt.Errorf("runtime config cannot be nil")
79+
}
80+
cfg.RuntimeConfig = config
81+
return nil
82+
}
83+
}
84+
85+
// WithHostFunctions creates an option to set additional host functions
86+
func WithHostFunctions(funcs []extismSDK.HostFunction) CompilerOption {
87+
return func(cfg *compilerOptions) error {
88+
cfg.HostFunctions = funcs
89+
return nil
90+
}
91+
}
92+
93+
// applyDefaults sets the default values for a compilerConfig
94+
func applyDefaults(cfg *compilerOptions) {
95+
// Default to stderr for logging if neither handler nor logger specified
96+
if cfg.LogHandler == nil && cfg.Logger == nil {
97+
cfg.LogHandler = slog.NewTextHandler(os.Stderr, nil)
98+
}
99+
100+
// Default entry point
101+
if cfg.EntryPoint == "" {
102+
cfg.EntryPoint = defaultEntryPoint
103+
}
104+
105+
// Default WASI setting
106+
cfg.EnableWASI = true
107+
108+
// Default runtime config
109+
if cfg.RuntimeConfig == nil {
110+
cfg.RuntimeConfig = wazero.NewRuntimeConfig()
111+
}
112+
113+
// Default to empty host functions
114+
if cfg.HostFunctions == nil {
115+
cfg.HostFunctions = []extismSDK.HostFunction{}
116+
}
117+
}
118+
119+
// validate checks if the configuration is valid
120+
func validate(cfg *compilerOptions) error {
121+
// Ensure we have either a logger or a handler
122+
if cfg.LogHandler == nil && cfg.Logger == nil {
123+
return fmt.Errorf("either log handler or logger must be specified")
124+
}
125+
126+
// Entry point must be non-empty
127+
if cfg.EntryPoint == "" {
128+
return fmt.Errorf("entry point must be specified")
129+
}
130+
131+
// Runtime config cannot be nil
132+
if cfg.RuntimeConfig == nil {
133+
return fmt.Errorf("runtime config cannot be nil")
134+
}
135+
136+
return nil
137+
}

0 commit comments

Comments
 (0)