/* * Copyright (C) 2021 Arsen Musayelyan * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package main import ( "fmt" "github.com/traefik/yaegi/interp" "github.com/traefik/yaegi/stdlib" "github.com/traefik/yaegi/stdlib/unrestricted" "io/fs" "path/filepath" ) // Create type for plugin functions type pluginFunc func(string, map[string]interface{}) // Initialize all available plugins func initPlugins(gopath string) map[string]pluginFunc { log.Info().Msg("Initializing plugins") out := map[string]pluginFunc{} // Create new yaegi Go interpreter with appropriate GOPATH i := interp.New(interp.Options{GoPath: gopath}) // Use standard library symbols i.Use(stdlib.Symbols) // Use unrestricted symbols (os/exec, syscall, etc.) i.Use(unrestricted.Symbols) // Use custom package i.Use(tridentSymbols) // Walk plugin directory err := filepath.WalkDir(filepath.Join(execDir, "plugins"), func(path string, d fs.DirEntry, err error) error { // If error encountered, return if err != nil { return err } // If current path is not a directory or it is the plugin root if !d.IsDir() || d.Name() == "plugins" { return nil } // Get name of plugin from directory name pluginName := filepath.Base(path) // IF plugin already exists, return error if _, ok := out[pluginName]; ok { return fmt.Errorf("plugin %s has already been initialized", pluginName) } // If verbose, log which plugin is being initialized if *verbose { log.Debug().Str("plugin", pluginName).Msg("Initializing plugin") } // Walk directory of specific plugin err = filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { // If error encountered, return if err != nil { return err } // If file is not go source, skip if filepath.Ext(path) != ".go" { return nil } // Evaluate go file _, err = i.EvalPath(path) if err != nil { return err } return nil }) // If error encountered walking plugin, return if err != nil { return err } // Get RunPlugin symbol from current plugin v, err := i.Eval(fmt.Sprintf("%s.RunPlugin", pluginName)) if err != nil { return err } // Assert RunPlugin symbol as a plugin function and add it to out map out[pluginName] = v.Interface().(func(string, map[string]interface{})) return nil }) // If error occurred walking directory, log fatally if err != nil { log.Fatal().Err(err).Msg("Error initializing plugins") } return out }