package main import ( "flag" "fmt" "os" "strings" "text/tabwriter" "text/template" ) var ( cmdHelp = &command{ Name: "help", Summary: "Show a list of commands or help for one command", Usage: "[COMMAND]", Run: runHelp, } globalUsageTemplate *template.Template commandUsageTemplate *template.Template templFuncs = template.FuncMap{ "descToLines": func(s string) []string { // trim leading/trailing whitespace and split into slice of lines return strings.Split(strings.Trim(s, "\n\t "), "\n") }, "printOption": func(name, defvalue, usage string) string { prefix := "--" if len(name) == 1 { prefix = "-" } return fmt.Sprintf("\n\t%s%s=%s\t%s", prefix, name, defvalue, usage) }, } tabOut *tabwriter.Writer ) func init() { tabOut = tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) commands = append(commands, cmdHelp) globalUsageTemplate = template.Must(template.New("global_usage").Funcs(templFuncs).Parse(` NAME: {{printf "\t%s - %s" .Executable .Description}} USAGE: {{printf "\t%s" .Executable}} [global options] [command options] [arguments...] COMMANDS:{{range .Commands}} {{printf "\t%s\t%s" .Name .Summary}}{{end}} GLOBAL OPTIONS:{{range .Flags}}{{printOption .Name .DefValue .Usage}}{{end}} Global options can also be configured via upper-case environment variables prefixed with "DEXCTL_" For example, "some-flag" => "DEXCTL_SOME_FLAG" Run "{{.Executable}} help " for more details on a specific command. `[1:])) commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(` NAME: {{printf "\t%s - %s" .Cmd.Name .Cmd.Summary}} USAGE: {{printf "\t%s %s %s" .Executable .Cmd.Name .Cmd.Usage}} DESCRIPTION: {{range $line := descToLines .Cmd.Description}}{{printf "\t%s" $line}} {{end}} {{if .CmdFlags}}OPTIONS:{{range .CmdFlags}} {{printOption .Name .DefValue .Usage}}{{end}} {{end}}For help on global options run "{{.Executable}} help" `[1:])) } func runHelp(args []string) (exit int) { if len(args) < 1 { printGlobalUsage() return } var cmd *command for _, c := range commands { if c.Name == args[0] { cmd = c break } } if cmd == nil { stderr("Unrecognized command: %s", args[0]) return 1 } printCommandUsage(cmd) return } func printGlobalUsage() { globalUsageTemplate.Execute(tabOut, struct { Executable string Commands []*command Flags []*flag.Flag Description string }{ cliName, commands, getFlags(globalFS), cliDescription, }) tabOut.Flush() } func printCommandUsage(cmd *command) { commandUsageTemplate.Execute(tabOut, struct { Executable string Cmd *command CmdFlags []*flag.Flag }{ cliName, cmd, getFlags(&cmd.Flags), }) tabOut.Flush() } func getFlags(flagset *flag.FlagSet) (flags []*flag.Flag) { flags = make([]*flag.Flag, 0) flagset.VisitAll(func(f *flag.Flag) { flags = append(flags, f) }) return }