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
|
package flag
import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"strings"
"github.com/posener/complete"
)
// Sets is a group of flag sets.
type Sets struct {
// unionSet is the set that is the union of all other sets. This
// has ALL flags defined on it and is the set that is parsed. But
// we maintain the other list of sets so that we can generate proper help.
unionSet *flag.FlagSet
// flagSets is the list of sets that we have. We don't parse these
// directly but use them for help generation and autocompletion.
flagSets []*Set
// completions is our set of autocompletion handlers. This is also
// the union of all available flags similar to unionSet.
completions complete.Flags
}
// NewSets creates a new flag sets.
func NewSets() *Sets {
unionSet := flag.NewFlagSet("", flag.ContinueOnError)
// Errors and usage are expected to be controlled externally by
// checking on the result of Parse.
unionSet.Usage = func() {}
unionSet.SetOutput(ioutil.Discard)
return &Sets{
unionSet: unionSet,
completions: complete.Flags{},
}
}
// NewSet creates a new single flag set. A set should be created for
// any grouping of flags, for example "Common Options", "Auth Options", etc.
func (f *Sets) NewSet(name string) *Set {
flagSet := NewSet(name)
// The union and completions are pointers to our own values
flagSet.unionSet = f.unionSet
flagSet.completions = f.completions
// Keep track of it for help generation
f.flagSets = append(f.flagSets, flagSet)
return flagSet
}
// AddSet adds a single flag set
func (f *Sets) AddSet(set *Set) {
newSet := f.NewSet(set.Name())
set.VisitVars(func(fl *VarFlag) {
newSet.VarFlag(fl)
})
}
// Completions returns the completions for this flag set.
func (f *Sets) Completions() complete.Flags {
return f.completions
}
// Parse parses the given flags, returning any errors.
func (f *Sets) Parse(args []string) error {
return f.unionSet.Parse(args)
}
// Parsed reports whether the command-line flags have been parsed.
func (f *Sets) Parsed() bool {
return f.unionSet.Parsed()
}
// Args returns the remaining args after parsing.
func (f *Sets) Args() []string {
return f.unionSet.Args()
}
// Visit visits the flags in lexicographical order, calling fn for each. It
// visits only those flags that have been set.
func (f *Sets) Visit(fn func(*flag.Flag)) {
f.unionSet.Visit(fn)
}
// Help builds custom help for this command, grouping by flag set.
func (fs *Sets) Help() string {
var out bytes.Buffer
for _, set := range fs.flagSets {
printFlagTitle(&out, set.name+":")
set.VisitAll(func(f *flag.Flag) {
// Skip any hidden flags
if v, ok := f.Value.(FlagVisibility); ok && v.Hidden() {
return
}
printFlagDetail(&out, f)
})
}
return strings.TrimRight(out.String(), "\n")
}
// Help builds custom help for this command, grouping by flag set.
func (fs *Sets) VisitSets(fn func(name string, set *Set)) {
for _, set := range fs.flagSets {
fn(set.name, set)
}
}
// Set is a grouped wrapper around a real flag set and a grouped flag set.
type Set struct {
name string
flagSet *flag.FlagSet
unionSet *flag.FlagSet
completions complete.Flags
vars []*VarFlag
}
// NewSet creates a new flag set.
func NewSet(name string) *Set {
return &Set{
name: name,
flagSet: flag.NewFlagSet(name, flag.ContinueOnError),
}
}
// Name returns the name of this flag set.
func (f *Set) Name() string {
return f.name
}
func (f *Set) Visit(fn func(*flag.Flag)) {
f.flagSet.Visit(fn)
}
func (f *Set) VisitAll(fn func(*flag.Flag)) {
f.flagSet.VisitAll(fn)
}
func (f *Set) VisitVars(fn func(*VarFlag)) {
for _, v := range f.vars {
fn(v)
}
}
// printFlagTitle prints a consistently-formatted title to the given writer.
func printFlagTitle(w io.Writer, s string) {
fmt.Fprintf(w, "%s\n\n", s)
}
// printFlagDetail prints a single flag to the given writer.
func printFlagDetail(w io.Writer, f *flag.Flag) {
// Check if the flag is hidden - do not print any flag detail or help output
// if it is hidden.
if h, ok := f.Value.(FlagVisibility); ok && h.Hidden() {
return
}
// Check for a detailed example
example := ""
if t, ok := f.Value.(FlagExample); ok {
example = t.Example()
}
if example != "" {
fmt.Fprintf(w, " -%s=<%s>\n", f.Name, example)
} else {
fmt.Fprintf(w, " -%s\n", f.Name)
}
usage := reRemoveWhitespace.ReplaceAllString(f.Usage, " ")
indented := wrapAtLengthWithPadding(usage, 6)
fmt.Fprintf(w, "%s\n\n", indented)
}
|