Support aliases for flags (#409)
Aliases are currently only supported for sub-commands, but they're useful for flags as well. E.g., when migrating from an old flag name to a new flag name, while still supporting the old value.
This commit is contained in:
committed by
GitHub
parent
30e84613fe
commit
fa9b636997
@@ -566,7 +566,7 @@ Both can coexist with standard Tag parsing.
|
|||||||
| `default:"1"` | On a command, make it the default. |
|
| `default:"1"` | On a command, make it the default. |
|
||||||
| `default:"withargs"` | On a command, make it the default and allow args/flags from that command |
|
| `default:"withargs"` | On a command, make it the default and allow args/flags from that command |
|
||||||
| `short:"X"` | Short name, if flag. |
|
| `short:"X"` | Short name, if flag. |
|
||||||
| `aliases:"X,Y"` | One or more aliases (for cmd). |
|
| `aliases:"X,Y"` | One or more aliases (for cmd or flag). |
|
||||||
| `required:""` | If present, flag/arg is required. |
|
| `required:""` | If present, flag/arg is required. |
|
||||||
| `optional:""` | If present, flag/arg is optional. |
|
| `optional:""` | If present, flag/arg is optional. |
|
||||||
| `hidden:""` | If present, command or flag is hidden. |
|
| `hidden:""` | If present, command or flag is hidden. |
|
||||||
|
|||||||
@@ -296,6 +296,13 @@ func buildField(k *Kong, node *Node, v reflect.Value, ft reflect.StructField, fv
|
|||||||
return failField(v, ft, "duplicate flag --%s", value.Name)
|
return failField(v, ft, "duplicate flag --%s", value.Name)
|
||||||
}
|
}
|
||||||
seenFlags["--"+value.Name] = true
|
seenFlags["--"+value.Name] = true
|
||||||
|
for _, alias := range tag.Aliases {
|
||||||
|
aliasFlag := "--" + alias
|
||||||
|
if seenFlags[aliasFlag] {
|
||||||
|
return failField(v, ft, "duplicate flag %s", aliasFlag)
|
||||||
|
}
|
||||||
|
seenFlags[aliasFlag] = true
|
||||||
|
}
|
||||||
if tag.Short != 0 {
|
if tag.Short != 0 {
|
||||||
if seenFlags["-"+string(tag.Short)] {
|
if seenFlags["-"+string(tag.Short)] {
|
||||||
return failField(v, ft, "duplicate short flag -%c", tag.Short)
|
return failField(v, ft, "duplicate short flag -%c", tag.Short)
|
||||||
@@ -304,6 +311,7 @@ func buildField(k *Kong, node *Node, v reflect.Value, ft reflect.StructField, fv
|
|||||||
}
|
}
|
||||||
flag := &Flag{
|
flag := &Flag{
|
||||||
Value: value,
|
Value: value,
|
||||||
|
Aliases: tag.Aliases,
|
||||||
Short: tag.Short,
|
Short: tag.Short,
|
||||||
PlaceHolder: tag.PlaceHolder,
|
PlaceHolder: tag.PlaceHolder,
|
||||||
Envs: tag.Envs,
|
Envs: tag.Envs,
|
||||||
|
|||||||
+12
-3
@@ -684,15 +684,24 @@ func flipBoolValue(value reflect.Value) error {
|
|||||||
|
|
||||||
func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
|
func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
|
||||||
candidates := []string{}
|
candidates := []string{}
|
||||||
|
|
||||||
for _, flag := range flags {
|
for _, flag := range flags {
|
||||||
long := "--" + flag.Name
|
long := "--" + flag.Name
|
||||||
short := "-" + string(flag.Short)
|
matched := long == match
|
||||||
neg := "--no-" + flag.Name
|
|
||||||
candidates = append(candidates, long)
|
candidates = append(candidates, long)
|
||||||
if flag.Short != 0 {
|
if flag.Short != 0 {
|
||||||
|
short := "-" + string(flag.Short)
|
||||||
|
matched = matched || (short == match)
|
||||||
candidates = append(candidates, short)
|
candidates = append(candidates, short)
|
||||||
}
|
}
|
||||||
if short != match && long != match && !(match == neg && flag.Tag.Negatable) {
|
for _, alias := range flag.Aliases {
|
||||||
|
alias = "--" + alias
|
||||||
|
matched = matched || (alias == match)
|
||||||
|
candidates = append(candidates, alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
neg := "--no-" + flag.Name
|
||||||
|
if !matched && !(match == neg && flag.Tag.Negatable) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Found a matching flag.
|
// Found a matching flag.
|
||||||
|
|||||||
@@ -518,6 +518,16 @@ func TestShort(t *testing.T) {
|
|||||||
assert.Equal(t, "hello", cli.String)
|
assert.Equal(t, "hello", cli.String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAlias(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
String string `aliases:"str"`
|
||||||
|
}
|
||||||
|
app := mustNew(t, &cli)
|
||||||
|
_, err := app.Parse([]string{"--str", "hello"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "hello", cli.String)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDuplicateFlagChoosesLast(t *testing.T) {
|
func TestDuplicateFlagChoosesLast(t *testing.T) {
|
||||||
var cli struct {
|
var cli struct {
|
||||||
Flag int
|
Flag int
|
||||||
@@ -1321,6 +1331,24 @@ func TestDuplicateShortflags(t *testing.T) {
|
|||||||
assert.EqualError(t, err, "<anonymous struct>.Flag2: duplicate short flag -t")
|
assert.EqualError(t, err, "<anonymous struct>.Flag2: duplicate short flag -t")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDuplicateAliases(t *testing.T) {
|
||||||
|
cli1 := struct {
|
||||||
|
Flag1 string `aliases:"flag"`
|
||||||
|
Flag2 string `aliases:"flag"`
|
||||||
|
}{}
|
||||||
|
_, err := kong.New(&cli1)
|
||||||
|
assert.EqualError(t, err, "<anonymous struct>.Flag2: duplicate flag --flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuplicateAliasLong(t *testing.T) {
|
||||||
|
cli2 := struct {
|
||||||
|
Flag string ``
|
||||||
|
Flag2 string `aliases:"flag"` // duplicates Flag
|
||||||
|
}{}
|
||||||
|
_, err := kong.New(&cli2)
|
||||||
|
assert.EqualError(t, err, "<anonymous struct>.Flag2: duplicate flag --flag")
|
||||||
|
}
|
||||||
|
|
||||||
func TestDuplicateNestedShortFlags(t *testing.T) {
|
func TestDuplicateNestedShortFlags(t *testing.T) {
|
||||||
cli := struct {
|
cli := struct {
|
||||||
Flag1 bool `short:"t"`
|
Flag1 bool `short:"t"`
|
||||||
|
|||||||
Reference in New Issue
Block a user