2023-07-20 11:25:36 -04:00
|
|
|
package hooks
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
2024-04-15 06:03:20 -04:00
|
|
|
"strings"
|
2023-07-20 11:25:36 -04:00
|
|
|
"text/template"
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
|
|
|
type HookType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
NextSteps = iota
|
|
|
|
)
|
|
|
|
|
|
|
|
// HookMessage represents a plugin hook response. Plugins
|
|
|
|
// declaring support for CLI hooks need to print a json
|
|
|
|
// representation of this type when their hook subcommand
|
|
|
|
// is invoked.
|
|
|
|
type HookMessage struct {
|
|
|
|
Type HookType
|
|
|
|
Template string
|
|
|
|
}
|
|
|
|
|
|
|
|
// TemplateReplaceSubcommandName returns a hook template string
|
|
|
|
// that will be replaced by the CLI subcommand being executed
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// "you ran the subcommand: " + TemplateReplaceSubcommandName()
|
|
|
|
//
|
|
|
|
// when being executed after the command:
|
|
|
|
// `docker run --name "my-container" alpine`
|
|
|
|
// will result in the message:
|
|
|
|
// `you ran the subcommand: run`
|
|
|
|
func TemplateReplaceSubcommandName() string {
|
|
|
|
return hookTemplateCommandName
|
|
|
|
}
|
|
|
|
|
|
|
|
// TemplateReplaceFlagValue returns a hook template string
|
|
|
|
// that will be replaced by the flags value.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// "you ran a container named: " + TemplateReplaceFlagValue("name")
|
|
|
|
//
|
|
|
|
// when being executed after the command:
|
|
|
|
// `docker run --name "my-container" alpine`
|
|
|
|
// will result in the message:
|
|
|
|
// `you ran a container named: my-container`
|
|
|
|
func TemplateReplaceFlagValue(flag string) string {
|
|
|
|
return fmt.Sprintf(hookTemplateFlagValue, flag)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TemplateReplaceArg takes an index i and returns a hook
|
|
|
|
// template string that the CLI will replace the template with
|
|
|
|
// the ith argument, after processing the passed flags.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// "run this image with `docker run " + TemplateReplaceArg(0) + "`"
|
|
|
|
//
|
|
|
|
// when being executed after the command:
|
|
|
|
// `docker pull alpine`
|
|
|
|
// will result in the message:
|
|
|
|
// "Run this image with `docker run alpine`"
|
|
|
|
func TemplateReplaceArg(i int) string {
|
|
|
|
return fmt.Sprintf(hookTemplateArg, strconv.Itoa(i))
|
|
|
|
}
|
|
|
|
|
2024-04-15 06:03:20 -04:00
|
|
|
func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) {
|
2023-07-20 11:25:36 -04:00
|
|
|
tmpl := template.New("").Funcs(commandFunctions)
|
|
|
|
tmpl, err := tmpl.Parse(hookTemplate)
|
|
|
|
if err != nil {
|
2024-04-15 06:03:20 -04:00
|
|
|
return nil, err
|
2023-07-20 11:25:36 -04:00
|
|
|
}
|
|
|
|
b := bytes.Buffer{}
|
|
|
|
err = tmpl.Execute(&b, cmd)
|
|
|
|
if err != nil {
|
2024-04-15 06:03:20 -04:00
|
|
|
return nil, err
|
2023-07-20 11:25:36 -04:00
|
|
|
}
|
2024-04-15 06:03:20 -04:00
|
|
|
return strings.Split(b.String(), "\n"), nil
|
2023-07-20 11:25:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
var ErrHookTemplateParse = errors.New("failed to parse hook template")
|
|
|
|
|
|
|
|
const (
|
|
|
|
hookTemplateCommandName = "{{.Name}}"
|
|
|
|
hookTemplateFlagValue = `{{flag . "%s"}}`
|
|
|
|
hookTemplateArg = "{{arg . %s}}"
|
|
|
|
)
|
|
|
|
|
|
|
|
var commandFunctions = template.FuncMap{
|
|
|
|
"flag": getFlagValue,
|
|
|
|
"arg": getArgValue,
|
|
|
|
}
|
|
|
|
|
|
|
|
func getFlagValue(cmd *cobra.Command, flag string) (string, error) {
|
|
|
|
cmdFlag := cmd.Flag(flag)
|
|
|
|
if cmdFlag == nil {
|
|
|
|
return "", ErrHookTemplateParse
|
|
|
|
}
|
|
|
|
return cmdFlag.Value.String(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getArgValue(cmd *cobra.Command, i int) (string, error) {
|
|
|
|
flags := cmd.Flags()
|
|
|
|
if flags == nil {
|
|
|
|
return "", ErrHookTemplateParse
|
|
|
|
}
|
|
|
|
return flags.Arg(i), nil
|
|
|
|
}
|