Skip to content

Commit

Permalink
Support aliases for flags (#409)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
prashantv committed Feb 27, 2024
1 parent 30e8461 commit fa9b636
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -566,7 +566,7 @@ Both can coexist with standard Tag parsing.
| `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 |
| `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. |
| `optional:""` | If present, flag/arg is optional. |
| `hidden:""` | If present, command or flag is hidden. |
Expand Down
8 changes: 8 additions & 0 deletions build.go
Expand Up @@ -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)
}
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 seenFlags["-"+string(tag.Short)] {
return failField(v, ft, "duplicate short flag -%c", tag.Short)
Expand All @@ -304,6 +311,7 @@ func buildField(k *Kong, node *Node, v reflect.Value, ft reflect.StructField, fv
}
flag := &Flag{
Value: value,
Aliases: tag.Aliases,
Short: tag.Short,
PlaceHolder: tag.PlaceHolder,
Envs: tag.Envs,
Expand Down
15 changes: 12 additions & 3 deletions context.go
Expand Up @@ -684,15 +684,24 @@ func flipBoolValue(value reflect.Value) error {

func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
candidates := []string{}

for _, flag := range flags {
long := "--" + flag.Name
short := "-" + string(flag.Short)
neg := "--no-" + flag.Name
matched := long == match
candidates = append(candidates, long)
if flag.Short != 0 {
short := "-" + string(flag.Short)
matched = matched || (short == match)
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
}
// Found a matching flag.
Expand Down
28 changes: 28 additions & 0 deletions kong_test.go
Expand Up @@ -518,6 +518,16 @@ func TestShort(t *testing.T) {
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) {
var cli struct {
Flag int
Expand Down Expand Up @@ -1321,6 +1331,24 @@ func TestDuplicateShortflags(t *testing.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) {
cli := struct {
Flag1 bool `short:"t"`
Expand Down
1 change: 1 addition & 0 deletions model.go
Expand Up @@ -397,6 +397,7 @@ type Flag struct {
Xor []string
PlaceHolder string
Envs []string
Aliases []string
Short rune
Hidden bool
Negated bool
Expand Down

0 comments on commit fa9b636

Please sign in to comment.