package cli import ( "flag" "fmt" "os" "strings" ) // BashCompletionFlag - This flag enables bash-completion for all commands and subcommands // it is hidden by default var BashCompletionFlag = BoolFlag{ Name: "generate-bash-completion", Hide: true, } // VersionFlag - This flag prints the version for the application var VersionFlag = BoolFlag{ Name: "version, v", Usage: "print the version", } // HelpFlay - This flag prints the help for all commands and subcommands // Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand // unless HideHelp is set to true) it is hidden by default var HelpFlag = BoolFlag{ Name: "help, h", Usage: "show help", Hide: true, } // Flag is a common interface related to parsing flags in cli. // For more advanced flag parsing techniques, it is recomended that // this interface be implemented. type Flag interface { fmt.Stringer // Apply Flag settings to the given flag set Apply(*flag.FlagSet) getName() string isNotHidden() bool } func flagSet(name string, flags []Flag) *flag.FlagSet { set := flag.NewFlagSet(name, flag.ContinueOnError) for _, f := range flags { f.Apply(set) } return set } func eachName(longName string, fn func(string)) { parts := strings.Split(longName, ",") for _, name := range parts { name = strings.Trim(name, " ") fn(name) } } // Generic is a generic parseable type identified by a specific flag type Generic interface { Set(value string) error String() string } // GenericFlag is the flag type for types implementing Generic type GenericFlag struct { Name string Value Generic Usage string EnvVar string Hide bool } // String returns the string representation of the generic flag to display the // help text to the user (uses the String() method of the generic flag to show // the value) func (f GenericFlag) String() string { return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage)) } // Apply takes the flagset and calls Set on the generic flag with the value // provided by the user for parsing by the flag func (f GenericFlag) Apply(set *flag.FlagSet) { val := f.Value if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) if envVal := os.Getenv(envVar); envVal != "" { val.Set(envVal) break } } } eachName(f.Name, func(name string) { set.Var(f.Value, name, f.Usage) }) } func (f GenericFlag) getName() string { return f.Name } func (f GenericFlag) isNotHidden() bool { return !f.Hide } func prefixFor(name string) (prefix string) { if len(name) == 1 { prefix = "-" } else { prefix = "--" } return } func prefixedNames(fullName string) (prefixed string) { parts := strings.Split(fullName, ",") for i, name := range parts { name = strings.Trim(name, " ") prefixed += prefixFor(name) + name if i < len(parts)-1 { prefixed += ", " } } return } func withEnvHint(envVar, str string) string { envText := "" if envVar != "" { envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $")) } return str + envText }