/
nickolasfox
/
kek
Обзор
Документация
Войти
/
nickolasfox
/
kek
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
pkg/plugins/plugin.go
176 строк
5 KB
Nickolas Fox
Fix running sub applications that demand environment variables
12 апр 2024, 19:47
12 апр 2024, 19:47
5c72dd5
Код
Авторство
О чём код?
package plugins import ( "bytes" "errors" "os" "os/exec" "github.com/spf13/cobra" "gitverse.ru/nickolasfox/kek/pkg/tools" ) // Exported errors. var ( ErrCommandIsExpected = errors.New("command should not be blank") ErrUnsupportedAppType = errors.New("unsupported application type") // envDefaults is a stub where extended environment variables are placed. envDefaults = []string{ "KEK=demo", } ) // PluginCompleteFunc runs completion for the specified plugin. type PluginCompleteFunc func(cmd *cobra.Command, args []string) (err error) // Plugin is a simple plugin interface for running not only `prefix-<app>` // compatible scripts and executables, but also write simple solutions. type Plugin struct { Name string `json:"name"` Command []string `json:"command"` Version string `json:"version"` Completion PluginCompletion `json:"completion"` Description string `json:"description"` // Complete runs completion routines for the specific plugin. Complete PluginCompleteFunc `json:"-"` // isValid sets if plugin is valid. // TODO: add validation gate for loading plugins. isValid bool `json:"-"` // isManifested means that plugin/application was represented over // UserConfigDir/$app/plugin/manifest.yaml configuration. isManifested bool `json:"-"` } // PluginCompletion keeps completion related settings for the plugin type PluginCompletion struct { Enabled bool `json:"enabled"` Command []string `json:"command"` } // Validate runs internal validation process for plugin, returns err if plugin is invalid. func (p *Plugin) Validate() (err error) { if len(p.Command) == 0 { err = ErrCommandIsExpected } if err == nil { p.isValid = true } return err } // IsValid designates if plugin is valid. func (p *Plugin) IsValid() bool { return p.isValid } // loadManifest runs additional helpers for the plugin like: // - Identify executable for its further running. func (p *Plugin) loadManifest() { if p.isManifested { p.Command[0] = tools.PopExecutable(p.Command[0]) } // Set defaults if p.Complete == nil { p.Complete = p.complete } } func (p *Plugin) completionApp() (app string) { app = p.Command[0] if p.Completion.Enabled { app = p.Command[0] if p.Completion.Command != nil { app = p.Completion.Command[0] } } return } // environ returns environment variables of the current process with extended // entries of envDefaults. func (p *Plugin) environ() []string { environ := os.Environ() environ = append(environ, envDefaults...) return environ } func (p *Plugin) run(cmd *cobra.Command, command string, args ...string) error { comm := exec.Command(command, args...) comm.Stdin = cmd.InOrStdin() comm.Stdout = cmd.OutOrStdout() comm.Stderr = cmd.OutOrStderr() comm.Env = p.environ() return comm.Run() } // Complete runs completion for target plugin. func (p *Plugin) complete(cmd *cobra.Command, args []string) (err error) { app := p.completionApp() var completeArgs []string if len(p.Completion.Command) > 0 { completeArgs = make([]string, 0, len(p.Completion.Command)+len(args)) // +-1 completeArgs = append(completeArgs, p.Completion.Command[1:]...) completeArgs = append(completeArgs, args[1:]...) } else { completeArgs = make([]string, 0, len(args)) // +-1 completeArgs = append(completeArgs, cobra.ShellCompRequestCmd) completeArgs = append(completeArgs, args[1:]...) } err = p.run(cmd, app, completeArgs...) // silence command root completion (since it should not have anything, including // debug prints) noOut := &bytes.Buffer{} cmd.Root().SetOut(noOut) cmd.Root().SetErr(noOut) return } // would work on linux, mac (it's required also adapt windows minigw for it) func (p *Plugin) script(cmd *cobra.Command, args []string) (err error) { var ( executable string prefixArgs []string ) script := p.Command[0] if executable, prefixArgs, err = tools.ShellExec(script); err == nil { allArgs := make([]string, 0, len(p.Command)-1+len(prefixArgs)+len(args)) allArgs = append(allArgs, prefixArgs...) allArgs = append(allArgs, script) allArgs = append(allArgs, args...) err = p.run(cmd, executable, allArgs...) } return } func (p *Plugin) execute(cmd *cobra.Command, args []string) (err error) { executable := p.Command[0] allArgs := make([]string, 0, len(p.Command)-1+len(args)) if len(p.Command) > 1 { allArgs = append(allArgs, p.Command[1:]...) } allArgs = append(allArgs, args...) return p.run(cmd, executable, allArgs...) } // Execute plugin func (p *Plugin) Execute(cmd *cobra.Command, args []string) (err error) { app := p.Command[0] switch tools.AppType(app) { case tools.Executable: return p.execute(cmd, args) case tools.Script: return p.script(cmd, args) default: return ErrUnsupportedAppType } }