feat: plugin install platformHooks

Signed-off-by: Dima Brusilovsky <dimabru@gmail.com>
pull/10126/head
Dima Brusilovsky 3 years ago
parent 2fee08553f
commit da6294c069

@ -19,6 +19,8 @@ import (
"io"
"os"
"os/exec"
"runtime"
"strings"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -47,15 +49,22 @@ func newPluginCmd(out io.Writer) *cobra.Command {
// runHook will execute a plugin hook.
func runHook(p *plugin.Plugin, event string) error {
hook := p.Metadata.Hooks[event]
if hook == "" {
hookParts, hookErr := p.PrepareHook(event)
if len(hookParts) == 0 {
return nil
}
if hookErr != nil {
os.Stderr.WriteString(hookErr.Error())
return errors.Errorf("plugin hook %s exited with error", event)
}
hook := strings.Join(hookParts, " ")
prog := exec.Command("sh", "-c", hook)
// TODO make this work on windows
// I think its ... ¯\_(ツ)_/¯
// prog := exec.Command("cmd", "/C", p.Metadata.Hooks.Install())
var prog *exec.Cmd
if runtime.GOOS == "windows" {
prog = exec.Command("cmd", "/C", hook)
} else {
prog = exec.Command("sh", "-c", hook)
}
debug("running %s hook: %s", event, prog)

@ -50,6 +50,12 @@ type PlatformCommand struct {
Command string `json:"command"`
}
type PlatformHook struct {
OperatingSystem string `json:"os"`
Architecture string `json:"arch"`
Hooks Hooks `json:"hooks"`
}
// Metadata describes a plugin.
//
// This is the plugin equivalent of a chart.Metadata.
@ -92,7 +98,8 @@ type Metadata struct {
IgnoreFlags bool `json:"ignoreFlags"`
// Hooks are commands that will run on events.
Hooks Hooks
PlatformHook []PlatformHook `json:"platformHook"`
Hooks Hooks
// Downloaders field is used if the plugin supply downloader mechanism
// for special protocols.
@ -166,6 +173,51 @@ func (p *Plugin) PrepareCommand(extraArgs []string) (string, []string, error) {
return main, baseArgs, nil
}
// The following rules will apply to processing the Plugin.PlatformHook.Hooks:
// If hook name exists in platformHook, do the following:
// - If both OS and Arch match the current platform, search will stop and the command will be prepared for execution
// - If OS matches and there is no more specific match, the hook will be prepared for execution
// - If no OS/Arch match is found, return nil
func getPlatformHook(platformHooks []PlatformHook, event string) []string {
var hookCommand []string
eq := strings.EqualFold
for _, p := range platformHooks {
if hook, ok := p.Hooks[event]; ok {
if eq(p.OperatingSystem, runtime.GOOS) {
hookCommand = strings.Split(os.ExpandEnv(hook), " ")
}
if eq(p.OperatingSystem, runtime.GOOS) && eq(p.Architecture, runtime.GOARCH) {
return strings.Split(os.ExpandEnv(hook), " ")
}
}
}
return hookCommand
}
// PrepareHook takes a Plugin.PlatformHook.Hooks, a Plugin.Hooks and an event and will apply the following processing:
// - If platformHook is present, it will be searched first
// - If both OS and Arch match the current platform, search for required hook name. If exists, search will stop and the hook will be prepared for execution
// - If OS matches and there is no more specific match, the hook will be prepared for execution
// - If no OS/Arch match is found, the default hook will be prepared for execution
// - If no hook is present and no matches are found in platformHook, will exit with an error
//
// The result is suitable to pass to exec.Command.
func (p *Plugin) PrepareHook(event string) ([]string, error) {
var parts []string
platCmdLen := len(p.Metadata.PlatformHook)
if platCmdLen > 0 {
parts = getPlatformHook(p.Metadata.PlatformHook, event)
}
if platCmdLen == 0 || parts == nil {
parts = strings.Split(os.ExpandEnv(p.Metadata.Hooks[event]), " ")
}
if len(parts) == 0 || parts[0] == "" {
return nil, fmt.Errorf("no plugin hook is applicable")
}
return parts, nil
}
// validPluginName is a regular expression that validates plugin names.
//
// Plugin names can only contain the ASCII characters a-z, A-Z, 0-9, _ and -.

Loading…
Cancel
Save