Add support for dynamically registered commands.
This commit is contained in:
@@ -66,6 +66,7 @@ type Kong struct {
|
|||||||
|
|
||||||
// Set temporarily by Options. These are applied after build().
|
// Set temporarily by Options. These are applied after build().
|
||||||
postBuildOptions []Option
|
postBuildOptions []Option
|
||||||
|
dynamicCommands []*dynamicCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Kong parser on grammar.
|
// New creates a new Kong parser on grammar.
|
||||||
@@ -106,6 +107,20 @@ func New(grammar interface{}, options ...Option) (*Kong, error) {
|
|||||||
k.Model = model
|
k.Model = model
|
||||||
k.Model.HelpFlag = k.helpFlag
|
k.Model.HelpFlag = k.helpFlag
|
||||||
|
|
||||||
|
// Synthesise command nodes.
|
||||||
|
for _, dcmd := range k.dynamicCommands {
|
||||||
|
tag := newEmptyTag()
|
||||||
|
tag.Name = dcmd.name
|
||||||
|
tag.Help = dcmd.help
|
||||||
|
tag.Group = dcmd.group
|
||||||
|
tag.Cmd = true
|
||||||
|
v := reflect.Indirect(reflect.ValueOf(dcmd.cmd))
|
||||||
|
buildChild(k, k.Model.Node, CommandNode, reflect.Value{}, reflect.StructField{
|
||||||
|
Name: dcmd.name,
|
||||||
|
Type: v.Type(),
|
||||||
|
}, v, tag, dcmd.name, map[string]bool{})
|
||||||
|
}
|
||||||
|
|
||||||
for _, option := range k.postBuildOptions {
|
for _, option := range k.postBuildOptions {
|
||||||
if err = option.Apply(k); err != nil {
|
if err = option.Apply(k); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -1002,3 +1002,30 @@ func TestPointers(t *testing.T) {
|
|||||||
require.NotNil(t, cli.JSON)
|
require.NotNil(t, cli.JSON)
|
||||||
require.Equal(t, "FOO", string(*cli.JSON))
|
require.Equal(t, "FOO", string(*cli.JSON))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type dynamicCommand struct {
|
||||||
|
Flag string
|
||||||
|
|
||||||
|
ran bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dynamicCommand) Run() error {
|
||||||
|
d.ran = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDynamicCommands(t *testing.T) {
|
||||||
|
cli := struct {
|
||||||
|
One struct{} `cmd:"one"`
|
||||||
|
}{}
|
||||||
|
two := &dynamicCommand{}
|
||||||
|
var twoi interface{} = &two
|
||||||
|
p := mustNew(t, &cli, kong.DynamicCommand("two", "", "", twoi))
|
||||||
|
kctx, err := p.Parse([]string{"two", "--flag=flag"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "flag", two.Flag)
|
||||||
|
require.False(t, two.ran)
|
||||||
|
err = kctx.Run()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, two.ran)
|
||||||
|
}
|
||||||
|
|||||||
+22
@@ -54,6 +54,28 @@ func Exit(exit func(int)) Option {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type dynamicCommand struct {
|
||||||
|
name string
|
||||||
|
help string
|
||||||
|
group string
|
||||||
|
cmd interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DynamicCommand registers a dynamically constructed command with the root of the CLI.
|
||||||
|
//
|
||||||
|
// This is useful for command-line structures that are extensible via user-provided plugins.
|
||||||
|
func DynamicCommand(name, help, group string, cmd interface{}) Option {
|
||||||
|
return OptionFunc(func(k *Kong) error {
|
||||||
|
k.dynamicCommands = append(k.dynamicCommands, &dynamicCommand{
|
||||||
|
name: name,
|
||||||
|
help: help,
|
||||||
|
group: group,
|
||||||
|
cmd: cmd,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// NoDefaultHelp disables the default help flags.
|
// NoDefaultHelp disables the default help flags.
|
||||||
func NoDefaultHelp() Option {
|
func NoDefaultHelp() Option {
|
||||||
return OptionFunc(func(k *Kong) error {
|
return OptionFunc(func(k *Kong) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user