summaryrefslogtreecommitdiff
path: root/cmd/podman/common/completion.go
diff options
context:
space:
mode:
authorPaul Holzinger <pholzing@redhat.com>2022-04-28 14:49:03 +0200
committerPaul Holzinger <pholzing@redhat.com>2022-04-28 15:11:21 +0200
commitf93ba587c608e2678b176f1460b32e8a144edf1a (patch)
treeb2c6b5ce5b7e571b33fb77146ef4bf1c0d7c9162 /cmd/podman/common/completion.go
parent2b8cafc0671fbbd155770f044b8216f050877192 (diff)
downloadpodman-f93ba587c608e2678b176f1460b32e8a144edf1a.tar.gz
podman-f93ba587c608e2678b176f1460b32e8a144edf1a.tar.bz2
podman-f93ba587c608e2678b176f1460b32e8a144edf1a.zip
shell completion --format: work with nil structs
AutocompleteFormat() takes the format struct as argument. Often the structs are deeply nested and contain other structs. Up until now if there was a pointer to a struct the logic was not able to get the field names from that, simply because the pointer was nil. However it is possible to create a new initialized type with reflect.New(). This allows us to complete all struct fields/functions even when there nil pointers. Therefore we can drop the extra initialization which was done by some callers. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
Diffstat (limited to 'cmd/podman/common/completion.go')
-rw-r--r--cmd/podman/common/completion.go39
1 files changed, 29 insertions, 10 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index c7d5d6d60..6f13eb5a2 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -987,14 +987,12 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
fields := strings.Split(field[len(field)-1], ".")
f := reflect.ValueOf(o)
for i := 1; i < len(fields); i++ {
- if f.Kind() == reflect.Ptr {
- f = f.Elem()
- }
-
- // the only supported type is struct
- if f.Kind() != reflect.Struct {
+ val := getActualStructType(f)
+ if val == nil {
+ // no struct return nothing to complete
return nil, cobra.ShellCompDirectiveNoFileComp
}
+ f = *val
// last field get all names to suggest
if i == len(fields)-1 {
@@ -1012,17 +1010,38 @@ 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{}
+// getActualStructType take the value and check if it is a struct,
+// if it is pointer it will dereference it and when it is nil,
+// it will create a new value from it to get the actual struct
+// returns nil when type is not a struct
+func getActualStructType(f reflect.Value) *reflect.Value {
// follow the pointer first
if f.Kind() == reflect.Ptr {
+ // if the pointer is nil we create a new value from the elements type
+ // this allows us to follow nil pointers and get the actual struct fields
+ if f.IsNil() {
+ f = reflect.New(f.Type().Elem())
+ }
f = f.Elem()
}
// we only support structs
if f.Kind() != reflect.Struct {
return nil
}
+ return &f
+}
+
+// getStructFields reads all struct field names and method names and returns them.
+func getStructFields(f reflect.Value, prefix string) []string {
+ suggestions := []string{}
+
+ val := getActualStructType(f)
+ if val == nil {
+ // no struct return nothing to complete
+ return nil
+ }
+ f = *val
+
// loop over all field names
for j := 0; j < f.NumField(); j++ {
field := f.Type().Field(j)
@@ -1043,7 +1062,7 @@ func getStructFields(f reflect.Value, prefix string) []string {
}
// if field is anonymous add the child fields as well
if field.Anonymous {
- suggestions = append(suggestions, getStructFields(f.FieldByIndex([]int{j}), prefix)...)
+ suggestions = append(suggestions, getStructFields(f.Field(j), prefix)...)
}
}