// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // plugin.go package expr import ( "fmt" "os" "plugin" "strings" ) var pluginRegister map[string]*plugin.Plugin func registerPlugin(name string, p *plugin.Plugin) (err error) { if pluginExists(name) { err = fmt.Errorf("plugin %q already loaded", name) } else { pluginRegister[name] = p } return } func pluginExists(name string) (exists bool) { _, exists = pluginRegister[name] return } func makePluginName(name string) (decorated string) { var template string if execName, err := os.Executable(); err != nil || !strings.Contains(execName, "debug") { template = "expr-%s-plugin.so" } else { template = "expr-%s-plugin.so.debug" } decorated = fmt.Sprintf(template, name) return } func importPlugin( /*ctx ExprContext,*/ dirList []string, name string) (err error) { var filePath string var p *plugin.Plugin var sym plugin.Symbol var moduleName string var importFunc func(ExprContext) var ok bool decoratedName := makePluginName(name) if filePath, err = makeFilepath(decoratedName, dirList); err != nil { return } if p, err = plugin.Open(filePath); err != nil { return } if sym, err = p.Lookup("MODULE_NAME"); err != nil { return } if moduleName = *sym.(*string); moduleName == "" { err = fmt.Errorf("plugin %q does not provide a valid module name", decoratedName) return } if sym, err = p.Lookup("DEPENDENCIES"); err != nil { return } if deps := *sym.(*[]string); len(deps) > 0 { // var count int if err = loadModules(dirList, deps); err != nil { return } } if sym, err = p.Lookup("ImportFuncs"); err != nil { return } if importFunc, ok = sym.(func(ExprContext)); !ok { err = fmt.Errorf("plugin %q does not provide a valid import function", decoratedName) return } registerPlugin(moduleName, p) importFunc(globalCtx) return } func loadModules(dirList []string, moduleNames []string) (err error) { for _, name := range moduleNames { if err1 := importPlugin(dirList, name); err1 != nil { if !ImportInContext(name) { err = err1 break } } } return } func init() { pluginRegister = make(map[string]*plugin.Plugin) }