forked from namsral/flag
-
Notifications
You must be signed in to change notification settings - Fork 0
/
extras.go
192 lines (163 loc) · 4.51 KB
/
extras.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package flag
import (
"bufio"
"os"
"strings"
secrets "github.com/ijustfool/docker-secrets"
)
// EnvironmentPrefix defines a string that will be implicitely prefixed to a
// flag name before looking it up in the environment variables.
var EnvironmentPrefix = ""
// ParseEnv parses flags from environment variables.
// Flags already set will be ignored.
func (f *FlagSet) ParseEnv(environ []string) error {
dockerSecrets, _ := secrets.NewDockerSecrets("")
env := make(map[string]string)
for _, s := range environ {
i := strings.Index(s, "=")
if i < 1 {
continue
}
env[s[0:i]] = s[i+1 : len(s)]
}
m := f.formal
for _, flag := range m {
name := flag.Name
if dockerSecrets != nil {
if secret, err := dockerSecrets.Get(name); err == nil && flag.Value.Set(secret) == nil {
continue
}
}
_, set := f.actual[name]
if set {
continue
}
flag, alreadythere := m[name]
if !alreadythere {
if name == "help" || name == "h" { // special case for nice help message.
f.usage()
return ErrHelp
}
return f.failf("environment variable provided but not defined: %s", name)
}
envKey := strings.ToUpper(flag.Name)
if f.envPrefix != "" {
envKey = f.envPrefix + "_" + envKey
}
envKey = strings.Replace(envKey, "-", "_", -1)
value, isSet := env[envKey]
if !isSet {
continue
}
hasValue := false
if len(value) > 0 {
hasValue = true
}
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
if hasValue {
if err := fv.Set(value); err != nil {
return f.failf("invalid boolean value %q for environment variable %s: %v", value, name, err)
}
} else {
// flag without value is regarded a bool
fv.Set("true")
}
} else {
if err := flag.Value.Set(value); err != nil {
return f.failf("invalid value %q for environment variable %s: %v", value, name, err)
}
}
// update f.actual
if f.actual == nil {
f.actual = make(map[string]*Flag)
}
f.actual[name] = flag
}
return nil
}
// NewFlagSetWithEnvPrefix returns a new empty flag set with the specified name,
// environment variable prefix, and error handling property.
func NewFlagSetWithEnvPrefix(name string, prefix string, errorHandling ErrorHandling) *FlagSet {
f := NewFlagSet(name, errorHandling)
f.envPrefix = prefix
return f
}
// DefaultConfigFlagname defines the flag name of the optional config file
// path. Used to lookup and parse the config file when a default is set and
// available on disk.
var DefaultConfigFlagname = "config"
// ParseFile parses flags from the file in path.
// Same format as commandline argumens, newlines and lines beginning with a
// "#" charater are ignored. Flags already set will be ignored.
func (f *FlagSet) ParseFile(path string) error {
// Extract arguments from file
fp, err := os.Open(path)
if err != nil {
return err
}
defer fp.Close()
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
line := scanner.Text()
// Ignore empty lines
if len(line) == 0 {
continue
}
// Ignore comments
if line[:1] == "#" {
continue
}
// Match `key=value` and `key value`
var name, value string
hasValue := false
for i, v := range line {
if v == '=' || v == ' ' {
hasValue = true
name, value = line[:i], line[i+1:]
break
}
}
if hasValue == false {
name = line
}
// Ignore flag when already set; arguments have precedence over file
if f.actual[name] != nil {
continue
}
m := f.formal
flag, alreadythere := m[name]
if !alreadythere {
if name == "help" || name == "h" { // special case for nice help message.
f.usage()
return ErrHelp
}
return f.failf("configuration variable provided but not defined: %s", name)
}
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
if hasValue {
if err := fv.Set(value); err != nil {
return f.failf("invalid boolean value %q for configuration variable %s: %v", value, name, err)
}
} else {
// flag without value is regarded a bool
fv.Set("true")
}
} else {
if err := flag.Value.Set(value); err != nil {
return f.failf("invalid value %q for configuration variable %s: %v", value, name, err)
}
}
// update f.actual
if f.actual == nil {
f.actual = make(map[string]*Flag)
}
f.actual[name] = flag
}
if err := scanner.Err(); err != nil {
return err
}
return nil
}