fix: add an xorprefix:"..." option for prefixing xor/and groups
Fixes #343
This commit is contained in:
@@ -550,6 +550,7 @@ Both can coexist with standard Tag parsing.
|
|||||||
| `and:"X,Y,..."` | AND groups for flags. All flags in the group must be used in the same command. When combined with `required`, all flags in the group will be required. |
|
| `and:"X,Y,..."` | AND groups for flags. All flags in the group must be used in the same command. When combined with `required`, all flags in the group will be required. |
|
||||||
| `prefix:"X"` | Prefix for all sub-flags. |
|
| `prefix:"X"` | Prefix for all sub-flags. |
|
||||||
| `envprefix:"X"` | Envar prefix for all sub-flags. |
|
| `envprefix:"X"` | Envar prefix for all sub-flags. |
|
||||||
|
| `xorprefix:"X"` | Prefix for all sub-flags in XOR/AND groups. |
|
||||||
| `set:"K=V"` | Set a variable for expansion by child elements. Multiples can occur. |
|
| `set:"K=V"` | Set a variable for expansion by child elements. Multiples can occur. |
|
||||||
| `embed:""` | If present, this field's children will be embedded in the parent. Useful for composition. |
|
| `embed:""` | If present, this field's children will be embedded in the parent. Useful for composition. |
|
||||||
| `passthrough:"<mode>"`[^1] | If present on a positional argument, it stops flag parsing when encountered, as if `--` was processed before. Useful for external command wrappers, like `exec`. On a command it requires that the command contains only one argument of type `[]string` which is then filled with everything following the command, unparsed. |
|
| `passthrough:"<mode>"`[^1] | If present on a positional argument, it stops flag parsing when encountered, as if `--` was processed before. Useful for external command wrappers, like `exec`. On a command it requires that the command contains only one argument of type `[]string` which is then filled with everything following the command, unparsed. |
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro
|
|||||||
// Accumulate prefixes.
|
// Accumulate prefixes.
|
||||||
tag.Prefix = ptag.Prefix + tag.Prefix
|
tag.Prefix = ptag.Prefix + tag.Prefix
|
||||||
tag.EnvPrefix = ptag.EnvPrefix + tag.EnvPrefix
|
tag.EnvPrefix = ptag.EnvPrefix + tag.EnvPrefix
|
||||||
|
tag.XorPrefix = ptag.XorPrefix + tag.XorPrefix
|
||||||
// Combine parent vars.
|
// Combine parent vars.
|
||||||
tag.Vars = ptag.Vars.CloneWith(tag.Vars)
|
tag.Vars = ptag.Vars.CloneWith(tag.Vars)
|
||||||
// Command and embedded structs can be pointers, so we hydrate them now.
|
// Command and embedded structs can be pointers, so we hydrate them now.
|
||||||
@@ -111,7 +112,7 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro
|
|||||||
// 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.
|
||||||
func buildNode(k *Kong, v reflect.Value, typ NodeType, tag *Tag, seenFlags map[string]bool) (*Node, error) {
|
func buildNode(k *Kong, v reflect.Value, typ NodeType, tag *Tag, seenFlags map[string]bool) (*Node, error) { //nolint:gocyclo
|
||||||
node := &Node{
|
node := &Node{
|
||||||
Type: typ,
|
Type: typ,
|
||||||
Target: v,
|
Target: v,
|
||||||
@@ -147,6 +148,12 @@ MAIN:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(tag.Xor) != 0 {
|
||||||
|
for i := range tag.Xor {
|
||||||
|
tag.Xor[i] = tag.XorPrefix + tag.Xor[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Nested structs are either commands or args, unless they implement the Mapper interface.
|
// Nested structs are either commands or args, unless they implement the Mapper interface.
|
||||||
if field.value.Kind() == reflect.Struct && (tag.Cmd || tag.Arg) && k.registry.ForValue(fv) == nil {
|
if field.value.Kind() == reflect.Struct && (tag.Cmd || tag.Arg) && k.registry.ForValue(fv) == nil {
|
||||||
typ := CommandNode
|
typ := CommandNode
|
||||||
|
|||||||
@@ -2475,3 +2475,23 @@ func TestCustomTypeNoEllipsis(t *testing.T) {
|
|||||||
help := w.String()
|
help := w.String()
|
||||||
assert.NotContains(t, help, "...")
|
assert.NotContains(t, help, "...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrefixXorIssue343(t *testing.T) {
|
||||||
|
type DBConfig struct {
|
||||||
|
Password string `help:"Password" xor:"password" optional:""`
|
||||||
|
PasswordFile string `help:"File which content will be used for a password" xor:"password" optional:""`
|
||||||
|
PasswordCommand string `help:"Command to run to retrieve password" xor:"password" optional:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SourceTargetConfig struct {
|
||||||
|
Source DBConfig `help:"Database config of source to be copied from" prefix:"source-" xorprefix:"source-" embed:""`
|
||||||
|
Target DBConfig `help:"Database config of source to be copied from" prefix:"target-" xorprefix:"target-" embed:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
cli := SourceTargetConfig{}
|
||||||
|
kctx := mustNew(t, &cli)
|
||||||
|
_, err := kctx.Parse([]string{"--source-password=foo", "--target-password=bar"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = kctx.Parse([]string{"--source-password-file=foo", "--source-password=bar"})
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type Tag struct {
|
|||||||
Vars Vars
|
Vars Vars
|
||||||
Prefix string // Optional prefix on anonymous structs. All sub-flags will have this prefix.
|
Prefix string // Optional prefix on anonymous structs. All sub-flags will have this prefix.
|
||||||
EnvPrefix string
|
EnvPrefix string
|
||||||
|
XorPrefix string // Optional prefix on XOR/AND groups.
|
||||||
Embed bool
|
Embed bool
|
||||||
Aliases []string
|
Aliases []string
|
||||||
Negatable string
|
Negatable string
|
||||||
@@ -268,6 +269,7 @@ func hydrateTag(t *Tag, typ reflect.Type) error { //nolint: gocyclo
|
|||||||
}
|
}
|
||||||
t.Prefix = t.Get("prefix")
|
t.Prefix = t.Get("prefix")
|
||||||
t.EnvPrefix = t.Get("envprefix")
|
t.EnvPrefix = t.Get("envprefix")
|
||||||
|
t.XorPrefix = t.Get("xorprefix")
|
||||||
t.Embed = t.Has("embed")
|
t.Embed = t.Has("embed")
|
||||||
if t.Has("negatable") {
|
if t.Has("negatable") {
|
||||||
if !isBool && !isBoolPtr {
|
if !isBool && !isBoolPtr {
|
||||||
|
|||||||
Reference in New Issue
Block a user