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