aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2022-08-05 13:09:20 -0400
committerGopher Robot <gobot@golang.org>2022-11-03 12:16:35 +0000
commit2af48cbb7d85e5fdc635e75b99f949010c607786 (patch)
tree39f2abed89888e1b93967d99de0d5752107677e7 /src/cmd
parentfb4f7fdb26da9ed0fee6beab280c84b399edaa42 (diff)
downloadgo-2af48cbb7d85e5fdc635e75b99f949010c607786.tar.xz
cmd/go: add -C flag
The -C flag is like tar -C or make -C: it changes to the named directory early in command startup, before anything else happens. Fixes #50332. Change-Id: I8e4546f69044cb3a028d4d26dfba482b08cb845d Reviewed-on: https://go-review.googlesource.com/c/go/+/421436 Reviewed-by: Bryan Mills <bcmills@google.com> Auto-Submit: Russ Cox <rsc@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/doc/main.go19
-rw-r--r--src/cmd/go/alldocs.go9
-rw-r--r--src/cmd/go/chdir_test.go49
-rw-r--r--src/cmd/go/internal/base/flag.go8
-rw-r--r--src/cmd/go/internal/bug/bug.go1
-rw-r--r--src/cmd/go/internal/envcmd/env.go1
-rw-r--r--src/cmd/go/internal/fmtcmd/fmt.go1
-rw-r--r--src/cmd/go/internal/modcmd/download.go1
-rw-r--r--src/cmd/go/internal/modcmd/edit.go5
-rw-r--r--src/cmd/go/internal/modcmd/graph.go1
-rw-r--r--src/cmd/go/internal/modcmd/init.go1
-rw-r--r--src/cmd/go/internal/modcmd/tidy.go1
-rw-r--r--src/cmd/go/internal/modcmd/vendor.go1
-rw-r--r--src/cmd/go/internal/modcmd/verify.go1
-rw-r--r--src/cmd/go/internal/modcmd/why.go1
-rw-r--r--src/cmd/go/internal/tool/tool.go1
-rw-r--r--src/cmd/go/internal/version/version.go1
-rw-r--r--src/cmd/go/internal/vet/vet.go3
-rw-r--r--src/cmd/go/internal/work/build.go5
-rw-r--r--src/cmd/go/internal/workcmd/edit.go1
-rw-r--r--src/cmd/go/internal/workcmd/init.go1
-rw-r--r--src/cmd/go/internal/workcmd/sync.go1
-rw-r--r--src/cmd/go/internal/workcmd/use.go1
-rw-r--r--src/cmd/go/testdata/script/chdir.txt31
24 files changed, 136 insertions, 9 deletions
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
index 3c45dd76df..ae1b7575e8 100644
--- a/src/cmd/doc/main.go
+++ b/src/cmd/doc/main.go
@@ -57,12 +57,13 @@ import (
)
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.
@@ -96,6 +97,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
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")
@@ -103,6 +105,11 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
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.
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index a8206c475c..051cf25996 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -100,6 +100,10 @@
// 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
@@ -1233,6 +1237,8 @@
// 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
@@ -1797,7 +1803,7 @@
//
// 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.
//
@@ -1806,6 +1812,7 @@
// 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.
//
diff --git a/src/cmd/go/chdir_test.go b/src/cmd/go/chdir_test.go
new file mode 100644
index 0000000000..44cbb9c3f7
--- /dev/null
+++ b/src/cmd/go/chdir_test.go
@@ -0,0 +1,49 @@
+// 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)
+}
diff --git a/src/cmd/go/internal/base/flag.go b/src/cmd/go/internal/base/flag.go
index 120420a126..9d8d1c0c8d 100644
--- a/src/cmd/go/internal/base/flag.go
+++ b/src/cmd/go/internal/base/flag.go
@@ -6,6 +6,7 @@ package base
import (
"flag"
+ "os"
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
@@ -57,6 +58,13 @@ func AddBuildFlagsNX(flags *flag.FlagSet) {
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", "")
diff --git a/src/cmd/go/internal/bug/bug.go b/src/cmd/go/internal/bug/bug.go
index e667012fbb..ed1813605e 100644
--- a/src/cmd/go/internal/bug/bug.go
+++ b/src/cmd/go/internal/bug/bug.go
@@ -37,6 +37,7 @@ The report includes useful system information.
func init() {
CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
+ base.AddChdirFlag(&CmdBug.Flag)
}
func runBug(ctx context.Context, cmd *base.Command, args []string) {
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index f7f065529d..10499c2d3e 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -57,6 +57,7 @@ For more about environment variables, see 'go help environment'.
func init() {
CmdEnv.Run = runEnv // break init cycle
+ base.AddChdirFlag(&CmdEnv.Flag)
}
var (
diff --git a/src/cmd/go/internal/fmtcmd/fmt.go b/src/cmd/go/internal/fmtcmd/fmt.go
index f6a8d207cd..62b22f6bcf 100644
--- a/src/cmd/go/internal/fmtcmd/fmt.go
+++ b/src/cmd/go/internal/fmtcmd/fmt.go
@@ -21,6 +21,7 @@ import (
func init() {
base.AddBuildFlagsNX(&CmdFmt.Flag)
+ base.AddChdirFlag(&CmdFmt.Flag)
base.AddModFlag(&CmdFmt.Flag)
base.AddModCommonFlags(&CmdFmt.Flag)
}
diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go
index 0b50afb668..f0b62e8b4b 100644
--- a/src/cmd/go/internal/modcmd/download.go
+++ b/src/cmd/go/internal/modcmd/download.go
@@ -84,6 +84,7 @@ func init() {
// 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)
}
diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go
index edc1b19877..5fd13f2627 100644
--- a/src/cmd/go/internal/modcmd/edit.go
+++ b/src/cmd/go/internal/modcmd/edit.go
@@ -127,6 +127,8 @@ Note that this only describes the go.mod file itself, not other modules
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'.
`,
}
@@ -157,8 +159,9 @@ func init() {
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) {
diff --git a/src/cmd/go/internal/modcmd/graph.go b/src/cmd/go/internal/modcmd/graph.go
index 9568c65740..feed6a0005 100644
--- a/src/cmd/go/internal/modcmd/graph.go
+++ b/src/cmd/go/internal/modcmd/graph.go
@@ -41,6 +41,7 @@ var (
func init() {
cmdGraph.Flag.Var(&graphGo, "go", "")
+ base.AddChdirFlag(&cmdGraph.Flag)
base.AddModCommonFlags(&cmdGraph.Flag)
}
diff --git a/src/cmd/go/internal/modcmd/init.go b/src/cmd/go/internal/modcmd/init.go
index bc4620a2a8..e4be73fab0 100644
--- a/src/cmd/go/internal/modcmd/init.go
+++ b/src/cmd/go/internal/modcmd/init.go
@@ -34,6 +34,7 @@ See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'.
}
func init() {
+ base.AddChdirFlag(&cmdInit.Flag)
base.AddModCommonFlags(&cmdInit.Flag)
}
diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go
index d35476eb53..27889941c7 100644
--- a/src/cmd/go/internal/modcmd/tidy.go
+++ b/src/cmd/go/internal/modcmd/tidy.go
@@ -64,6 +64,7 @@ func init() {
cmdTidy.Flag.BoolVar(&tidyE, "e", false, "")
cmdTidy.Flag.Var(&tidyGo, "go", "")
cmdTidy.Flag.Var(&tidyCompat, "compat", "")
+ base.AddChdirFlag(&cmdTidy.Flag)
base.AddModCommonFlags(&cmdTidy.Flag)
}
diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go
index a93c52dbb3..4f820eb13e 100644
--- a/src/cmd/go/internal/modcmd/vendor.go
+++ b/src/cmd/go/internal/modcmd/vendor.go
@@ -61,6 +61,7 @@ func init() {
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)
}
diff --git a/src/cmd/go/internal/modcmd/verify.go b/src/cmd/go/internal/modcmd/verify.go
index 459bf5d070..a5f7f24563 100644
--- a/src/cmd/go/internal/modcmd/verify.go
+++ b/src/cmd/go/internal/modcmd/verify.go
@@ -38,6 +38,7 @@ See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
}
func init() {
+ base.AddChdirFlag(&cmdVerify.Flag)
base.AddModCommonFlags(&cmdVerify.Flag)
}
diff --git a/src/cmd/go/internal/modcmd/why.go b/src/cmd/go/internal/modcmd/why.go
index 8e929a0001..729c88f3f1 100644
--- a/src/cmd/go/internal/modcmd/why.go
+++ b/src/cmd/go/internal/modcmd/why.go
@@ -58,6 +58,7 @@ var (
func init() {
cmdWhy.Run = runWhy // break init cycle
+ base.AddChdirFlag(&cmdWhy.Flag)
base.AddModCommonFlags(&cmdWhy.Flag)
}
diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go
index afa3ac404f..069968b1b6 100644
--- a/src/cmd/go/internal/tool/tool.go
+++ b/src/cmd/go/internal/tool/tool.go
@@ -48,6 +48,7 @@ func isGccgoTool(tool string) bool {
}
func init() {
+ base.AddChdirFlag(&CmdTool.Flag)
CmdTool.Flag.BoolVar(&toolN, "n", false, "")
}
diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go
index 6bbd48c6e6..a0f6123149 100644
--- a/src/cmd/go/internal/version/version.go
+++ b/src/cmd/go/internal/version/version.go
@@ -44,6 +44,7 @@ See also: go doc runtime/debug.BuildInfo.
}
func init() {
+ base.AddChdirFlag(&CmdVersion.Flag)
CmdVersion.Run = runVersion // break init cycle
}
diff --git a/src/cmd/go/internal/vet/vet.go b/src/cmd/go/internal/vet/vet.go
index e5f8af1c37..c73fa5b424 100644
--- a/src/cmd/go/internal/vet/vet.go
+++ b/src/cmd/go/internal/vet/vet.go
@@ -25,7 +25,7 @@ func init() {
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.
@@ -35,6 +35,7 @@ For more about specifying packages, see 'go help packages'.
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.
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index d8b7848071..553cd66ef3 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -58,6 +58,10 @@ will be written to that directory.
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
@@ -282,6 +286,7 @@ const (
// 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 {
diff --git a/src/cmd/go/internal/workcmd/edit.go b/src/cmd/go/internal/workcmd/edit.go
index 8d1d38318b..f5e3304025 100644
--- a/src/cmd/go/internal/workcmd/edit.go
+++ b/src/cmd/go/internal/workcmd/edit.go
@@ -109,6 +109,7 @@ func init() {
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) {
diff --git a/src/cmd/go/internal/workcmd/init.go b/src/cmd/go/internal/workcmd/init.go
index c2513bac35..6fb033ee29 100644
--- a/src/cmd/go/internal/workcmd/init.go
+++ b/src/cmd/go/internal/workcmd/init.go
@@ -34,6 +34,7 @@ for more information.
}
func init() {
+ base.AddChdirFlag(&cmdInit.Flag)
base.AddModCommonFlags(&cmdInit.Flag)
}
diff --git a/src/cmd/go/internal/workcmd/sync.go b/src/cmd/go/internal/workcmd/sync.go
index 7712eb6b6b..9f9962709b 100644
--- a/src/cmd/go/internal/workcmd/sync.go
+++ b/src/cmd/go/internal/workcmd/sync.go
@@ -41,6 +41,7 @@ for more information.
}
func init() {
+ base.AddChdirFlag(&cmdSync.Flag)
base.AddModCommonFlags(&cmdSync.Flag)
}
diff --git a/src/cmd/go/internal/workcmd/use.go b/src/cmd/go/internal/workcmd/use.go
index fcb4e9e5f1..be90989ddd 100644
--- a/src/cmd/go/internal/workcmd/use.go
+++ b/src/cmd/go/internal/workcmd/use.go
@@ -43,6 +43,7 @@ var useR = cmdUse.Flag.Bool("r", false, "")
func init() {
cmdUse.Run = runUse // break init cycle
+ base.AddChdirFlag(&cmdUse.Flag)
base.AddModCommonFlags(&cmdUse.Flag)
}
diff --git a/src/cmd/go/testdata/script/chdir.txt b/src/cmd/go/testdata/script/chdir.txt
new file mode 100644
index 0000000000..8952d18a72
--- /dev/null
+++ b/src/cmd/go/testdata/script/chdir.txt
@@ -0,0 +1,31 @@
+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