Call Run(...) for all parent nodes.
Instead of just the leaf command. Fixes #30.
This commit is contained in:
@@ -166,6 +166,10 @@ A more robust approach is to break each command out into their own structs:
|
|||||||
3. Call `kong.Kong.Parse()` to obtain a `kong.Context`.
|
3. Call `kong.Kong.Parse()` to obtain a `kong.Context`.
|
||||||
4. Call `kong.Context.Run(bindings...)` to call the selected parsed command.
|
4. Call `kong.Context.Run(bindings...)` to call the selected parsed command.
|
||||||
|
|
||||||
|
Once a command node is selected by Kong it will search from that node back to the root. Each
|
||||||
|
encountered command node with a `Run(...) error` will be called in reverse order. This allows
|
||||||
|
sub-trees to be re-used fairly conveniently.
|
||||||
|
|
||||||
In addition to values bound with the `kong.Bind(...)` option, any values
|
In addition to values bound with the `kong.Bind(...)` option, any values
|
||||||
passed through to `kong.Context.Run(...)` are also bindable to the target's
|
passed through to `kong.Context.Run(...)` are also bindable to the target's
|
||||||
`Run()` arguments.
|
`Run()` arguments.
|
||||||
|
|||||||
+25
-5
@@ -88,6 +88,10 @@ func (c *Context) Bind(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BindTo adds a binding to the Context.
|
// BindTo adds a binding to the Context.
|
||||||
|
//
|
||||||
|
// This will typically have to be called like so:
|
||||||
|
//
|
||||||
|
// BindTo(impl, (*MyInterface)(nil))
|
||||||
func (c *Context) BindTo(impl, iface interface{}) {
|
func (c *Context) BindTo(impl, iface interface{}) {
|
||||||
c.bindings[reflect.TypeOf(iface).Elem()] = reflect.ValueOf(impl)
|
c.bindings[reflect.TypeOf(iface).Elem()] = reflect.ValueOf(impl)
|
||||||
}
|
}
|
||||||
@@ -493,16 +497,32 @@ func (c *Context) Run(bindings ...interface{}) (err error) {
|
|||||||
if node == nil {
|
if node == nil {
|
||||||
return fmt.Errorf("no command selected")
|
return fmt.Errorf("no command selected")
|
||||||
}
|
}
|
||||||
method := getMethod(node.Target, "Run")
|
type targetMethod struct {
|
||||||
if !method.IsValid() {
|
node *Node
|
||||||
return fmt.Errorf("no Run() method on %s", node.Target)
|
method reflect.Value
|
||||||
|
}
|
||||||
|
methods := []targetMethod{}
|
||||||
|
for i := 0; node != nil; i, node = i+1, node.Parent {
|
||||||
|
method := getMethod(node.Target, "Run")
|
||||||
|
if method.IsValid() {
|
||||||
|
methods = append(methods, targetMethod{node, method})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(methods) == 0 {
|
||||||
|
return fmt.Errorf("no Run() method found in hierarchy of %s", c.Selected().Summary())
|
||||||
}
|
}
|
||||||
_, err = c.Apply()
|
_, err = c.Apply()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
binds := c.Kong.bindings.clone().add(bindings...).add(c).merge(c.bindings)
|
|
||||||
return callMethod("Run", node.Target, method, binds)
|
for _, method := range methods {
|
||||||
|
binds := c.Kong.bindings.clone().add(bindings...).add(c).merge(c.bindings)
|
||||||
|
if err = callMethod("Run", method.node.Target, method.method, binds); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintUsage to Kong's stdout.
|
// PrintUsage to Kong's stdout.
|
||||||
|
|||||||
+21
-2
@@ -513,9 +513,22 @@ func (c *cmdWithRun) Run(key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type parentCmdWithRun struct {
|
||||||
|
Flag string
|
||||||
|
SubCommand struct {
|
||||||
|
Arg string `arg:""`
|
||||||
|
} `cmd:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parentCmdWithRun) Run(key string) error {
|
||||||
|
p.SubCommand.Arg += key
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type grammarWithRun struct {
|
type grammarWithRun struct {
|
||||||
One cmdWithRun `cmd:""`
|
One cmdWithRun `cmd:""`
|
||||||
Two cmdWithRun `cmd:""`
|
Two cmdWithRun `cmd:""`
|
||||||
|
Three parentCmdWithRun `cmd:""`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRun(t *testing.T) {
|
func TestRun(t *testing.T) {
|
||||||
@@ -532,6 +545,12 @@ func TestRun(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = ctx.Run("ERROR")
|
err = ctx.Run("ERROR")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
|
ctx, err = p.Parse([]string{"three", "sub-command", "arg"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = ctx.Run("ping")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "argping", cli.Three.SubCommand.Arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInterpolationIntoModel(t *testing.T) {
|
func TestInterpolationIntoModel(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user