Merge pull request #11337 from Luap99/anon-template

Shell completion for --format with anonymous fields
This commit is contained in:
OpenShift Merge Robot 2021-08-27 07:23:26 -04:00 committed by GitHub
commit 6f61ef87af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 32 deletions

View File

@ -985,40 +985,14 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
f = f.Elem()
}
// // the only supported type is struct
// the only supported type is struct
if f.Kind() != reflect.Struct {
return nil, cobra.ShellCompDirectiveNoFileComp
}
// last field get all names to suggest
if i == len(fields)-1 {
suggestions := []string{}
for j := 0; j < f.NumField(); j++ {
fname := f.Type().Field(j).Name
suffix := "}}"
kind := f.Type().Field(j).Type.Kind()
if kind == reflect.Ptr {
// make sure to read the actual type when it is a pointer
kind = f.Type().Field(j).Type.Elem().Kind()
}
// when we have a nested struct do not append braces instead append a dot
if kind == reflect.Struct {
suffix = "."
}
if strings.HasPrefix(fname, fields[i]) {
// add field name with closing braces
suggestions = append(suggestions, fname+suffix)
}
}
for j := 0; j < f.NumMethod(); j++ {
fname := f.Type().Method(j).Name
if strings.HasPrefix(fname, fields[i]) {
// add method name with closing braces
suggestions = append(suggestions, fname+"}}")
}
}
suggestions := getStructFields(f, fields[i])
// add the current toComplete value in front so that the shell can complete this correctly
toCompArr := strings.Split(toComplete, ".")
toCompArr[len(toCompArr)-1] = ""
@ -1032,6 +1006,52 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
}
}
// getStructFields reads all struct field names and method names and returns them.
func getStructFields(f reflect.Value, prefix string) []string {
suggestions := []string{}
// follow the pointer first
if f.Kind() == reflect.Ptr {
f = f.Elem()
}
// we only support structs
if f.Kind() != reflect.Struct {
return nil
}
// loop over all field names
for j := 0; j < f.NumField(); j++ {
field := f.Type().Field(j)
fname := field.Name
suffix := "}}"
kind := field.Type.Kind()
if kind == reflect.Ptr {
// make sure to read the actual type when it is a pointer
kind = field.Type.Elem().Kind()
}
// when we have a nested struct do not append braces instead append a dot
if kind == reflect.Struct {
suffix = "."
}
if strings.HasPrefix(fname, prefix) {
// add field name with suffix
suggestions = append(suggestions, fname+suffix)
}
// if field is anonymous add the child fields as well
if field.Anonymous {
suggestions = append(suggestions, getStructFields(f.FieldByIndex([]int{j}), prefix)...)
}
}
for j := 0; j < f.NumMethod(); j++ {
fname := f.Type().Method(j).Name
if strings.HasPrefix(fname, prefix) {
// add method name with closing braces
suggestions = append(suggestions, fname+"}}")
}
}
return suggestions
}
// AutocompleteEventFilter - Autocomplete event filter flag options.
// -> "container=", "event=", "image=", "pod=", "volume=", "type="
func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {

View File

@ -17,6 +17,10 @@ type Car struct {
Extras map[string]string
}
type Anonymous struct {
Hello string
}
func (c Car) Type() string {
return ""
}
@ -30,7 +34,10 @@ func TestAutocompleteFormat(t *testing.T) {
Name string
Age int
Car *Car
}{}
*Anonymous
}{
Anonymous: &Anonymous{},
}
testStruct.Car = &Car{}
testStruct.Car.Extras = map[string]string{"test": "1"}
@ -73,12 +80,12 @@ func TestAutocompleteFormat(t *testing.T) {
{
"fist level struct field name",
"{{.",
[]string{"{{.Name}}", "{{.Age}}", "{{.Car."},
[]string{"{{.Name}}", "{{.Age}}", "{{.Car.", "{{.Anonymous.", "{{.Hello}}"},
},
{
"fist level struct field name",
"{{ .",
[]string{"{{ .Name}}", "{{ .Age}}", "{{ .Car."},
[]string{"{{ .Name}}", "{{ .Age}}", "{{ .Car.", "{{ .Anonymous.", "{{ .Hello}}"},
},
{
"fist level struct field name",

View File

@ -57,7 +57,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&psInput.Format, formatFlagName, "", "Pretty-print pods to JSON or using a Go template")
_ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPodReporter{}))
_ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPodReporter{ListPodsReport: &entities.ListPodsReport{}}))
flags.Bool("noheading", false, "Do not print headers")
flags.BoolVar(&psInput.Namespace, "namespace", false, "Display namespace information of the pod")