diff --git a/cmd/helm/plugin.go b/cmd/helm/plugin.go index 8e1044f54..f6c12fb9d 100644 --- a/cmd/helm/plugin.go +++ b/cmd/helm/plugin.go @@ -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) diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 1399b7116..cdd024805 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -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 ​-.