-
Notifications
You must be signed in to change notification settings - Fork 9
/
usage.go
125 lines (95 loc) · 2.07 KB
/
usage.go
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package uconfig
import (
"fmt"
"io"
"os"
"sort"
"strings"
"text/tabwriter"
"github.com/omeid/uconfig/flat"
"github.com/omeid/uconfig/plugins"
)
const usageTag = "usage"
func init() {
plugins.RegisterTag(usageTag)
}
// UsageOutput is the io.Writer used by Usage message printer.
var UsageOutput io.Writer = os.Stdout
// Usage prints out the current config fields, flags, env vars
// and any other source and setting.
func (c *config) Usage() {
setUsageMeta(c.fields)
headers := getHeaders(c.fields)
w := tabwriter.NewWriter(UsageOutput, 0, 0, 4, ' ', 0)
fmt.Fprintf(w, "\nSupported Fields:\n")
fmt.Fprintln(w, strings.ToUpper(strings.Join(headers, "\t")))
dashes := make([]string, len(headers))
for i, f := range headers {
n := len(f)
if n < 5 {
n = 5
}
dashes[i] = strings.Repeat("-", n)
}
fmt.Fprintln(w, strings.Join(dashes, "\t"))
for _, f := range c.fields {
values := make([]string, len(headers))
values[0] = f.Name()
for i, header := range headers[1:] {
value := f.Meta()[header]
values[i+1] = value
}
fmt.Fprintln(w, strings.Join(values, "\t"))
}
err := w.Flush()
if err != nil {
// we are asked for usage which means it is interactive use
// and so panicing is acceptable.
panic(err)
}
}
func setUsageMeta(fs flat.Fields) {
for _, f := range fs {
usage, ok := f.Tag(usageTag)
if !ok {
continue
}
f.Meta()[usageTag] = usage
}
}
func getHeaders(fs flat.Fields) []string {
tagMap := map[string]struct{}{}
for _, f := range fs {
for key := range f.Meta() {
tagMap[key] = struct{}{}
}
}
tags := make([]string, 0, len(tagMap)+2)
tags = append(tags, "field")
for key := range tagMap {
tags = append(tags, key)
}
weights := map[string]int{
"field": 1,
"usage": 99,
"flag": 3,
"env": 4,
}
weight := func(tags []string, i int) int {
key := tags[i]
w, ok := weights[key]
if !ok {
return 98
}
return w
}
sort.SliceStable(tags, func(i, j int) bool {
iw := weight(tags, i)
jw := weight(tags, j)
if iw == jw {
return tags[i] < tags[j]
}
return iw < jw
})
return tags
}