summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/completion.go76
-rw-r--r--cmd/podman/common/completion_test.go13
-rw-r--r--cmd/podman/pods/ps.go2
3 files changed, 59 insertions, 32 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 9a4524b46..3966606e3 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -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) {
diff --git a/cmd/podman/common/completion_test.go b/cmd/podman/common/completion_test.go
index 5bd627b85..84b3c1132 100644
--- a/cmd/podman/common/completion_test.go
+++ b/cmd/podman/common/completion_test.go
@@ -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",
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index 14e3e2ea9..60aadf224 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -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")