-
Notifications
You must be signed in to change notification settings - Fork 2
/
xconf_usage.go
158 lines (146 loc) · 4.61 KB
/
xconf_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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package xconf
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"sort"
"strings"
"github.com/sandwich-go/xconf/xfield"
"github.com/sandwich-go/xconf/xflag"
"github.com/sandwich-go/xconf/xutil"
)
// Usage 打印usage信息
func (x *XConf) Usage() { x.UsageToWriter(os.Stderr, x.cc.FlagArgs...) }
func (x *XConf) UsageToWriter(w io.Writer, args ...string) {
err := x.usageToWriter(w, args...)
if err == nil {
return
}
x.cc.LogWarning(fmt.Sprintf("UsageToWriter got error:%s", err.Error()))
}
func (x *XConf) usageToWriter(w io.Writer, args ...string) (err error) {
parsedOptions := xflag.ParseArgsToMapStringString(args)
val, got := parsedOptions["help"]
if !got {
val, got = parsedOptions["h"]
}
val = xutil.StringTrim(val)
if got && strings.EqualFold(xutil.StringTrim(val), "xconf") {
// 指定xconf_usage的FlagArgs为空,避免再次触发help逻辑
xx := New(WithFlagSet(newFlagSetContinueOnError("xconf_usage")), WithFlagArgs(), WithErrorHandling(ContinueOnError))
cc := NewOptions()
xutil.PanicErr(xx.Parse(cc))
return xx.usageLinesToWriter(w)
}
if got && strings.EqualFold(xutil.StringTrim(val), "yaml") {
if x.valPtrForUsageDump == nil {
return errors.New("usage for yaml got empty config input")
}
return x.SaveVarToWriterAsYAML(x.valPtrForUsageDump, w)
}
if got && strings.HasSuffix(val, string(ConfigTypeYAML)) { // 输出到文件
defer func() {
if err == nil {
fmt.Println("\n🍺 save config file as yaml to: ", val)
} else {
fmt.Println("\n🚫 got error while save config file as yaml, err:", err.Error())
}
err = nil
}()
if x.valPtrForUsageDump == nil {
return errors.New("usage for yaml file got config input")
}
bytesBuffer := bytes.NewBuffer([]byte{})
err := x.SaveVarToWriterAsYAML(x.valPtrForUsageDump, bytesBuffer)
if err != nil {
return err
}
return xutil.FilePutContents(val, bytesBuffer.Bytes())
}
return x.usageLinesToWriter(w)
}
// usageLinesToWriter 打印usage信息到io.Writer
func (x *XConf) usageLinesToWriter(w io.Writer) error {
optionUsageStr := x.optionUsage
lines, magic, err := x.usageLines()
if err != nil {
return fmt.Errorf("Usage err: " + err.Error())
}
fmt.Fprintln(w, xutil.TableFormat(lines, magic, true, optionUsageStr))
return nil
}
func (x *XConf) usageLines() ([]string, string, error) {
magic := "\x00"
var lineAll []string
lineAll = append(lineAll, "FLAG"+magic+"ENV"+magic+"TYPE"+magic+"USAGE")
allFlag := xflag.GetFlagInfo(x.cc.FlagSet)
for _, v := range allFlag.List {
line := fmt.Sprintf("--%s", v.Name)
line += magic
tag := FlagTypeStr(x, v.Name)
if tag == "-" {
// - 脱离xconf的tag, flag只是我们操作的原子单位,无法将数据附加到flag,再次更新
// M xconf原子tag,但通过环境变量设置的意义不大,考虑移除这部分对环境变量的支持
line += "-"
} else {
line += xflag.FlagToEnvUppercase(x.cc.EnvironPrefix, v.Name)
}
line += magic
line += v.TypeName
line += magic
usage := ""
if info, ok := x.fieldPathInfoMap[v.Name]; ok {
usage = info.Tag.Get("usage")
}
if usage == "" {
usage = v.Usage
}
if !xflag.IsZeroValue(v.Flag, v.DefValue) {
if v.TypeName == "string" {
usage += fmt.Sprintf(" (default %q)", v.DefValue)
} else {
usage += fmt.Sprintf(" (default %s)", v.DefValue)
}
}
line += fmt.Sprintf("|%s| %s", tag, usage)
lineAll = append(lineAll, line)
}
sort.Strings(lineAll[1:])
return lineAll, magic, nil
}
// FlagTypeStr 获取子弹标记,Y代表xconf解析管理的配置,M标识xconf内置配置,D标识Deprecated,-表示为非xconf管理的配置
func FlagTypeStr(x *XConf, name string) (tag string) {
v, ok := x.fieldPathInfoMap[name]
if !ok {
if xutil.ContainStringEqualFold(metaKeyList, name) {
return "M"
}
return "-"
}
if v.TagListXConf.HasIgnoreCase(xfield.TagDeprecated) {
return "D"
}
return "Y"
}
// DumpInfo 打印调试信息
func (x *XConf) DumpInfo() {
var lines []string
lines = append(lines, fmt.Sprintf("# FieldPath: \n%v", x.keysList()))
lines = append(lines, fmt.Sprintf("# DataDest: \n%v", x.dataLatestCached))
lines = append(lines, fmt.Sprintf("# DataMeta: \n%v", x.dataMeta))
hashCode := x.Hash()
lines = append(lines, fmt.Sprintf("# Hash Local : %s", hashCode))
hashCenter := DefaultInvalidHashString
if center := x.dataMeta[MetaKeyLatestHash]; center != nil {
hashCenter = center.(string)
}
lines = append(lines, fmt.Sprintf("# Hash Center : %s", hashCenter))
usageLines, magic, err := x.usageLines()
if err != nil {
x.cc.LogWarning("got error:" + err.Error())
return
}
fmt.Fprintln(os.Stderr, xutil.TableFormat(usageLines, magic, true, lines...))
}