-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenvflagset.go
More file actions
115 lines (99 loc) · 2.26 KB
/
envflagset.go
File metadata and controls
115 lines (99 loc) · 2.26 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
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
package envflagset
import (
"flag"
"fmt"
"log"
"os"
"runtime"
"strings"
)
var (
cn string
prefix string
ver string
fs *flag.FlagSet
showVersion bool
dumpDefault bool
parsed bool
)
const (
fVersion = "Ver"
fDumpEnv = "DumpEnv"
)
func New(name, version string) *flag.FlagSet {
cn = name
SetPrefix(name)
ver = version
// fs = flag.NewFlagSet(name, flag.ExitOnError)
fs = flag.CommandLine
fs.BoolVar(&showVersion, fVersion, false, "Print the version and exit")
fs.BoolVar(&dumpDefault, fDumpEnv, false, "output all default env values")
return fs
}
func SetPrefix(name string) {
if name != "" {
prefix = toEnvName(name) + "_"
}
}
func toEnvName(name string) string {
return strings.ToUpper(strings.Replace(name, "-", "_", -1))
}
func Parse() {
if parsed {
return
}
parsed = true
if len(os.Args) > 1 && strings.HasSuffix(os.Args[1], fDumpEnv) {
Dump(fs, prefix)
os.Exit(0)
}
perr := fs.Parse(os.Args[1:])
switch perr {
case nil:
case flag.ErrHelp:
os.Exit(0)
default:
os.Exit(2)
}
if showVersion {
fmt.Printf("%s version %s %s\n", cn, ver, runtime.Version())
os.Exit(0)
}
err := ParseEnv(fs, prefix)
if err != nil {
log.Fatalf("ParseEnv error: %v", err)
}
}
// ParseEnv parses all registered flags in the given flagset,
// and if they are not already set it attempts to set their values from
// environment variables. Environment variables take the name of the flag but
// are UPPERCASE, have the prefix "PREFIX_", and any dashes are replaced by
// underscores - for example: some-flag => PREFIX_SOME_FLAG
func ParseEnv(fs *flag.FlagSet, prefix string) error {
var err error
alreadySet := make(map[string]bool)
fs.Visit(func(f *flag.Flag) {
alreadySet[f.Name] = true
})
fs.VisitAll(func(f *flag.Flag) {
if !alreadySet[f.Name] {
key := prefix + toEnvName(f.Name)
val := os.Getenv(key)
if val != "" {
if serr := fs.Set(f.Name, val); serr != nil {
err = fmt.Errorf("invalid value %q for %s: %v", val, key, serr)
}
}
}
})
return err
}
func Dump(fs *flag.FlagSet, prefix string) {
fs.VisitAll(func(f *flag.Flag) {
if len(f.Name) < 2 || f.Name == fDumpEnv || f.Name == fVersion {
return
}
key := prefix + toEnvName(f.Name)
fmt.Printf("%s=%q\n", key, f.DefValue)
})
}