-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathusage.go
More file actions
83 lines (73 loc) · 1.77 KB
/
Copy pathusage.go
File metadata and controls
83 lines (73 loc) · 1.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package envstruct
import (
"fmt"
"io"
"reflect"
"strings"
"text/tabwriter"
)
func usageStruct(prefix string, rt reflect.Type, tw *tabwriter.Writer) {
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i)
if !f.IsExported() {
continue
}
envName := camelToUpperSnake(f.Name)
spec := parseTag(f, envName)
if spec.Ignored {
continue
}
ft := f.Type
// Unwrap pointer for type display and struct check.
isPtr := ft.Kind() == reflect.Ptr
elemType := ft
if isPtr {
elemType = ft.Elem()
}
// Recurse into nested structs.
if isStructField(ft) {
nestedPrefix := spec.Name
if f.Anonymous {
nestedPrefix = prefix
} else if prefix != "" {
nestedPrefix = prefix + "_" + spec.Name
}
nestedPrefix = strings.ToUpper(nestedPrefix)
if isPtr {
usageStruct(nestedPrefix, elemType, tw)
} else {
usageStruct(nestedPrefix, ft, tw)
}
continue
}
// Build key.
key := spec.Name
if prefix != "" {
key = prefix + "_" + spec.Name
}
key = strings.ToUpper(key)
// Type name.
typeName := ft.String()
// Options column.
var opts string
if spec.Required {
opts = "[required]"
} else if spec.HasDefault {
opts = fmt.Sprintf("[default: %s]", spec.DefaultValue)
}
_, _ = fmt.Fprintf(tw, " %s\t%s\t%s\t%s\n", key, typeName, opts, spec.Description)
}
}
func writeUsage(prefix string, spec interface{}, out io.Writer) error {
rv := reflect.ValueOf(spec)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
if rv.Kind() != reflect.Struct {
return fmt.Errorf("envstruct: spec must be a struct or pointer to struct")
}
tw := tabwriter.NewWriter(out, 0, 4, 2, ' ', 0)
_, _ = fmt.Fprintf(tw, " %s\t%s\t%s\t%s\n", "KEY", "TYPE", "DEFAULT", "DESCRIPTION")
usageStruct(prefix, rv.Type(), tw)
return tw.Flush()
}