This repository has been archived by the owner on May 18, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcli_source.go
115 lines (99 loc) · 3.56 KB
/
cli_source.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
package configo
import (
"flag"
"fmt"
"io"
"os"
"strconv"
)
// CLISource allows for registration of command line flags
// and stores their actual values, if supplied on the command line.
// It implements the Source interface so it can be used by a Reader.
type CLISource struct {
source []string
flags *flag.FlagSet
registry map[string]*string
boolRegistry map[string]*bool
values map[string]string
output io.Writer
usageMessage string
}
const flagSetName = "configo"
// FromCLI creates a new CLISource for use in a Reader.
// It uses a *flag.FlagSet internally to register and parse the flags.
// Be default the flag.ErrorHandling mode is set to flag.ExitOnError
func FromCLI(options ...CLI) *CLISource {
source := &CLISource{
source: os.Args,
flags: flag.NewFlagSet(flagSetName, flag.ExitOnError),
registry: make(map[string]*string),
boolRegistry: make(map[string]*bool),
values: make(map[string]string),
}
for _, option := range options {
option(source)
}
return source
}
type CLI func(*CLISource)
// ContinueOnError sets the flag.ErrorHandling mode of the internal *flag.FlagSet
// to flag.ContinueOnError. Must be called before Initialize is called.
func ContinueOnError() CLI {
return func(this *CLISource) { this.flags.Init(flagSetName, flag.ContinueOnError) }
}
// PanicOnError sets the flag.ErrorHandling mode of the internal *flag.FlagSet
// to flag.PanicOnError. Must be called before Initialize is called.
func PanicOnError() CLI {
return func(this *CLISource) { this.flags.Init(flagSetName, flag.PanicOnError) }
}
// Flag registers a flag and corresponding usage description with the CLISource.
func Flag(name, description string) CLI {
return func(this *CLISource) { this.registry[name] = this.flags.String(name, "", description) }
}
// BoolFlag registers a boolean flag and corresponding usage description with the CLISource.
// The advantage of this method over Flag for boolean values is that the user can merely
// supply the flag without a value to set the boolean flag to true. This doesn't work with Flag.
func BoolFlag(name, description string) CLI {
return func(this *CLISource) { this.boolRegistry[name] = this.flags.Bool(name, false, description) }
}
// Usage appends a custom message to the end of what is normally printed
// by flag.PrintDefaults().
func Usage(message string) CLI {
return func(this *CLISource) { this.usageMessage = message }
}
// SetOutput allows printing to an io.Writer other than os.Stderr, the default.
func SetOutput(writer io.Writer) CLI {
return func(this *CLISource) { this.flags.SetOutput(writer); this.output = writer }
}
// Initialize parses the internal *flag.FlagSet. Call only after making all Flag calls.
func (this *CLISource) Initialize() {
this.flags.Usage = this.usage
this.flags.Parse(this.source[1:])
this.flags.Visit(this.visitor)
}
func (this *CLISource) usage() {
fmt.Fprintf(this.out(), "Usage of %s:\n", os.Args[0])
this.flags.PrintDefaults()
fmt.Fprintln(this.out(), this.usageMessage)
}
func (this *CLISource) out() io.Writer {
if this.output == nil {
return os.Stderr
}
return this.output
}
func (this *CLISource) visitor(flag *flag.Flag) {
if b, found := this.boolRegistry[flag.Name]; found {
this.values[flag.Name] = strconv.FormatBool(*b)
} else {
this.values[flag.Name] = *this.registry[flag.Name]
}
}
// Strings returns the matching command line flag value, or KeyNotFound.
func (this *CLISource) Strings(key string) ([]string, error) {
value, found := this.values[key]
if !found {
return nil, ErrKeyNotFound
}
return []string{value}, nil
}