-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
flag.go
123 lines (113 loc) · 3.31 KB
/
flag.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
// Copyright 2017 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 cmdflag handles flag processing common to several go tools.
package cmdflag
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
"cmd/go/internal/base"
)
// The flag handling part of go commands such as test is large and distracting.
// We can't use the standard flag package because some of the flags from
// our command line are for us, and some are for the binary we're running,
// and some are for both.
// Defn defines a flag we know about.
type Defn struct {
Name string // Name on command line.
BoolVar *bool // If it's a boolean flag, this points to it.
Value flag.Value // The flag.Value represented.
PassToTest bool // Pass to the test binary? Used only by go test.
Present bool // Flag has been seen.
}
// IsBool reports whether v is a bool flag.
func IsBool(v flag.Value) bool {
vv, ok := v.(interface {
IsBoolFlag() bool
})
if ok {
return vv.IsBoolFlag()
}
return false
}
// SetBool sets the addressed boolean to the value.
func SetBool(cmd string, flag *bool, value string) {
x, err := strconv.ParseBool(value)
if err != nil {
SyntaxError(cmd, "illegal bool flag value "+value)
}
*flag = x
}
// SetInt sets the addressed integer to the value.
func SetInt(cmd string, flag *int, value string) {
x, err := strconv.Atoi(value)
if err != nil {
SyntaxError(cmd, "illegal int flag value "+value)
}
*flag = x
}
// SyntaxError reports an argument syntax error and exits the program.
func SyntaxError(cmd, msg string) {
fmt.Fprintf(os.Stderr, "go %s: %s\n", cmd, msg)
if cmd == "test" {
fmt.Fprintf(os.Stderr, `run "go help %s" or "go help testflag" for more information`+"\n", cmd)
} else {
fmt.Fprintf(os.Stderr, `run "go help %s" for more information`+"\n", cmd)
}
os.Exit(2)
}
// Parse sees if argument i is present in the definitions and if so,
// returns its definition, value, and whether it consumed an extra word.
// If the flag begins (cmd+".") it is ignored for the purpose of this function.
func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
arg := args[i]
if strings.HasPrefix(arg, "--") { // reduce two minuses to one
arg = arg[1:]
}
switch arg {
case "-?", "-h", "-help":
base.Usage()
}
if arg == "" || arg[0] != '-' {
return
}
name := arg[1:]
// If there's already a prefix such as "test.", drop it for now.
name = strings.TrimPrefix(name, cmd+".")
equals := strings.Index(name, "=")
if equals >= 0 {
value = name[equals+1:]
name = name[:equals]
}
for _, f = range defns {
if name == f.Name {
// Booleans are special because they have modes -x, -x=true, -x=false.
if f.BoolVar != nil || IsBool(f.Value) {
if equals < 0 { // Otherwise, it's been set and will be verified in SetBool.
value = "true"
} else {
// verify it parses
SetBool(cmd, new(bool), value)
}
} else { // Non-booleans must have a value.
extra = equals < 0
if extra {
if i+1 >= len(args) {
SyntaxError(cmd, "missing argument for flag "+f.Name)
}
value = args[i+1]
}
}
if f.Present {
SyntaxError(cmd, f.Name+" flag may be set only once")
}
f.Present = true
return
}
}
f = nil
return
}