alecthomas / kong Goto Github PK
View Code? Open in Web Editor NEWKong is a command-line parser for Go
License: MIT License
Kong is a command-line parser for Go
License: MIT License
With nested anonymous flags:
type Cmd struct {
NestedFlag `prefix:"nested-"`
}
honors nesting and applies "nested-" prefix.
However:
type Cmd struct {
NestedFlag `kong:"prefix:'nested-'"`
}
does not honor/apply the prefix.
Some CLI tools traditionally use the single dash to mean "stdin".
Examples are tar tvfz -
or cat -
Kong however chokes when encountering a -
not followed with a letter with error: expected short flag
.
In my current project, I faced the following challenge. I have a cli whichs commands are composed of two subcommand sets. E.g, build
and find
as root commands and both have the same sub commands with the same methods, e.g., build foo
, build goo
, find foo
, and find goo
. Ideally, there would be only one sub command struct for foo
and goo
that is embedded in the root commands. However, I could not find an idiomatic way to call the root commands (i.e, parents) from the sub commands Run
methods. I had to access context.Command()
and identify the struct field using reflection.
So I'm wondering if you considered such a case - maybe I haven't seen the obvious again - or if you would like to see a feature that allows to traverse to parent command structs and execute a Run
on it. Thereby, someone could create quite advanced command chains.
hcl config:
kafka {
replication-factor = 3
}
struct to set
type KafkaConfig struct {
BootstrapServer string `help:"The advertised address and port of the kafka brokers" default:"localhost:9093"`
ReplicationFactor int16 `help:"The replication factor for topics" default:"1"`
}
panic: mapper kong.MapperFunc failed to apply to --kafka-replication-factor=1: reflect.Set: value of type int is not assignable to type int16 [recovered]
happens at
Line 340 in 51a1ea9
How to load configuration from the path defined in the CLI/ENV? Do it parse twice?
type Cli struct {
Config string `type:"path"`
...
}
func main() {
var cli Cli
_ := kong.Parse(&cli)
ctx := kong.Parse(&cli, kong.Configuration(kong.JSON, cli.Config))
}
Since I am unclear how to describe this, I will just show the DSL for the behaviour I would like:
Usage: cli <command>
Commands:
cmd [<arg> [sub <arg>]]
cmd sub
I can construct a struct
where, ./cli cmd
executes cmd other
, thus effectively giving me cmd [<arg>]
: (both the docs do not show this, and it feels like a hack, is there a better way?)
Usage: cli <command>
Commands:
cmd other
cmd <arg>
cmd sub
var CLI struct {
Cmd struct{
Other struct{} `cmd default:"1"`
Arg struct {
Arg string `arg`
} `arg`
Sub struct{} `cmd`
} `cmd`
}
Again trickery with default:"1"
gives me ./cli cmd arg
which executes cmd <arg>
, but it does not document well:
Usage: cli <command>
Commands:
cmd other
cmd <arg> other
cmd <arg> sub [<arg>]
cmd sub
var CLI struct {
Cmd struct{
Other struct{} `cmd default:"1"`
Arg struct {
Arg string `arg`
Other struct{} `cmd default:"1"`
Sub struct{
Arg string `arg optional`
} `cmd`
} `arg`
Sub struct{} `cmd`
} `cmd`
}
If there is a better way, I am all ears, otherwise I the following workaround would make the docs read correctly without refactoring the parsing logic:
Usage: cli <command>
Commands:
cmd # this is implied by `default:"1"`
cmd other # I am fine with this being visible, but somebody may want to hide it
cmd <arg> # this is implied by `default"1"`
cmd <arg> sub [<arg>]
cmd sub
var CLI struct {
Cmd struct{
Other struct{} `cmd default:"1"`
Arg struct {
Arg string `arg` // with `cmd <arg>` now visible, either this tag
Other struct{} `cmd hidden default:"1"`
Sub struct{
Arg string `arg optional`
} `cmd`
} `arg` // or this one should control visibility
Sub struct{} `cmd`
} `cmd`
}
Hi
Thanks for the cool library. One thing I am missing is, how to show which config file was used (if any).
Something like this would be great:
$ command subcommand
using configuration file: .test.json
...
It would be possible to do that in the Configuration
Option like:
func Configuration(loader ConfigurationLoader, showUsedConfigs bool, paths ...string) Option {
return OptionFunc(func(k *Kong) error {
k.loader = loader
for _, path := range paths {
resolver, _ := k.LoadConfig(path)
if resolver != nil {
if showUsedConfigs {
fmt.Fprintf(k.Stderr, "using configuration file: %s\n", path)
}
k.resolvers = append(k.resolvers, resolver)
}
}
return nil
})
}
But there are two problems:
--help
flag.Any interests in adding such a feature?
I could also create a custom config file Resolver. I suppose in that case I would be able to get the value of the help
flag and there would be no API break.
Discoverability of environment variables is an issue in general. Command-line arguments can probably help with this. It would be great if when you invoke the help (e.g. --help) if the arguments that have associate environment variables could be shown there.
For example, I have this snippet in my struct:
WhiteList []string `env:"ANONYMIZER_WHITE_LIST" sep:";" help:"List of tags that should be white listed." default:"(0008,103e);(0020,0011)"`
But, when I invoke my command with --help there is no mention of the environment variable:
Flags:
...
--white-list=(0008,103e);(0020,0011),...
List of tags that should be white listed.
What if the output showed something like this for flags with the 'env' property:
Flags:
...
--white-list=(0008,103e);(0020,0011),...
List of tags that should be white listed.
Environment variable: ANONYMIZER_WHITE_LIST
How to load this kind of JSON to flags:
{
"Name": "Some name",
"db": {
"host": "localhost",
"port": "9000",
}
}
Maybe I just haven't figured it out, but is there a simple way to add longer help texts to the commands, not just one liners?
Using the AWS CLI illustrates how useful that would be, as it's basically impossible to discover how to use it unless you already know exactly what you're looking for. Something like a --help[=<foo>]
would be excellent.
For given sample:
package main
import (
"fmt"
"github.com/alecthomas/kong"
)
var CLI struct {
One struct {
OneArg string `arg:"" required:""`
} `cmd: ""`
Two struct {
TwoArg string `arg:"" enum:"a,b,c" required:""`
} `cmd: ""`
}
func main() {
ctx := kong.Parse(&CLI)
switch cmd := ctx.Command(); cmd {
case "one <one-arg>", "two <two-arg>":
fmt.Println("command:", cmd)
default:
panic(ctx.Command())
}
}
I expect the following behaviour:
> go run main.go one X
command: one <one-arg>
> go run main.go two a
command: two <two-arg>
However, I get:
> go run main.go one X
main: error: <two-arg> must be one of "a","b","c" but got ""
exit status 1
> go run main.go two a
command: two <two-arg>
When I remove the enum
tag or replace required
with default:"a"
in command two
, command one
behaves as expected.
Hi Alec,
I was wondering if there is a way to set the short name for the default help flag. I was able to do it by adding the following option after forking your project:
// DefaultHelpShort sets the short name for the default help flag.
func DefaultHelpShort(v rune) Option {
return OptionFunc(func(k *Kong) error {
k.postBuildOptions = append(k.postBuildOptions, OptionFunc(func(k *Kong) error {
k.Model.HelpFlag.Short = v
return nil
}))
return nil
})
}
Is there a better way to do this that already exists? If not, would you consider adding this functionality?
Thank you.
Sorry to bother again.
I am writing a custom HelpPrinter
but since the latest commit I had to add the following:
newHelp = strings.ReplaceAll(help, "($"+envVar+")", "")
This works, but is error-prone. Should you decide to change the format the above code can break.
Is there a better way to disable that new behavior?
On armv7hl and i686 builds (both 32-bit), these tests fail due to constant overflow:
# github.com/alecthomas/kong_test [github.com/alecthomas/kong.test]
./mapper_test.go:287:26: constant 9223372036854775807 overflows int
./mapper_test.go:290:26: constant 4294967295 overflows int
./mapper_test.go:312:16: constant -9223372036854775808 overflows int
FAIL github.com/alecthomas/kong [build failed]
So if i have a flag as follows, can i validate this is set without adding required?
The rational is I just want to know if it was defaulted from an ENV or set via a command flag.
Stage stageFlag `help:"The stage this is deployed." env:"STAGE"`
Cheers
When type:"existingfile" is given, kong checks if the default value exists as a file even the config value is explicitly set to something else.
Would a pull request for a mapsep tag be accepted? A ; char is very unfortunate since ot terminates the command if you don‘t put it into ‘.
Currently if the the default --help
option is used the app returns exit code 1
. I personally don't think that someone specifically calling --help
should result in an exit code other than 0
. Is there a way to change this behavior? I've reviewed the docs and Issues pretty thoroughly and can't find anything.
I'm also open to any rational that presents a good argument for why a program should return an exit code other than 0
for a user (person or automation) specifically calling --help
as the only parameter sent to a program.
I'm struggling to understand if there's a way in Kong to enable automatic resolution for flag from environment variables without specifying the env
tag on each flag. I've tried playing around with hooks and resolvers but couldn't get it working.
What I want is to be able to pull configuration values from flags, config files and environment variables automatically. Also would be great to be able to specify a prefix for environment variables if needed.
I was wondering if there was an intention of bringing over the the ExpandArgsFromFile
and the @
operator from Kingpin.
https://github.com/alecthomas/kingpin/blob/f024f0c4376385bf6318d43c2a6937ccf6253fea/parser.go#L270
It was a useful feature.
Thanks in advance either way.
When using counter
named type, only the short version is allowed, even though --help
shows I should be able to provide an int type value as an argument in the longer flag version as well.
Configuration:
type cli struct {
Verbosity int `short:"v" type"counter" help:"Set verbosity level."`
}
--help
output:
Flags:
--help Show context-sensitive help.
-v, --verbosity=INT Set verbosity level.
When I try executing with the longer version:
go run main.go --verbosity=3
main: error: unexpected flag argument "3"
exit status 1
Given this source:
package main
import (
"context"
"fmt"
"github.com/alecthomas/kong"
)
type Cmd struct {
}
func (Cmd) Run(ctx context.Context) error {
fmt.Println("ok")
return nil
}
type Options struct {
Cmd Cmd `cmd:""`
}
func main() {
var opts Options
cli := kong.Parse(&opts)
ctx := context.TODO()
cli.FatalIfErrorf(cli.Run(ctx))
}
When I run go run example.go cmd
, I get the following error:
example: error: couldn't find binding of type context.Context for parameter 0 of main.Cmd.Run(), use kong.Bind(context.Context)
I can bind values of concrete types, but it doesn’t seem like I can bind interface values. Am I missing something?
(Thanks for making Kong, BTW. Great library.)
I am getting the follow warning in my IDE:
struct field tag `cmd help:"Lists all active games"` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair
Nothing specularly bad, just wondering if you know of a work around. I'm getting the issue here - https://github.com/mattcanty/lichess-cli/blob/master/main.go#L15. Note that line 16 also nods to #66!
I'm writing a program that takes a bunch of arguments, as well as a shell command as input (interpreted by kong as an arg
) and exec's that command after doing a little processing. Unfortunately, kong doesn't deal well with the presence of short arguments given to the command-as-argument confuse kong and it errors. Here's an example:
package main
import (
"fmt"
"github.com/alecthomas/kong"
)
var CLI struct {
Run struct {
Cmd []string `arg name:"command" help:"Command to run."`
} `cmd help:"Run command."`
}
func main() {
ctx := kong.Parse(&CLI)
switch ctx.Command() {
case "run <command>":
fmt.Println(CLI)
default:
panic(ctx.Command())
}
}
A plain command works:
$ go run main.go run ls
{{[ls]}}
A command with flags works after a --
:
$ go run main.go run -- ls -la
{{[ls -la]}}
A command with flags is interpreted by kong and errors:
$ go run main.go run ls -la
main: error: unknown flag -l
exit status 1
I would have expected kong to stop parsing further arguments once it finds things fitting the terminating argument string slice & treat the command line given above like it does it in the "works after a --
" example.
Have users pass in the --
flag, but that they can pass the un---
-escaped command line means if they start out without the escape and then add flags later, the command may fail without them realizing (or expecting) it.
Is there a simple way to create a counter-like value?
The main idea behind this is to increase verbosity level. For example:
foo -v
or
foo -vvv
Thanks in advance.
When using the Go standard syntax, the default
struct tag is ignored:
var cli struct {
URL string `help:"URL of the AMQP server" default:"127.0.0.1:5432"`
Bind string `kong:"help:'address to bind to',default:'0.0.0.0:9000'"`
}
[...]
log.Printf("Config: %#v", cli)
results in (indentations by me to enhance readability)
2020/04/26 15:16:18 Config: struct {
URL string "help:\"URL of the AMQP server\" default:\"127.0.0.1:5432\"";
Bind string "kong:\"help:'address to bind to',default:'0.0.0.0:9000'\"" }
{URL:"127.0.0.1:5432", Bind:""}
In and of itself, it is not much of a problem, one can use the simplified syntax. However, every linter gets a bit crazy about that.
If a flag is an enum value, it isn't checked if either the default or the explicitly set value are in the enum.
From @alecthomas:
We need a solution for non-core decoders, plugins, etc. that need configuration through tags.
For example, the "slice" decoder supports an optional sep=','
parameter, which is currently extracted from tags. Two options I can think of, but if you have any ideas I'd be interested:
Tag
to support arbitrary key/value lookups for non-core tags. eg. Tag.Get("sep")
Tag
entirely with a generic key/value thing. eg. Tag.GetBool("cmd")
, Tag.Get("help")
, Tag.GetRune("short")
, etc.Children command under a hidden parent is hidden in the root usage print out but revealed in helped text one level above the hidden parent.
https://gist.github.com/lyonlai/9ba5a40861759612a20ee69d010e0976
./main
and you should see no database update
commands./main database
and you will see the intended to be hidden update commands shows up in the print outThis is to support parsing of flags at any position after they are first encountered.
Vitess2 vitess2.Commands `cmd hidden:"" help:""`
main: error: unexpected argument vitess2, did you mean "vitess"?
This works:
NewVitess vitess2.Commands `cmd hidden:"" help:""`
Differences between Kong and Cobra (https://github.com/spf13/cobra)?
Dear Alec,
I noticed that -h is not enabled by default. I would like to suggest to enable it in root command conditionally, if no other command uses the -h shorthand in postBuild. Do you think it is a good idea? If so, I can PR it, just let me know. Or, even simpler: just enable -h shorthand by default - is it not Linux standard?
Would you be open to adding bash and/or zsh completion generation in a manner similar to cobra?
In the scenario of app invocation from terminal without any command/flags
> my-app
I'd expect the same output of:
> my-app --help
Instead, I have the error about the missing command.
my-app: error: expected one of "cmd1", "cmd2"
Is there a way/configuration to achieve my expected outcome?
The closest function I've found is kong.UsageOnError()
, except it prints usage help for any error (when for any other type of error I'd expect to just print the specific error).
Apologies in advance if I'm missing the obvious.
I'm aiming to have a command with subcommands where there is a default subcommand when no subcommand is entered on the command line. The help message for that would look something like this:
cli --help
Commands:
command command help
command sub sub-command help
cli command --help
Flags:
--command-opt=STRING command-opt help. Should NOT be part of sub command.
cli command sub --help
Flags:
--sub-opt=STRING sub-opt help. Should ONLY be part of sub command.
I've tried a couple of alternatives:
name:""
(full file).Commands:
command default command help
command sub sub help
Command
as parent command with Sub
as nested command field.
Here I don't get command command help
listed in cli --help
and
the --command-opt
appears in cli command sub --help
(full file).
Command
and Sub
as "sibling" commands with Sub
name being: command sub
(full file).
var cli struct {
Command CommandCmd `cmd:"" help:"command help"`
Sub SubCmd `cmd:"" help:"sub-command help" name:"sub"`
}
Here I get an error when trying to run cli command sub
:
main: error: unexpected argument sub
.
kong:""
tags are good because they are the standard form, but are also quite verbose. We should also support raw tags like so:
type cli struct {
Flag bool `required help:"A flag."`
Arg string `arg optional help:"An arg."`
}
The complication here is that the standard Go tag parser only supports tags in the form <key>:"<value>"
. However, we are in luck because @gak's parser already effectively supports the above form, with some minor enhancements. If we parameterise the separator
, the quote
character and the assignment
character, and allow multiple contiguous separator characters, we'll have a parser that works.
Inside kong:""
parser:
separator=","
quote="'"
assignment=":"
Outside:
separator=" " (space)
quote="\""
assignment="="
Is this supported?
Hi! It appears that no license information is specified for Kong, with the exception of camelcase.go and levenshtein.go from 3rd-party sources which you carefully documented.
This came to my attention when I used the dh-make-golang tool to create a preliminary Debian package for Kong (for Chroma 0.6.1) and saw the following warning:
2018/12/22 21:49:17 Could not determine license for "github.com/alecthomas/kong":
GET https://api.github.com/repos/alecthomas/kong/license: 404 Not Found []
Thanks in advance for any clarification!
Hi
To experiment I tried to create my own HelpPrinter
by copying DefaultHelpPrinter
and make some changes.
The Problem I have now, is that CommandTree
is unexported. Would a PR accepted to change that?
I'd like to write a tool similar to pg_ctlcluster
which synopsis is:
pg_ctlcluster <VERSION> <CLUSTER> <COMMAND>
where COMMAND
can be something lile start
, stop
, etc...
For some reasons I'd like to have the command in that specific order without flags for neither VERSION
nor CLUSTER
.
A very naive approach is something like:
var CLI struct {
Version string `arg`
Cluster string `arg`
Start struct {} `cmd`
Stop struct {} `cmd`
}
Which results to:
panic: can't mix positional arguments and branching arguments on *struct { Version string "arg"; Cluster string "arg"; Start struct {} "cmd"; Stop struct {} "cmd" }
Am I missing something?
Some flag handling packages allow shortcuts for commands.
I can do it my putting commands double in the parent struct like this, but it is kind of ugly:
type rootCmd struct {
LongName longNameCmd `cmd:"" help:"Do something."`
X1 longNameCmd `cmd:"" name:"ln"`
}
Is there a better way? Should I (try to) make a pull request for an extra tag, or to enable the short tag for commands as well?
While I was working on custom HelpPrinter
implementation I realized that I had to copy a lot of code from the DefaultHelpPrinter
function. And with the newly added interpolation of the $env
variable, the current HelpPrinter
function is very close to what I was looking for. To close the gap I would like propose the following changes:
For the following Tags:
StringFlag string `enum:"a,b,c" help:"Help."`
I would like to see the following placeholder:
Flags:
--string-flag=a|b|c Help.
And if there is a default
tag:
StringFlag string `enum:"a,b,c" help:"Help." default:"b"`
Maybe something like this:
Flags:
--string-flag=a|(b)|c Help.
Or maybe even make the selected value bold with github.com/fatih/color.
Add a new Option AutomaticEnv
which would do the following:
Visit all flags and args and sets the empty env
field tags with the following:
strings.ToUpper(app.Model.Name+"_"+strings.ReplaceAll(flag.Name,"-","_"))
So a flag-name
would correspond to APPNAME_FLAG_NAME
Let me know what you think. I am willing to do the implementation if you want.
This will hold the state for the parse, which we can then use for not only parsing, but for context-sensitive help, and context-sensitive completion.
For example, if at a subcommand app cmd --help
, the parse context would have the cumulative flags, cumulative commands, as well as the current node. This allows help to be context-sensitive, and completion as well.
hi.
Was a fan of kingpin. I know you moved onto kong. Was wondering if you can provide some examples of
hope this library is as great as kingpin!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.