1
0
mirror of https://github.com/lxc/incus.git synced 2026-02-05 09:46:19 +01:00

shared/scriptlet: Move scriptlet utils to shared

Signed-off-by: Max Asnaashari <max.asna@futurfusion.io>
This commit is contained in:
Max Asnaashari
2025-08-08 15:49:03 -07:00
parent 7c42db4ebf
commit cb8cc27ab5
3 changed files with 53 additions and 29 deletions

View File

@@ -1,4 +1,4 @@
package marshal
package scriptlet
import (
"fmt"
@@ -16,25 +16,31 @@ type starlarkObject struct {
typeName string
}
// Type is a starlark object type.
func (s *starlarkObject) Type() string {
return s.typeName
}
// String is a starlark object string.
func (s *starlarkObject) String() string {
return s.d.String()
}
// Freeze freezes the starlark object.
func (s *starlarkObject) Freeze() {
}
// Hash returns a hash of the starlark object.
func (s *starlarkObject) Hash() (uint32, error) {
return 0, fmt.Errorf("Unhashable type %s", s.Type())
}
// Truth returns whether the starlark object is true.
func (s *starlarkObject) Truth() starlark.Bool {
return starlark.True
}
// AttrNames returns the attribute names of the starlark object.
func (s *starlarkObject) AttrNames() []string {
keys := s.d.Keys()
keyNames := make([]string, 0, len(keys))
@@ -45,6 +51,7 @@ func (s *starlarkObject) AttrNames() []string {
return keyNames
}
// Attr gets an attribute of the starlark object.
func (s *starlarkObject) Attr(name string) (starlark.Value, error) {
field, found, err := s.d.Get(starlark.String(name))
if err != nil {

View File

@@ -1,4 +1,4 @@
package marshal
package scriptlet
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package load
package scriptlet
import (
"errors"
@@ -6,11 +6,18 @@ import (
"slices"
"sort"
"strings"
"sync"
"go.starlark.net/starlark"
"go.starlark.net/syntax"
)
// Loader holds the programs for the scriptlet.
type Loader struct {
programsMu sync.Mutex
programs map[string]*starlark.Program
}
// argMismatch represents mismatching arguments in a function.
type argMismatch struct {
gotten []string
@@ -23,11 +30,19 @@ type scriptletFunction struct {
optional bool
}
// declaration is a type alias to make scriptlet declaration easier.
type declaration = map[scriptletFunction][]string
// Declaration is a type alias to make scriptlet declaration easier.
type Declaration = map[scriptletFunction][]string
// compile compiles a scriptlet.
func compile(programName string, src string, preDeclared []string) (*starlark.Program, error) {
// NewLoader creates a new Loader.
func NewLoader() *Loader {
return &Loader{
programsMu: sync.Mutex{},
programs: map[string]*starlark.Program{},
}
}
// Compile compiles a scriptlet.
func Compile(programName string, src string, preDeclared []string) (*starlark.Program, error) {
isPreDeclared := func(name string) bool {
return slices.Contains(preDeclared, name)
}
@@ -45,13 +60,13 @@ func compile(programName string, src string, preDeclared []string) (*starlark.Pr
return mod, nil
}
// required is a convenience wrapper declaring a required function.
func required(name string) scriptletFunction {
// Required is a convenience wrapper declaring a required function.
func Required(name string) scriptletFunction {
return scriptletFunction{name: name, optional: false}
}
// required is a convenience wrapper declaring an optional function.
func optional(name string) scriptletFunction {
// Optional is a convenience wrapper declaring an optional function.
func Optional(name string) scriptletFunction {
return scriptletFunction{name: name, optional: true}
}
@@ -105,8 +120,8 @@ func validateFunction(funv starlark.Value, requiredArgs []string) (bool, bool, *
return false, false, nil
}
// validate validates a scriptlet by compiling it and checking the presence of required and optional functions.
func validate(compiler func(string, string) (*starlark.Program, error), programName string, src string, scriptletFunctions declaration) error {
// Validate validates a scriptlet by compiling it and checking the presence of required and optional functions.
func Validate(compiler func(string, string) (*starlark.Program, error), programName string, src string, scriptletFunctions Declaration) error {
// Try to compile the program.
prog, err := compiler(programName, src)
if err != nil {
@@ -152,11 +167,13 @@ func validate(compiler func(string, string) (*starlark.Program, error), programN
// String builder to format pretty error messages.
appendToError := func(text string) {
var link string
if sentences == 0 {
switch sentences {
case 0:
link = ""
} else if sentences == 1 {
case 1:
link = "; additionally, "
} else {
default:
link = "; finally, "
}
@@ -194,31 +211,31 @@ func validate(compiler func(string, string) (*starlark.Program, error), programN
return errors.New(errorText)
}
// set compiles a scriptlet into memory. If empty src is provided the current program is deleted.
func set(compiler func(string, string) (*starlark.Program, error), programName string, src string) error {
// Set compiles a scriptlet into memory. If empty src is provided the current program is deleted.
func (l *Loader) Set(compiler func(string, string) (*starlark.Program, error), programName string, src string) error {
if src == "" {
programsMu.Lock()
delete(programs, programName)
programsMu.Unlock()
l.programsMu.Lock()
delete(l.programs, programName)
l.programsMu.Unlock()
} else {
prog, err := compiler(programName, src)
if err != nil {
return err
}
programsMu.Lock()
programs[programName] = prog
programsMu.Unlock()
l.programsMu.Lock()
l.programs[programName] = prog
l.programsMu.Unlock()
}
return nil
}
// program returns a precompiled scriptlet program.
func program(name string, programName string) (*starlark.Program, *starlark.Thread, error) {
programsMu.Lock()
prog, found := programs[programName]
programsMu.Unlock()
// Program returns a precompiled scriptlet program.
func (l *Loader) Program(name string, programName string) (*starlark.Program, *starlark.Thread, error) {
l.programsMu.Lock()
prog, found := l.programs[programName]
l.programsMu.Unlock()
if !found {
return nil, nil, fmt.Errorf("%s scriptlet not loaded", name)
}