github.1git.de/docker/cli@v26.1.3+incompatible/cli-plugins/hooks/template.go (about)

     1  package hooks
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  	"text/template"
    10  
    11  	"github.com/spf13/cobra"
    12  )
    13  
    14  type HookType int
    15  
    16  const (
    17  	NextSteps = iota
    18  )
    19  
    20  // HookMessage represents a plugin hook response. Plugins
    21  // declaring support for CLI hooks need to print a json
    22  // representation of this type when their hook subcommand
    23  // is invoked.
    24  type HookMessage struct {
    25  	Type     HookType
    26  	Template string
    27  }
    28  
    29  // TemplateReplaceSubcommandName returns a hook template string
    30  // that will be replaced by the CLI subcommand being executed
    31  //
    32  // Example:
    33  //
    34  // "you ran the subcommand: " + TemplateReplaceSubcommandName()
    35  //
    36  // when being executed after the command:
    37  // `docker run --name "my-container" alpine`
    38  // will result in the message:
    39  // `you ran the subcommand: run`
    40  func TemplateReplaceSubcommandName() string {
    41  	return hookTemplateCommandName
    42  }
    43  
    44  // TemplateReplaceFlagValue returns a hook template string
    45  // that will be replaced by the flags value.
    46  //
    47  // Example:
    48  //
    49  // "you ran a container named: " + TemplateReplaceFlagValue("name")
    50  //
    51  // when being executed after the command:
    52  // `docker run --name "my-container" alpine`
    53  // will result in the message:
    54  // `you ran a container named: my-container`
    55  func TemplateReplaceFlagValue(flag string) string {
    56  	return fmt.Sprintf(hookTemplateFlagValue, flag)
    57  }
    58  
    59  // TemplateReplaceArg takes an index i and returns a hook
    60  // template string that the CLI will replace the template with
    61  // the ith argument, after processing the passed flags.
    62  //
    63  // Example:
    64  //
    65  // "run this image with `docker run " + TemplateReplaceArg(0) + "`"
    66  //
    67  // when being executed after the command:
    68  // `docker pull alpine`
    69  // will result in the message:
    70  // "Run this image with `docker run alpine`"
    71  func TemplateReplaceArg(i int) string {
    72  	return fmt.Sprintf(hookTemplateArg, strconv.Itoa(i))
    73  }
    74  
    75  func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) {
    76  	tmpl := template.New("").Funcs(commandFunctions)
    77  	tmpl, err := tmpl.Parse(hookTemplate)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	b := bytes.Buffer{}
    82  	err = tmpl.Execute(&b, cmd)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	return strings.Split(b.String(), "\n"), nil
    87  }
    88  
    89  var ErrHookTemplateParse = errors.New("failed to parse hook template")
    90  
    91  const (
    92  	hookTemplateCommandName = "{{.Name}}"
    93  	hookTemplateFlagValue   = `{{flag . "%s"}}`
    94  	hookTemplateArg         = "{{arg . %s}}"
    95  )
    96  
    97  var commandFunctions = template.FuncMap{
    98  	"flag": getFlagValue,
    99  	"arg":  getArgValue,
   100  }
   101  
   102  func getFlagValue(cmd *cobra.Command, flag string) (string, error) {
   103  	cmdFlag := cmd.Flag(flag)
   104  	if cmdFlag == nil {
   105  		return "", ErrHookTemplateParse
   106  	}
   107  	return cmdFlag.Value.String(), nil
   108  }
   109  
   110  func getArgValue(cmd *cobra.Command, i int) (string, error) {
   111  	flags := cmd.Flags()
   112  	if flags == nil {
   113  		return "", ErrHookTemplateParse
   114  	}
   115  	return flags.Arg(i), nil
   116  }