feat: Allow ignoring fields from embedded structs (#499)
If a field in a struct is ignored with `kong:"-"`, any embedded fields with the same name are also ignored. This allows an outer struct to remove flags from an embedded struct by redefining it and adding a kong ignore tag.
This commit is contained in:
@@ -54,6 +54,7 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro
|
|||||||
if v.Kind() != reflect.Struct {
|
if v.Kind() != reflect.Struct {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
ignored := map[string]bool{}
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
ft := v.Type().Field(i)
|
ft := v.Type().Field(i)
|
||||||
fv := v.Field(i)
|
fv := v.Field(i)
|
||||||
@@ -61,7 +62,8 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if tag.Ignored {
|
if tag.Ignored || ignored[ft.Name] {
|
||||||
|
ignored[ft.Name] = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Assign group if it's not already set.
|
// Assign group if it's not already set.
|
||||||
@@ -106,9 +108,27 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro
|
|||||||
}
|
}
|
||||||
out = append(out, sub...)
|
out = append(out, sub...)
|
||||||
}
|
}
|
||||||
|
out = removeIgnored(out, ignored)
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeIgnored(fields []flattenedField, ignored map[string]bool) []flattenedField {
|
||||||
|
j := 0
|
||||||
|
for i := 0; i < len(fields); i++ {
|
||||||
|
if ignored[fields[i].field.Name] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i != j {
|
||||||
|
fields[j] = fields[i]
|
||||||
|
}
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if j != len(fields) {
|
||||||
|
fields = fields[:j]
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
// Build a Node in the Kong data model.
|
// Build a Node in the Kong data model.
|
||||||
//
|
//
|
||||||
// "v" is the value to create the node from, "typ" is the output Node type.
|
// "v" is the value to create the node from, "typ" is the output Node type.
|
||||||
|
|||||||
@@ -856,6 +856,43 @@ func TestExcludedField(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExcludeEmbeddedField(t *testing.T) {
|
||||||
|
type Embedded struct {
|
||||||
|
Flag string
|
||||||
|
Excluded string
|
||||||
|
}
|
||||||
|
type Embedded2 struct {
|
||||||
|
Flag2 string
|
||||||
|
Excluded string
|
||||||
|
}
|
||||||
|
var cli struct {
|
||||||
|
Embedded
|
||||||
|
Excluded string `kong:"-"`
|
||||||
|
Embedded2
|
||||||
|
}
|
||||||
|
var cli2 struct {
|
||||||
|
Embedded Embedded `kong:"embed"`
|
||||||
|
Excluded string `kong:"-"`
|
||||||
|
Embedded2 Embedded2 `kong:"embed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse([]string{"--flag=foo"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = p.Parse([]string{"--flag-2=foo"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = p.Parse([]string{"--excluded=foo"})
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
p = mustNew(t, &cli2)
|
||||||
|
_, err = p.Parse([]string{"--flag=foo"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = p.Parse([]string{"--flag-2=foo"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = p.Parse([]string{"--excluded=foo"})
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnnamedFieldEmbeds(t *testing.T) {
|
func TestUnnamedFieldEmbeds(t *testing.T) {
|
||||||
type Embed struct {
|
type Embed struct {
|
||||||
Flag string
|
Flag string
|
||||||
|
|||||||
Reference in New Issue
Block a user