Bind Vars.

This commit is contained in:
Alec Thomas
2018-07-06 10:44:09 +10:00
parent 17e855bc47
commit 99ff32a85f
4 changed files with 46 additions and 27 deletions
+7 -5
View File
@@ -18,7 +18,7 @@
1. [Slices](#slices)
1. [Maps](#maps)
1. [Custom named decoders](#custom-named-decoders)
1. [Custom decoders](#custom-decoders)
1. [Custom decoders \(mappers\)](#custom-decoders-mappers)
1. [Supported tags](#supported-tags)
1. [Variable interpolation](#variable-interpolation)
1. [Modifying Kong's behaviour](#modifying-kongs-behaviour)
@@ -162,11 +162,13 @@ This has the advantage that it is convenient, but the downside that if you modif
A more robust approach is to break each command out into their own structs:
1. Break leaf commands out into separate structs.
2. Attach a `Run(...) error` method to all leaf commands (`Run()` signatures must match).
2. Attach a `Run(...) error` method to all leaf commands.
3. Call `kong.Kong.Parse()` to obtain a `kong.Context`.
4. Call `kong.Context.Run(params...)` to call the selected parsed command.
4. Call `kong.Context.Run(bindings...)` to call the selected parsed command.
Note that `Run()` method arguments may also be provided by the `Bind(...)` option (see below).
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
`Run()` arguments.
There's a full example emulating part of the Docker CLI [here](https://github.com/alecthomas/kong/tree/master/_examples/docker).
@@ -362,7 +364,7 @@ specifies the element type. For maps, the tag has the format
`tag:"[<key>]:[<value>]"` where either may be omitted.
## Custom decoders
## Custom decoders (mappers)
If a field implements the [MapperValue](https://godoc.org/github.com/alecthomas/kong#MapperValue)
interface it will be used to decode arguments into the field.
+31 -16
View File
@@ -2,24 +2,36 @@
package main
import (
"fmt"
"github.com/alecthomas/kong"
)
type Globals struct {
Config string `help:"Location of client config files" default:"~/.docker" type:"path"`
Debug bool `short:"D" help:"Enable debug mode"`
Host []string `short:"H" help:"Daemon socket(s) to connect to"`
LogLevel string `short:"l" help:"Set the logging level (debug|info|warn|error|fatal)" default:"info"`
TLS bool `help:"Use TLS; implied by --tls-verify"`
TLSCACert string `name:"tls-ca-cert" help:"Trust certs signed only by this CA" default:"~/.docker/ca.pem" type:"path"`
TLSCert string `help:"Path to TLS certificate file" default:"~/.docker/cert.pem" type:"path"`
TLSKey string `help:"Path to TLS key file" default:"~/.docker/key.pem" type:"path"`
TLSVerify bool `help:"Use TLS and verify the remote"`
Config string `help:"Location of client config files" default:"~/.docker" type:"path"`
Debug bool `short:"D" help:"Enable debug mode"`
Host []string `short:"H" help:"Daemon socket(s) to connect to"`
LogLevel string `short:"l" help:"Set the logging level (debug|info|warn|error|fatal)" default:"info"`
TLS bool `help:"Use TLS; implied by --tls-verify"`
TLSCACert string `name:"tls-ca-cert" help:"Trust certs signed only by this CA" default:"~/.docker/ca.pem" type:"path"`
TLSCert string `help:"Path to TLS certificate file" default:"~/.docker/cert.pem" type:"path"`
TLSKey string `help:"Path to TLS key file" default:"~/.docker/key.pem" type:"path"`
TLSVerify bool `help:"Use TLS and verify the remote"`
Version VersionFlag `name:"version" help:"Print version information and quit"`
}
type VersionFlag string
func (v VersionFlag) Decode(ctx *kong.DecodeContext) error { return nil }
func (v VersionFlag) IsBool() bool { return true }
func (v VersionFlag) BeforeHook(app *kong.Kong, vars kong.Vars) error {
fmt.Println(vars["version"])
app.Exit(0)
return nil
}
type CLI struct {
Globals
VersionFlag bool `name:"version" help:"Print version information and quit"`
Attach AttachCmd `cmd help:"Attach local standard input, output, and error streams to a running container"`
Build BuildCmd `cmd help:"Build an image from a Dockerfile"`
@@ -65,7 +77,12 @@ type CLI struct {
}
func main() {
cli := CLI{}
cli := CLI{
Globals: Globals{
Version: VersionFlag("0.1.1"),
},
}
ctx := kong.Parse(&cli,
kong.Name("docker"),
kong.Description("A self-sufficient runtime for containers"),
@@ -73,11 +90,9 @@ func main() {
kong.ConfigureHelp(kong.HelpOptions{
Compact: true,
}),
//
kong.Hook(&cli.VersionFlag, func(ctx *kong.Context, path *kong.Path) error {
ctx.Printf("1.0.0").Exit(0)
return nil
}))
kong.Vars{
"version": "0.0.1",
})
err := ctx.Run(&cli.Globals)
ctx.FatalIfErrorf(err)
}
+4 -4
View File
@@ -470,10 +470,10 @@ func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
return findPotentialCandidates(match, candidates, "unknown flag %s", match)
}
// Run executes the corresponding Run(params...) method on the target command selected by the parsed args.
// Run executes the Run() method on the selected command, which must exist.
//
// The target Run() method must exist and have the type signature "Run(params...) error".
func (c *Context) Run(params ...interface{}) (err error) {
// Any passed values will be bindable to arguments of the target Run() method.
func (c *Context) Run(bindings ...interface{}) (err error) {
defer catch(&err)
node := c.Selected()
if node == nil {
@@ -487,7 +487,7 @@ func (c *Context) Run(params ...interface{}) (err error) {
if err != nil {
return err
}
binds := c.Kong.bindings.clone().add(params...).add(c)
binds := c.Kong.bindings.clone().add(bindings...).add(c)
return callMethod("Run", node.Target, method, binds)
}
+4 -2
View File
@@ -51,7 +51,7 @@ type Kong struct {
help HelpPrinter
helpOptions HelpOptions
helpFlag *Flag
vars map[string]string
vars Vars
// Set temporarily by Options. These are applied after build().
postBuildOptions []Option
@@ -67,7 +67,7 @@ func New(grammar interface{}, options ...Option) (*Kong, error) {
Stderr: os.Stderr,
registry: NewRegistry().RegisterDefaults(),
resolvers: []ResolverFunc{Envars()},
vars: map[string]string{},
vars: Vars{},
bindings: bindings{},
}
@@ -102,6 +102,8 @@ func New(grammar interface{}, options ...Option) (*Kong, error) {
return nil, err
}
k.bindings.add(k.vars)
return k, nil
}