2022-11-16 10:33:57PM

This commit is contained in:
Alexander Wang 2022-11-16 22:33:57 -08:00
parent 7d9ace3ae4
commit 052b461b03
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
3 changed files with 134 additions and 24 deletions

View file

@ -28,7 +28,7 @@ Subcommands:
%[1]s layout [layout name] - Display long help for a particular layout engine %[1]s layout [layout name] - Display long help for a particular layout engine
See more docs and the source code at https://oss.terrastruct.com/d2 See more docs and the source code at https://oss.terrastruct.com/d2
`, ms.Name, ms.Opts.Help()) `, ms.Name, ms.Opts.Defaults())
} }
func layoutHelp(ctx context.Context, ms *xmain.State) error { func layoutHelp(ctx context.Context, ms *xmain.State) error {

45
lib/xmain/flag_helpers.go Normal file
View file

@ -0,0 +1,45 @@
// flag_helpers.go are private functions from pflag/flag.go
package xmain
import "strings"
func wrap(i, w int, s string) string {
if w == 0 {
return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
}
wrap := w - i
var r, l string
if wrap < 24 {
i = 16
wrap = w - i
r += "\n" + strings.Repeat(" ", i)
}
if wrap < 24 {
return strings.Replace(s, "\n", r, -1)
}
slop := 5
wrap = wrap - slop
l, s = wrapN(wrap, slop, s)
r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
for s != "" {
var t string
t, s = wrapN(wrap, slop, s)
r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
}
return r
}
func wrapN(i, slop int, s string) (string, string) {
if i+slop > len(s) {
return s, ""
}
w := strings.LastIndexAny(s[:i], " \t\n")
if w <= 0 {
return s, ""
}
nlPos := strings.LastIndex(s[:i], "\n")
if nlPos > 0 && nlPos < w {
return s[:nlPos], s[nlPos+1:]
}
return s[:w], s[w+1:]
}

View file

@ -1,6 +1,7 @@
package xmain package xmain
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
@ -17,7 +18,7 @@ type Opts struct {
env *xos.Env env *xos.Env
log *cmdlog.Logger log *cmdlog.Logger
registeredEnvs []string flagEnv map[string]string
} }
func NewOpts(env *xos.Env, log *cmdlog.Logger, args []string) *Opts { func NewOpts(env *xos.Env, log *cmdlog.Logger, args []string) *Opts {
@ -30,38 +31,102 @@ func NewOpts(env *xos.Env, log *cmdlog.Logger, args []string) *Opts {
Flags: flags, Flags: flags,
env: env, env: env,
log: log, log: log,
flagEnv: make(map[string]string),
} }
} }
func (o *Opts) Help() string { // Mostly copy pasted pasted from pflag.FlagUsagesWrapped
b := &strings.Builder{} // with modifications for env var
o.Flags.SetOutput(b) func (o *Opts) Defaults() string {
o.Flags.PrintDefaults() buf := new(bytes.Buffer)
if len(o.registeredEnvs) > 0 { var lines []string
b.WriteString("\nYou may persistently set the following as environment variables (flags take precedent):\n")
for i, e := range o.registeredEnvs { maxlen := 0
s := fmt.Sprintf("- $%s", e) maxEnvLen := 0
if i != len(o.registeredEnvs)-1 { o.Flags.VisitAll(func(flag *pflag.Flag) {
s += "\n" if flag.Hidden {
return
} }
b.WriteString(s)
line := ""
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
} else {
line = fmt.Sprintf(" --%s", flag.Name)
}
varname, usage := pflag.UnquoteUsage(flag)
if varname != "" {
line += " " + varname
}
if flag.NoOptDefVal != "" {
switch flag.Value.Type() {
case "string":
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
case "bool":
if flag.NoOptDefVal != "true" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
case "count":
if flag.NoOptDefVal != "+1" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
default:
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
} }
} }
return b.String() line += "\x00"
if len(line) > maxlen {
maxlen = len(line)
}
if e, ok := o.flagEnv[flag.Name]; ok {
line += fmt.Sprintf("$%s", e)
}
line += "\x01"
if len(line) > maxEnvLen {
maxEnvLen = len(line)
}
line += usage
if flag.Value.Type() == "string" {
line += fmt.Sprintf(" (default %q)", flag.DefValue)
} else {
line += fmt.Sprintf(" (default %s)", flag.DefValue)
}
if len(flag.Deprecated) != 0 {
line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
}
lines = append(lines, line)
})
for _, line := range lines {
sidx1 := strings.Index(line, "\x00")
sidx2 := strings.Index(line, "\x01")
spacing1 := strings.Repeat(" ", maxlen-sidx1)
spacing2 := strings.Repeat(" ", (maxEnvLen-maxlen)-sidx2+sidx1)
fmt.Fprintln(buf, line[:sidx1], spacing1, line[sidx1+1:sidx2], spacing2, wrap(maxEnvLen+3, 0, line[sidx2+1:]))
}
return buf.String()
} }
func (o *Opts) getEnv(k string) string { func (o *Opts) getEnv(flag, k string) string {
if k != "" { if k != "" {
o.registeredEnvs = append(o.registeredEnvs, k) o.flagEnv[flag] = k
return o.env.Getenv(k) return o.env.Getenv(k)
} }
return "" return ""
} }
func (o *Opts) Int64(envKey, flag, shortFlag string, defaultVal int64, usage string) (*int64, error) { func (o *Opts) Int64(envKey, flag, shortFlag string, defaultVal int64, usage string) (*int64, error) {
if env := o.getEnv(envKey); env != "" { if env := o.getEnv(flag, envKey); env != "" {
envVal, err := strconv.ParseInt(env, 10, 64) envVal, err := strconv.ParseInt(env, 10, 64)
if err != nil { if err != nil {
return nil, fmt.Errorf(`invalid environment variable %s. Expected int64. Found "%v".`, envKey, envVal) return nil, fmt.Errorf(`invalid environment variable %s. Expected int64. Found "%v".`, envKey, envVal)
@ -73,7 +138,7 @@ func (o *Opts) Int64(envKey, flag, shortFlag string, defaultVal int64, usage str
} }
func (o *Opts) String(envKey, flag, shortFlag string, defaultVal, usage string) *string { func (o *Opts) String(envKey, flag, shortFlag string, defaultVal, usage string) *string {
if env := o.getEnv(envKey); env != "" { if env := o.getEnv(flag, envKey); env != "" {
defaultVal = env defaultVal = env
} }
@ -81,7 +146,7 @@ func (o *Opts) String(envKey, flag, shortFlag string, defaultVal, usage string)
} }
func (o *Opts) Bool(envKey, flag, shortFlag string, defaultVal bool, usage string) (*bool, error) { func (o *Opts) Bool(envKey, flag, shortFlag string, defaultVal bool, usage string) (*bool, error) {
if env := o.getEnv(envKey); env != "" { if env := o.getEnv(flag, envKey); env != "" {
if !boolyEnv(env) { if !boolyEnv(env) {
return nil, fmt.Errorf(`invalid environment variable %s. Expected bool. Found "%s".`, envKey, env) return nil, fmt.Errorf(`invalid environment variable %s. Expected bool. Found "%s".`, envKey, env)
} }