1 // Copyright 2011 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.
5 //go:generate go test cmd/go -v -run=TestDocsUpToDate -fixdocs
10 "cmd/go/internal/toolchain"
11 "cmd/go/internal/workcmd"
20 rtrace "runtime/trace"
23 "cmd/go/internal/base"
26 "cmd/go/internal/clean"
28 "cmd/go/internal/envcmd"
30 "cmd/go/internal/fmtcmd"
31 "cmd/go/internal/generate"
33 "cmd/go/internal/help"
34 "cmd/go/internal/list"
35 "cmd/go/internal/modcmd"
36 "cmd/go/internal/modfetch"
37 "cmd/go/internal/modget"
38 "cmd/go/internal/modload"
40 "cmd/go/internal/test"
41 "cmd/go/internal/tool"
42 "cmd/go/internal/trace"
43 "cmd/go/internal/version"
45 "cmd/go/internal/work"
49 base.Go.Commands = []*base.Command{
69 help.HelpBuildConstraint,
82 modfetch.HelpModuleAuth,
97 flag.Usage = base.Usage
105 if args[0] == "get" || args[0] == "help" {
106 if !modload.WillBeEnabled() {
107 // Replace module-aware get with GOPATH get if appropriate.
108 *modget.CmdGet = *get.CmdGet
112 cfg.CmdName = args[0] // for error messages
113 if args[0] == "help" {
114 help.Help(os.Stdout, args[1:])
118 // Diagnose common mistake: GOPATH==GOROOT.
119 // This setting is equivalent to not setting GOPATH at all,
120 // which is not what most people want when they do it.
121 if gopath := cfg.BuildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
122 fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
124 for _, p := range filepath.SplitList(gopath) {
125 // Some GOPATHs have empty directory elements - ignore them.
126 // See issue 21928 for details.
130 // Note: using HasPrefix instead of Contains because a ~ can appear
131 // in the middle of directory elements, such as /tmp/git-1.8.2~rc3
132 // or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
133 if strings.HasPrefix(p, "~") {
134 fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
137 if !filepath.IsAbs(p) {
138 if cfg.Getenv("GOPATH") == "" {
139 // We inferred $GOPATH from $HOME and did a bad job at it.
140 // Instead of dying, uninfer it.
141 cfg.BuildContext.GOPATH = ""
143 fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
150 if cfg.GOROOT == "" {
151 fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: 'go' binary is trimmed and GOROOT is not set\n")
154 if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() {
155 fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
160 for bigCmd := base.Go; ; {
161 for _, cmd := range bigCmd.Commands {
162 if cmd.Name() != args[0] {
165 if len(cmd.Commands) > 0 {
169 help.PrintUsage(os.Stderr, bigCmd)
170 base.SetExitStatus(2)
173 if args[0] == "help" {
174 // Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
175 help.Help(os.Stdout, append(strings.Split(cfg.CmdName, " "), args[1:]...))
178 cfg.CmdName += " " + args[0]
189 if i := strings.LastIndex(cfg.CmdName, " "); i >= 0 {
190 helpArg = " " + cfg.CmdName[:i]
192 fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cfg.CmdName, helpArg)
193 base.SetExitStatus(2)
198 func invoke(cmd *base.Command, args []string) {
199 // 'go env' handles checking the build config
200 if cmd != envcmd.CmdEnv {
202 if cfg.ExperimentErr != nil {
203 base.Fatal(cfg.ExperimentErr)
207 // Set environment (GOOS, GOARCH, etc) explicitly.
208 // In theory all the commands we invoke should have
209 // the same default computation of these as we do,
210 // but in practice there might be skew
211 // This makes sure we all agree.
212 cfg.OrigEnv = toolchain.FilterEnv(os.Environ())
213 cfg.CmdEnv = envcmd.MkEnv()
214 for _, env := range cfg.CmdEnv {
215 if os.Getenv(env.Name) != env.Value {
216 os.Setenv(env.Name, env.Value)
220 cmd.Flag.Usage = func() { cmd.Usage() }
224 base.SetFromGOFLAGS(&cmd.Flag)
225 cmd.Flag.Parse(args[1:])
226 args = cmd.Flag.Args()
229 if cfg.DebugRuntimeTrace != "" {
230 f, err := os.Create(cfg.DebugRuntimeTrace)
232 base.Fatalf("creating trace file: %v", err)
234 if err := rtrace.Start(f); err != nil {
235 base.Fatalf("starting event trace: %v", err)
242 ctx := maybeStartTrace(context.Background())
243 ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
244 cmd.Run(ctx, cmd, args)
249 base.Usage = mainUsage
253 help.PrintUsage(os.Stderr, base.Go)
257 func maybeStartTrace(pctx context.Context) context.Context {
258 if cfg.DebugTrace == "" {
262 ctx, close, err := trace.Start(pctx, cfg.DebugTrace)
264 base.Fatalf("failed to start trace: %v", err)
267 if err := close(); err != nil {
268 base.Fatalf("failed to stop trace: %v", err)