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. 4 5//go:generate ./mkalldocs.sh 6 7package main 8 9import ( 10 "context" 11 "flag" 12 "fmt" 13 "log" 14 "os" 15 "path/filepath" 16 "runtime" 17 "strings" 18 19 "cmd/go/internal/base" 20 "cmd/go/internal/bug" 21 "cmd/go/internal/cfg" 22 "cmd/go/internal/clean" 23 "cmd/go/internal/doc" 24 "cmd/go/internal/envcmd" 25 "cmd/go/internal/fix" 26 "cmd/go/internal/fmtcmd" 27 "cmd/go/internal/generate" 28 "cmd/go/internal/get" 29 "cmd/go/internal/help" 30 "cmd/go/internal/list" 31 "cmd/go/internal/modcmd" 32 "cmd/go/internal/modfetch" 33 "cmd/go/internal/modget" 34 "cmd/go/internal/modload" 35 "cmd/go/internal/run" 36 "cmd/go/internal/test" 37 "cmd/go/internal/tool" 38 "cmd/go/internal/trace" 39 "cmd/go/internal/version" 40 "cmd/go/internal/vet" 41 "cmd/go/internal/work" 42) 43 44func init() { 45 base.Go.Commands = []*base.Command{ 46 bug.CmdBug, 47 work.CmdBuild, 48 clean.CmdClean, 49 doc.CmdDoc, 50 envcmd.CmdEnv, 51 fix.CmdFix, 52 fmtcmd.CmdFmt, 53 generate.CmdGenerate, 54 modget.CmdGet, 55 work.CmdInstall, 56 list.CmdList, 57 modcmd.CmdMod, 58 run.CmdRun, 59 test.CmdTest, 60 tool.CmdTool, 61 version.CmdVersion, 62 vet.CmdVet, 63 64 help.HelpBuildConstraint, 65 help.HelpBuildmode, 66 help.HelpC, 67 help.HelpCache, 68 help.HelpEnvironment, 69 help.HelpFileType, 70 modload.HelpGoMod, 71 help.HelpGopath, 72 get.HelpGopathGet, 73 modfetch.HelpGoproxy, 74 help.HelpImportPath, 75 modload.HelpModules, 76 modget.HelpModuleGet, 77 modfetch.HelpModuleAuth, 78 help.HelpPackages, 79 modfetch.HelpPrivate, 80 test.HelpTestflag, 81 test.HelpTestfunc, 82 modget.HelpVCS, 83 } 84} 85 86func main() { 87 _ = go11tag 88 flag.Usage = base.Usage 89 flag.Parse() 90 log.SetFlags(0) 91 92 args := flag.Args() 93 if len(args) < 1 { 94 base.Usage() 95 } 96 97 if args[0] == "get" || args[0] == "help" { 98 if !modload.WillBeEnabled() { 99 // Replace module-aware get with GOPATH get if appropriate. 100 *modget.CmdGet = *get.CmdGet 101 } 102 } 103 104 cfg.CmdName = args[0] // for error messages 105 if args[0] == "help" { 106 help.Help(os.Stdout, args[1:]) 107 return 108 } 109 110 // Diagnose common mistake: GOPATH==GOROOT. 111 // This setting is equivalent to not setting GOPATH at all, 112 // which is not what most people want when they do it. 113 if gopath := cfg.BuildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) { 114 fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath) 115 } else { 116 for _, p := range filepath.SplitList(gopath) { 117 // Some GOPATHs have empty directory elements - ignore them. 118 // See issue 21928 for details. 119 if p == "" { 120 continue 121 } 122 // Note: using HasPrefix instead of Contains because a ~ can appear 123 // in the middle of directory elements, such as /tmp/git-1.8.2~rc3 124 // or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell. 125 if strings.HasPrefix(p, "~") { 126 fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p) 127 os.Exit(2) 128 } 129 if !filepath.IsAbs(p) { 130 if cfg.Getenv("GOPATH") == "" { 131 // We inferred $GOPATH from $HOME and did a bad job at it. 132 // Instead of dying, uninfer it. 133 cfg.BuildContext.GOPATH = "" 134 } else { 135 fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p) 136 os.Exit(2) 137 } 138 } 139 } 140 } 141 142 // For gccgo this is fine, carry on. 143 // Note that this check is imperfect as we have not yet parsed 144 // the -compiler flag. 145 if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() && runtime.Compiler != "gccgo" { 146 fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT) 147 os.Exit(2) 148 } 149 150 // Set environment (GOOS, GOARCH, etc) explicitly. 151 // In theory all the commands we invoke should have 152 // the same default computation of these as we do, 153 // but in practice there might be skew 154 // This makes sure we all agree. 155 cfg.OrigEnv = os.Environ() 156 cfg.CmdEnv = envcmd.MkEnv() 157 for _, env := range cfg.CmdEnv { 158 if os.Getenv(env.Name) != env.Value { 159 os.Setenv(env.Name, env.Value) 160 } 161 } 162 163BigCmdLoop: 164 for bigCmd := base.Go; ; { 165 for _, cmd := range bigCmd.Commands { 166 if cmd.Name() != args[0] { 167 continue 168 } 169 if len(cmd.Commands) > 0 { 170 bigCmd = cmd 171 args = args[1:] 172 if len(args) == 0 { 173 help.PrintUsage(os.Stderr, bigCmd) 174 base.SetExitStatus(2) 175 base.Exit() 176 } 177 if args[0] == "help" { 178 // Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'. 179 help.Help(os.Stdout, append(strings.Split(cfg.CmdName, " "), args[1:]...)) 180 return 181 } 182 cfg.CmdName += " " + args[0] 183 continue BigCmdLoop 184 } 185 if !cmd.Runnable() { 186 continue 187 } 188 cmd.Flag.Usage = func() { cmd.Usage() } 189 if cmd.CustomFlags { 190 args = args[1:] 191 } else { 192 base.SetFromGOFLAGS(&cmd.Flag) 193 cmd.Flag.Parse(args[1:]) 194 args = cmd.Flag.Args() 195 } 196 ctx := maybeStartTrace(context.Background()) 197 ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command")) 198 cmd.Run(ctx, cmd, args) 199 span.Done() 200 base.Exit() 201 return 202 } 203 helpArg := "" 204 if i := strings.LastIndex(cfg.CmdName, " "); i >= 0 { 205 helpArg = " " + cfg.CmdName[:i] 206 } 207 fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cfg.CmdName, helpArg) 208 base.SetExitStatus(2) 209 base.Exit() 210 } 211} 212 213func init() { 214 base.Usage = mainUsage 215} 216 217func mainUsage() { 218 help.PrintUsage(os.Stderr, base.Go) 219 os.Exit(2) 220} 221 222func maybeStartTrace(pctx context.Context) context.Context { 223 if cfg.DebugTrace == "" { 224 return pctx 225 } 226 227 ctx, close, err := trace.Start(pctx, cfg.DebugTrace) 228 if err != nil { 229 base.Fatalf("failed to start trace: %v", err) 230 } 231 base.AtExit(func() { 232 if err := close(); err != nil { 233 base.Fatalf("failed to stop trace: %v", err) 234 } 235 }) 236 237 return ctx 238} 239