feat: show environment variables where from values are taken and better usage information.

This commit is contained in:
Andrey Parhomenko 2024-07-21 02:18:38 +05:00
parent bf3699257d
commit b5baabf74f
3 changed files with 63 additions and 10 deletions

View file

@ -59,10 +59,8 @@ var (
), ),
).Desc( ).Desc(
"the testing program to show how to use the lib", "the testing program to show how to use the lib",
).Ldesc( ).Ldesc(`This is the long description where you
"this is the long description where you " + can put anything you want about the program.`)
"can put anything you want about the program",
)
) )
func main() { func main() {

View file

@ -15,6 +15,7 @@ type Flags struct {
tool *Tool tool *Tool
args []string args []string
parsedArgs []string parsedArgs []string
envNameMap map[string] []string
envMap map[string]string envMap map[string]string
} }
@ -34,6 +35,7 @@ func (flags *Flags) setEnv(
name string, name string,
env []string, env []string,
) bool { ) bool {
flags.envNameMap[name] = env
for _, k := range env { for _, k := range env {
value, has := os.LookupEnv(k) value, has := os.LookupEnv(k)
if !has { if !has {
@ -47,6 +49,8 @@ func (flags *Flags) setEnv(
return false return false
} }
// Set new string variable
// to parse.
func (flags *Flags) StringVar( func (flags *Flags) StringVar(
p *string, p *string,
name string, name string,
@ -58,6 +62,7 @@ func (flags *Flags) StringVar(
flags.setEnv(name, env) flags.setEnv(name, env)
} }
// Set new int variable to parse.
func (flags *Flags) IntVar( func (flags *Flags) IntVar(
p *int, p *int,
name string, name string,
@ -69,6 +74,7 @@ func (flags *Flags) IntVar(
flags.setEnv(name, env) flags.setEnv(name, env)
} }
// Set new int64 variable to parse.
func (flags *Flags) Int64Var( func (flags *Flags) Int64Var(
p *int64, p *int64,
name string, name string,
@ -80,6 +86,7 @@ func (flags *Flags) Int64Var(
flags.setEnv(name, env) flags.setEnv(name, env)
} }
// Set new bool variable to parse.
func (flags *Flags) BoolVar( func (flags *Flags) BoolVar(
p *bool, p *bool,
name string, name string,
@ -91,6 +98,7 @@ func (flags *Flags) BoolVar(
flags.setEnv(name, env) flags.setEnv(name, env)
} }
// Set new float64 variable to parse.
func (flags *Flags) Float64Var( func (flags *Flags) Float64Var(
p *float64, p *float64,
name string, name string,
@ -102,6 +110,7 @@ func (flags *Flags) Float64Var(
flags.setEnv(name, env) flags.setEnv(name, env)
} }
// Set new duration variable to parse.
func (flags *Flags) DurationVar( func (flags *Flags) DurationVar(
p *time.Duration, p *time.Duration,
name string, name string,
@ -126,14 +135,18 @@ func (flags *Flags) Parse() []string {
return flags.parsedArgs return flags.parsedArgs
} }
// Get all the arguments, including the
// parsed ones.
func (flags *Flags) AllArgs() []string { func (flags *Flags) AllArgs() []string {
return flags.args return flags.args
} }
// Get all the arguments going after options.
func (flags *Flags) Args() []string { func (flags *Flags) Args() []string {
return flags.parsedArgs return flags.parsedArgs
} }
// Get the tool currently called.
func (flags *Flags) Tool() *Tool { func (flags *Flags) Tool() *Tool {
return flags.tool return flags.tool
} }

View file

@ -2,6 +2,7 @@ package mtool
import ( import (
"text/tabwriter" "text/tabwriter"
"strings"
"flag" "flag"
"sort" "sort"
"fmt" "fmt"
@ -118,14 +119,28 @@ func (t *Tool) Run(args []string) {
flags := &Flags{ flags := &Flags{
FlagSet : flagSet, FlagSet : flagSet,
envMap: make(map[string]string), envMap: make(map[string]string),
envNameMap: make(map[string] []string),
} }
out := flags.Output() out := flags.Output()
flags.Usage = func() { flags.Usage = func() {
n := 0 nflags := 0
flags.VisitAll(func(f *flag.Flag){ flags.VisitAll(func(f *flag.Flag){
n++ nflags++
varNames, ok := flags.envNameMap[f.Name]
if !ok || len(varNames) == 0 {
return
}
f.Usage += " ("
for i, name := range varNames {
f.Usage += "$"+name
if i < len(varNames) - 1 {
f.Usage += ", "
}
}
f.Usage += ")"
}) })
hasOptions := n != 0 hasOptions := nflags != 0
// Name // Name
if usageTool.desc != "" { if usageTool.desc != "" {
@ -162,6 +177,7 @@ func (t *Tool) Run(args []string) {
// Options // Options
if hasOptions { if hasOptions {
fmt.Fprintln(out, "\nOptions:") fmt.Fprintln(out, "\nOptions:")
fmt.Fprintln(out, " --\n option terminator")
flags.PrintDefaults() flags.PrintDefaults()
} }
@ -178,7 +194,18 @@ func (t *Tool) Run(args []string) {
// Print available sub commands if // Print available sub commands if
// got no arguments. // got no arguments.
if len(args) == 0 { if len(args) == 0 || func() bool {
toolName := args[0]
_, ok := t.subs[toolName]
if ok {
return false
}
if toolName != "" && toolName[0]=='-' {
return true
}
return false
}() {
if t.desc != "" { if t.desc != "" {
fmt.Fprintf( fmt.Fprintf(
@ -191,7 +218,11 @@ func (t *Tool) Run(args []string) {
" %s <command>\n", t.FullName()) " %s <command>\n", t.FullName())
if t.ldesc != "" { if t.ldesc != "" {
fmt.Fprintf(out, "\nDescription:\n %s\n", t.ldesc) fmt.Fprintf(
out,
"\nDescription:\n %s\n",
t.GetLongFormattedDesc(),
)
} }
if len(t.subs) > 0 { if len(t.subs) > 0 {
@ -205,7 +236,13 @@ func (t *Tool) Run(args []string) {
args = args[1:] args = args[1:]
if _, ok := t.subs[toolName] ; !ok { if _, ok := t.subs[toolName] ; !ok {
fmt.Printf("%s: No such util %q'\n", t.ProgName(), toolName) fmt.Fprintf(
out,
"%s: No such util %q'\n" +
"use ' %s ' to see available commands\n",
t.FullName(), toolName,
t.FullName(),
)
os.Exit(1) os.Exit(1)
} }
@ -213,3 +250,8 @@ func (t *Tool) Run(args []string) {
usageTool = sub usageTool = sub
sub.Run(args) sub.Run(args)
} }
func (t *Tool) GetLongFormattedDesc() string {
return strings.ReplaceAll(t.ldesc, "\n", "\n ")
}