)
var (
- unexported bool // -u flag
- matchCase bool // -c flag
- showAll bool // -all flag
- showCmd bool // -cmd flag
- showSrc bool // -src flag
- short bool // -short flag
+ unexported bool // -u flag
+ matchCase bool // -c flag
+ chdir string // -C flag
+ showAll bool // -all flag
+ showCmd bool // -cmd flag
+ showSrc bool // -src flag
+ short bool // -short flag
)
// usage is a replacement usage function for the flags package.
flagSet.Usage = usage
unexported = false
matchCase = false
+ flagSet.StringVar(&chdir, "C", "", "change to `dir` before running command")
flagSet.BoolVar(&unexported, "u", false, "show unexported symbols as well as exported")
flagSet.BoolVar(&matchCase, "c", false, "symbol matching honors case (paths not affected)")
flagSet.BoolVar(&showAll, "all", false, "show all documentation for package")
flagSet.BoolVar(&showSrc, "src", false, "show source code for symbol")
flagSet.BoolVar(&short, "short", false, "one-line representation for each symbol")
flagSet.Parse(args)
+ if chdir != "" {
+ if err := os.Chdir(chdir); err != nil {
+ return err
+ }
+ }
var paths []string
var symbol, method string
// Loop until something is printed.
// The build flags are shared by the build, clean, get, install, list, run,
// and test commands:
//
+// -C dir
+// Change to dir before running the command.
+// Any files named on the command line are interpreted after
+// changing directories.
// -a
// force rebuilding of packages that are already up-to-date.
// -n
// referred to indirectly. For the full set of modules available to a build,
// use 'go list -m -json all'.
//
+// Edit also provides the -C, -n, and -x build flags.
+//
// See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'.
//
// # Print module requirement graph
//
// Usage:
//
-// go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]
+// go vet [-C dir] [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]
//
// Vet runs the Go vet command on the packages named by the import paths.
//
// For a list of checkers and their flags, see 'go tool vet help'.
// For details of a specific checker such as 'printf', see 'go tool vet help printf'.
//
+// The -C flag changes to dir before running the 'go vet' command.
// The -n flag prints commands that would be executed.
// The -x flag prints commands as they are executed.
//
--- /dev/null
+// Copyright 2022 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 main
+
+import (
+ "cmd/go/internal/base"
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestChdir(t *testing.T) {
+ // We want -C to apply to every go subcommand.
+ // Test that every command either has a -C flag registered
+ // or has CustomFlags set. In the latter case, the command
+ // must be explicitly tested in TestScript/chdir.
+ script, err := os.ReadFile("testdata/script/chdir.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var walk func(string, *base.Command)
+ walk = func(name string, cmd *base.Command) {
+ if len(cmd.Commands) > 0 {
+ for _, sub := range cmd.Commands {
+ walk(name+" "+sub.Name(), sub)
+ }
+ return
+ }
+ if !cmd.Runnable() {
+ return
+ }
+ if cmd.CustomFlags {
+ if !strings.Contains(string(script), "# "+name+"\n") {
+ t.Errorf("%s has custom flags, not tested in testdata/script/chdir.txt", name)
+ }
+ return
+ }
+ f := cmd.Flag.Lookup("C")
+ if f == nil {
+ t.Errorf("%s has no -C flag", name)
+ } else if f.Usage != "AddChdirFlag" {
+ t.Errorf("%s has -C flag but not from AddChdirFlag", name)
+ }
+ }
+ walk("go", base.Go)
+}
import (
"flag"
+ "os"
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
flags.BoolVar(&cfg.BuildX, "x", false, "")
}
+// AddChdirFlag adds the -C flag to the flag set.
+func AddChdirFlag(flags *flag.FlagSet) {
+ // The usage message is never printed, but it's used in chdir_test.go
+ // to identify that the -C flag is from AddChdirFlag.
+ flags.Func("C", "AddChdirFlag", os.Chdir)
+}
+
// AddModFlag adds the -mod build flag to the flag set.
func AddModFlag(flags *flag.FlagSet) {
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
func init() {
CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
+ base.AddChdirFlag(&CmdBug.Flag)
}
func runBug(ctx context.Context, cmd *base.Command, args []string) {
func init() {
CmdEnv.Run = runEnv // break init cycle
+ base.AddChdirFlag(&CmdEnv.Flag)
}
var (
func init() {
base.AddBuildFlagsNX(&CmdFmt.Flag)
+ base.AddChdirFlag(&CmdFmt.Flag)
base.AddModFlag(&CmdFmt.Flag)
base.AddModCommonFlags(&CmdFmt.Flag)
}
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
+ base.AddChdirFlag(&cmdDownload.Flag)
base.AddModCommonFlags(&cmdDownload.Flag)
}
referred to indirectly. For the full set of modules available to a build,
use 'go list -m -json all'.
+Edit also provides the -C, -n, and -x build flags.
+
See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'.
`,
}
cmdEdit.Flag.Var(flagFunc(flagRetract), "retract", "")
cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "")
- base.AddModCommonFlags(&cmdEdit.Flag)
base.AddBuildFlagsNX(&cmdEdit.Flag)
+ base.AddChdirFlag(&cmdEdit.Flag)
+ base.AddModCommonFlags(&cmdEdit.Flag)
}
func runEdit(ctx context.Context, cmd *base.Command, args []string) {
func init() {
cmdGraph.Flag.Var(&graphGo, "go", "")
+ base.AddChdirFlag(&cmdGraph.Flag)
base.AddModCommonFlags(&cmdGraph.Flag)
}
}
func init() {
+ base.AddChdirFlag(&cmdInit.Flag)
base.AddModCommonFlags(&cmdInit.Flag)
}
cmdTidy.Flag.BoolVar(&tidyE, "e", false, "")
cmdTidy.Flag.Var(&tidyGo, "go", "")
cmdTidy.Flag.Var(&tidyCompat, "compat", "")
+ base.AddChdirFlag(&cmdTidy.Flag)
base.AddModCommonFlags(&cmdTidy.Flag)
}
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
cmdVendor.Flag.BoolVar(&vendorE, "e", false, "")
cmdVendor.Flag.StringVar(&vendorO, "o", "", "")
+ base.AddChdirFlag(&cmdVendor.Flag)
base.AddModCommonFlags(&cmdVendor.Flag)
}
}
func init() {
+ base.AddChdirFlag(&cmdVerify.Flag)
base.AddModCommonFlags(&cmdVerify.Flag)
}
func init() {
cmdWhy.Run = runWhy // break init cycle
+ base.AddChdirFlag(&cmdWhy.Flag)
base.AddModCommonFlags(&cmdWhy.Flag)
}
}
func init() {
+ base.AddChdirFlag(&CmdTool.Flag)
CmdTool.Flag.BoolVar(&toolN, "n", false, "")
}
}
func init() {
+ base.AddChdirFlag(&CmdVersion.Flag)
CmdVersion.Run = runVersion // break init cycle
}
var CmdVet = &base.Command{
CustomFlags: true,
- UsageLine: "go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]",
+ UsageLine: "go vet [-C dir] [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]",
Short: "report likely mistakes in packages",
Long: `
Vet runs the Go vet command on the packages named by the import paths.
For a list of checkers and their flags, see 'go tool vet help'.
For details of a specific checker such as 'printf', see 'go tool vet help printf'.
+The -C flag changes to dir before running the 'go vet' command.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
The build flags are shared by the build, clean, get, install, list, run,
and test commands:
+ -C dir
+ Change to dir before running the command.
+ Any files named on the command line are interpreted after
+ changing directories.
-a
force rebuilding of packages that are already up-to-date.
-n
// install, list, run, and test commands.
func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
base.AddBuildFlagsNX(&cmd.Flag)
+ base.AddChdirFlag(&cmd.Flag)
cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "")
cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "")
if mask&OmitVFlag == 0 {
cmdEdit.Flag.Var(flagFunc(flagEditworkDropUse), "dropuse", "")
cmdEdit.Flag.Var(flagFunc(flagEditworkReplace), "replace", "")
cmdEdit.Flag.Var(flagFunc(flagEditworkDropReplace), "dropreplace", "")
+ base.AddChdirFlag(&cmdEdit.Flag)
}
func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
}
func init() {
+ base.AddChdirFlag(&cmdInit.Flag)
base.AddModCommonFlags(&cmdInit.Flag)
}
}
func init() {
+ base.AddChdirFlag(&cmdSync.Flag)
base.AddModCommonFlags(&cmdSync.Flag)
}
func init() {
cmdUse.Run = runUse // break init cycle
+ base.AddChdirFlag(&cmdUse.Flag)
base.AddModCommonFlags(&cmdUse.Flag)
}
--- /dev/null
+env OLD=$PWD
+
+# basic -C functionality
+cd $GOROOT/src/math
+go list -C ../strings
+stdout strings
+! go list -C ../nonexist
+stderr 'chdir.*nonexist'
+
+# check for -C in subcommands with custom flag parsing
+# cmd/go/chdir_test.go handles the normal ones more directly.
+
+# go doc
+go doc -C ../strings HasPrefix
+
+# go env
+go env -C $OLD/custom GOMOD
+stdout 'custom[\\/]go.mod'
+! go env -C ../nonexist
+stderr '^invalid value "../nonexist" for flag -C: chdir ../nonexist:.*$'
+
+# go test
+go test -n -C ../strings
+stderr 'strings\.test'
+
+# go vet
+go vet -n -C ../strings
+stderr strings_test
+
+-- custom/go.mod --
+module m