| // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: |
| //go:build go1.24 |
| |
| package hooks |
| |
| import ( |
| "bytes" |
| "errors" |
| "fmt" |
| "strings" |
| "text/template" |
| |
| "github.com/spf13/cobra" |
| ) |
| |
| func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) { |
| out := hookTemplate |
| if strings.Contains(hookTemplate, "{{") { |
| // Message may be a template. |
| msgContext := commandInfo{cmd: cmd} |
| |
| tmpl, err := template.New("").Funcs(template.FuncMap{ |
| "command": msgContext.command, |
| "flagValue": msgContext.flagValue, |
| "argValue": msgContext.argValue, |
| |
| // kept for backward-compatibility with old templates. |
| "flag": func(_ any, flagName string) (string, error) { return msgContext.flagValue(flagName) }, |
| "arg": func(_ any, i int) (string, error) { return msgContext.argValue(i) }, |
| }).Parse(hookTemplate) |
| if err != nil { |
| return nil, err |
| } |
| var b bytes.Buffer |
| err = tmpl.Execute(&b, msgContext) |
| if err != nil { |
| return nil, err |
| } |
| out = b.String() |
| } |
| return strings.Split(out, "\n"), nil |
| } |
| |
| var ErrHookTemplateParse = errors.New("failed to parse hook template") |
| |
| // commandInfo provides info about the command for which the hook was invoked. |
| // It is used for templated hook-messages. |
| type commandInfo struct { |
| cmd *cobra.Command |
| } |
| |
| // Name returns the name of the (sub)command for which the hook was invoked. |
| // |
| // It's used for backward-compatibility with old templates. |
| func (c commandInfo) Name() string { |
| return c.command() |
| } |
| |
| // command returns the name of the (sub)command for which the hook was invoked. |
| func (c commandInfo) command() string { |
| if c.cmd == nil { |
| return "" |
| } |
| return c.cmd.Name() |
| } |
| |
| // flagValue returns the value that was set for the given flag when the hook was invoked. |
| func (c commandInfo) flagValue(flagName string) (string, error) { |
| if c.cmd == nil { |
| return "", fmt.Errorf("%w: flagValue: cmd is nil", ErrHookTemplateParse) |
| } |
| f := c.cmd.Flag(flagName) |
| if f == nil { |
| return "", fmt.Errorf("%w: flagValue: no flags found", ErrHookTemplateParse) |
| } |
| return f.Value.String(), nil |
| } |
| |
| // argValue returns the value of the nth argument. |
| func (c commandInfo) argValue(n int) (string, error) { |
| if c.cmd == nil { |
| return "", fmt.Errorf("%w: arg: cmd is nil", ErrHookTemplateParse) |
| } |
| flags := c.cmd.Flags() |
| v := flags.Arg(n) |
| if v == "" && n >= flags.NArg() { |
| return "", fmt.Errorf("%w: arg: %dth argument not set", ErrHookTemplateParse, n) |
| } |
| return v, nil |
| } |