Skip to content

Commit 62aeb77

Browse files
committed
cmd/go: allow full flag processing in go vet
This allows the go tool to run "go vet" with both the build flags that make sense, such as -x and -tags, and vet with all its flags. To do this, create a new package cmd/go/internal/cmdflag to hold functionality common to flag handling for test and vet. Fixes #19350 RELNOTES=yes Change-Id: Ia1ae213bd3f6cab1c5e492501c8d43ce61a7ee89 Reviewed-on: https://go-review.googlesource.com/40112 Reviewed-by: Russ Cox <[email protected]>
1 parent 9ffd933 commit 62aeb77

File tree

8 files changed

+306
-168
lines changed

8 files changed

+306
-168
lines changed

src/cmd/dist/deps.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ var builddeps = map[string][]string{
2121
"cmd/go/internal/load": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/str", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "math/bits", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
2222
"cmd/go/internal/run": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "math/bits", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
2323
"cmd/go/internal/str": {"bytes", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
24-
"cmd/go/internal/test": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "math/bits", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
24+
"cmd/go/internal/test": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/cmdflag", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "math/bits", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
2525
"cmd/go/internal/tool": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
2626
"cmd/go/internal/version": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
27-
"cmd/go/internal/vet": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "math/bits", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
27+
"cmd/go/internal/cmdflag": {"cmd/go/internal/base", "flag", "fmt", "os", "strconv", "strings"},
28+
"cmd/go/internal/vet": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/cmdflag", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "math/bits", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
2829
"cmd/go/internal/web": {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
2930
"cmd/go/internal/work": {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "math/bits", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
3031
"compress/flate": {"bufio", "bytes", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},

src/cmd/go/alldocs.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -798,15 +798,13 @@
798798
//
799799
// Usage:
800800
//
801-
// go vet [-n] [-x] [build flags] [packages]
801+
// go vet [-n] [-x] [build flags] [vet flags] [packages]
802802
//
803803
// Vet runs the Go vet command on the packages named by the import paths.
804804
//
805-
// For more about vet, see 'go doc cmd/vet'.
805+
// For more about vet and its flags, see 'go doc cmd/vet'.
806806
// For more about specifying packages, see 'go help packages'.
807807
//
808-
// To run the vet tool with specific options, run 'go tool vet'.
809-
//
810808
// The -n flag prints commands that would be executed.
811809
// The -x flag prints commands as they are executed.
812810
//

src/cmd/go/go_test.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,8 +2650,6 @@ func TestGoGetInternalWildcard(t *testing.T) {
26502650
}
26512651

26522652
func TestGoVetWithExternalTests(t *testing.T) {
2653-
testenv.MustHaveExternalNetwork(t)
2654-
26552653
tg := testgo(t)
26562654
defer tg.cleanup()
26572655
tg.makeTempdir()
@@ -2662,15 +2660,32 @@ func TestGoVetWithExternalTests(t *testing.T) {
26622660
}
26632661

26642662
func TestGoVetWithTags(t *testing.T) {
2665-
testenv.MustHaveExternalNetwork(t)
2666-
26672663
tg := testgo(t)
26682664
defer tg.cleanup()
26692665
tg.makeTempdir()
26702666
tg.run("install", "cmd/vet")
26712667
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
26722668
tg.runFail("vet", "-tags", "tagtest", "vetpkg")
2673-
tg.grepBoth(`c\.go.*wrong number of args for format`, "go get vetpkg did not run scan tagged file")
2669+
tg.grepBoth(`c\.go.*wrong number of args for format`, "go vet vetpkg did not run scan tagged file")
2670+
}
2671+
2672+
func TestGoVetWithFlagsOn(t *testing.T) {
2673+
tg := testgo(t)
2674+
defer tg.cleanup()
2675+
tg.makeTempdir()
2676+
tg.run("install", "cmd/vet")
2677+
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
2678+
tg.runFail("vet", "-printf", "vetpkg")
2679+
tg.grepBoth("missing argument for Printf", "go vet -printf vetpkg did not find missing argument for Printf")
2680+
}
2681+
2682+
func TestGoVetWithFlagsOff(t *testing.T) {
2683+
tg := testgo(t)
2684+
defer tg.cleanup()
2685+
tg.makeTempdir()
2686+
tg.run("install", "cmd/vet")
2687+
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
2688+
tg.run("vet", "-printf=false", "vetpkg")
26742689
}
26752690

26762691
// Issue 9767, 19769.

src/cmd/go/internal/cmdflag/flag.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package cmdflag handles flag processing common to several go tools.
6+
package cmdflag
7+
8+
import (
9+
"flag"
10+
"fmt"
11+
"os"
12+
"strconv"
13+
"strings"
14+
15+
"cmd/go/internal/base"
16+
)
17+
18+
// The flag handling part of go commands such as test is large and distracting.
19+
// We can't use the standard flag package because some of the flags from
20+
// our command line are for us, and some are for the binary we're running,
21+
// and some are for both.
22+
23+
// Defn defines a flag we know about.
24+
type Defn struct {
25+
Name string // Name on command line.
26+
BoolVar *bool // If it's a boolean flag, this points to it.
27+
Value flag.Value // The flag.Value represented.
28+
PassToTest bool // Pass to the test binary? Used only by go test.
29+
Present bool // Flag has been seen.
30+
}
31+
32+
// IsBool reports whether v is a bool flag.
33+
func IsBool(v flag.Value) bool {
34+
vv, ok := v.(interface {
35+
IsBoolFlag() bool
36+
})
37+
if ok {
38+
return vv.IsBoolFlag()
39+
}
40+
return false
41+
}
42+
43+
// SetBool sets the addressed boolean to the value.
44+
func SetBool(cmd string, flag *bool, value string) {
45+
x, err := strconv.ParseBool(value)
46+
if err != nil {
47+
SyntaxError(cmd, "illegal bool flag value "+value)
48+
}
49+
*flag = x
50+
}
51+
52+
// SetInt sets the addressed integer to the value.
53+
func SetInt(cmd string, flag *int, value string) {
54+
x, err := strconv.Atoi(value)
55+
if err != nil {
56+
SyntaxError(cmd, "illegal int flag value "+value)
57+
}
58+
*flag = x
59+
}
60+
61+
// SyntaxError reports an argument syntax error and exits the program.
62+
func SyntaxError(cmd, msg string) {
63+
fmt.Fprintf(os.Stderr, "go %s: %s\n", cmd, msg)
64+
if cmd == "test" {
65+
fmt.Fprintf(os.Stderr, `run "go help %s" or "go help testflag" for more information`+"\n", cmd)
66+
} else {
67+
fmt.Fprintf(os.Stderr, `run "go help %s" for more information`+"\n", cmd)
68+
}
69+
os.Exit(2)
70+
}
71+
72+
// Parse sees if argument i is present in the definitions and if so,
73+
// returns its definition, value, and whether it consumed an extra word.
74+
// If the flag begins (cmd+".") it is ignored for the purpose of this function.
75+
func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
76+
arg := args[i]
77+
if strings.HasPrefix(arg, "--") { // reduce two minuses to one
78+
arg = arg[1:]
79+
}
80+
switch arg {
81+
case "-?", "-h", "-help":
82+
base.Usage()
83+
}
84+
if arg == "" || arg[0] != '-' {
85+
return
86+
}
87+
name := arg[1:]
88+
// If there's already a prefix such as "test.", drop it for now.
89+
name = strings.TrimPrefix(name, cmd+".")
90+
equals := strings.Index(name, "=")
91+
if equals >= 0 {
92+
value = name[equals+1:]
93+
name = name[:equals]
94+
}
95+
for _, f = range defns {
96+
if name == f.Name {
97+
// Booleans are special because they have modes -x, -x=true, -x=false.
98+
if f.BoolVar != nil || IsBool(f.Value) {
99+
if equals < 0 { // Otherwise, it's been set and will be verified in SetBool.
100+
value = "true"
101+
} else {
102+
// verify it parses
103+
SetBool(cmd, new(bool), value)
104+
}
105+
} else { // Non-booleans must have a value.
106+
extra = equals < 0
107+
if extra {
108+
if i+1 >= len(args) {
109+
SyntaxError(cmd, "missing argument for flag "+f.Name)
110+
}
111+
value = args[i+1]
112+
}
113+
}
114+
if f.Present {
115+
SyntaxError(cmd, f.Name+" flag may be set only once")
116+
}
117+
f.Present = true
118+
return
119+
}
120+
}
121+
f = nil
122+
return
123+
}

0 commit comments

Comments
 (0)