github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/go/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 package main 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "go/build" 12 "io" 13 "log" 14 "os" 15 "os/exec" 16 "path" 17 "path/filepath" 18 "regexp" 19 "runtime" 20 "strings" 21 "sync" 22 "text/template" 23 "unicode" 24 "unicode/utf8" 25 ) 26 27 // A Command is an implementation of a go command 28 // like go build or go fix. 29 type Command struct { 30 // Run runs the command. 31 // The args are the arguments after the command name. 32 Run func(cmd *Command, args []string) 33 34 // UsageLine is the one-line usage message. 35 // The first word in the line is taken to be the command name. 36 UsageLine string 37 38 // Short is the short description shown in the 'go help' output. 39 Short string 40 41 // Long is the long message shown in the 'go help <this-command>' output. 42 Long string 43 44 // Flag is a set of flags specific to this command. 45 Flag flag.FlagSet 46 47 // CustomFlags indicates that the command will do its own 48 // flag parsing. 49 CustomFlags bool 50 } 51 52 // Name returns the command's name: the first word in the usage line. 53 func (c *Command) Name() string { 54 name := c.UsageLine 55 i := strings.Index(name, " ") 56 if i >= 0 { 57 name = name[:i] 58 } 59 return name 60 } 61 62 func (c *Command) Usage() { 63 fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine) 64 fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long)) 65 os.Exit(2) 66 } 67 68 // Runnable reports whether the command can be run; otherwise 69 // it is a documentation pseudo-command such as importpath. 70 func (c *Command) Runnable() bool { 71 return c.Run != nil 72 } 73 74 // Commands lists the available commands and help topics. 75 // The order here is the order in which they are printed by 'go help'. 76 var commands = []*Command{ 77 cmdBuild, 78 cmdClean, 79 cmdEnv, 80 cmdFix, 81 cmdFmt, 82 cmdGenerate, 83 cmdGet, 84 cmdInstall, 85 cmdList, 86 cmdRun, 87 cmdTest, 88 cmdTool, 89 cmdVersion, 90 cmdVet, 91 92 helpC, 93 helpFileType, 94 helpGopath, 95 helpImportPath, 96 helpPackages, 97 helpTestflag, 98 helpTestfunc, 99 } 100 101 var exitStatus = 0 102 var exitMu sync.Mutex 103 104 func setExitStatus(n int) { 105 exitMu.Lock() 106 if exitStatus < n { 107 exitStatus = n 108 } 109 exitMu.Unlock() 110 } 111 112 func main() { 113 _ = go11tag 114 flag.Usage = usage 115 flag.Parse() 116 log.SetFlags(0) 117 118 args := flag.Args() 119 if len(args) < 1 { 120 usage() 121 } 122 123 if args[0] == "help" { 124 help(args[1:]) 125 return 126 } 127 128 // Diagnose common mistake: GOPATH==GOROOT. 129 // This setting is equivalent to not setting GOPATH at all, 130 // which is not what most people want when they do it. 131 if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() { 132 fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath) 133 } else { 134 for _, p := range filepath.SplitList(gopath) { 135 // Note: using HasPrefix instead of Contains because a ~ can appear 136 // in the middle of directory elements, such as /tmp/git-1.8.2~rc3 137 // or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell. 138 if strings.HasPrefix(p, "~") { 139 fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p) 140 os.Exit(2) 141 } 142 if build.IsLocalImport(p) { 143 fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p) 144 os.Exit(2) 145 } 146 } 147 } 148 149 if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() { 150 fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot) 151 os.Exit(2) 152 } 153 154 for _, cmd := range commands { 155 if cmd.Name() == args[0] && cmd.Run != nil { 156 cmd.Flag.Usage = func() { cmd.Usage() } 157 if cmd.CustomFlags { 158 args = args[1:] 159 } else { 160 cmd.Flag.Parse(args[1:]) 161 args = cmd.Flag.Args() 162 } 163 cmd.Run(cmd, args) 164 exit() 165 return 166 } 167 } 168 169 fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0]) 170 setExitStatus(2) 171 exit() 172 } 173 174 var usageTemplate = `Go is a tool for managing Go source code. 175 176 Usage: 177 178 go command [arguments] 179 180 The commands are: 181 {{range .}}{{if .Runnable}} 182 {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} 183 184 Use "go help [command]" for more information about a command. 185 186 Additional help topics: 187 {{range .}}{{if not .Runnable}} 188 {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} 189 190 Use "go help [topic]" for more information about that topic. 191 192 ` 193 194 var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}} 195 196 {{end}}{{.Long | trim}} 197 ` 198 199 var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reserved. 200 // Use of this source code is governed by a BSD-style 201 // license that can be found in the LICENSE file. 202 203 // DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh. 204 // Edit the documentation in other files and rerun mkdoc.sh to generate this one. 205 206 /* 207 {{range .}}{{if .Short}}{{.Short | capitalize}} 208 209 {{end}}{{if .Runnable}}Usage: 210 211 go {{.UsageLine}} 212 213 {{end}}{{.Long | trim}} 214 215 216 {{end}}*/ 217 package main 218 ` 219 220 // tmpl executes the given template text on data, writing the result to w. 221 func tmpl(w io.Writer, text string, data interface{}) { 222 t := template.New("top") 223 t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) 224 template.Must(t.Parse(text)) 225 if err := t.Execute(w, data); err != nil { 226 panic(err) 227 } 228 } 229 230 func capitalize(s string) string { 231 if s == "" { 232 return s 233 } 234 r, n := utf8.DecodeRuneInString(s) 235 return string(unicode.ToTitle(r)) + s[n:] 236 } 237 238 func printUsage(w io.Writer) { 239 tmpl(w, usageTemplate, commands) 240 } 241 242 func usage() { 243 // special case "go test -h" 244 if len(os.Args) > 1 && os.Args[1] == "test" { 245 help([]string{"testflag"}) 246 os.Exit(2) 247 } 248 printUsage(os.Stderr) 249 os.Exit(2) 250 } 251 252 // help implements the 'help' command. 253 func help(args []string) { 254 if len(args) == 0 { 255 printUsage(os.Stdout) 256 // not exit 2: succeeded at 'go help'. 257 return 258 } 259 if len(args) != 1 { 260 fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n") 261 os.Exit(2) // failed at 'go help' 262 } 263 264 arg := args[0] 265 266 // 'go help documentation' generates doc.go. 267 if arg == "documentation" { 268 buf := new(bytes.Buffer) 269 printUsage(buf) 270 usage := &Command{Long: buf.String()} 271 tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...)) 272 return 273 } 274 275 for _, cmd := range commands { 276 if cmd.Name() == arg { 277 tmpl(os.Stdout, helpTemplate, cmd) 278 // not exit 2: succeeded at 'go help cmd'. 279 return 280 } 281 } 282 283 fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg) 284 os.Exit(2) // failed at 'go help cmd' 285 } 286 287 // importPathsNoDotExpansion returns the import paths to use for the given 288 // command line, but it does no ... expansion. 289 func importPathsNoDotExpansion(args []string) []string { 290 if len(args) == 0 { 291 return []string{"."} 292 } 293 var out []string 294 for _, a := range args { 295 // Arguments are supposed to be import paths, but 296 // as a courtesy to Windows developers, rewrite \ to / 297 // in command-line arguments. Handles .\... and so on. 298 if filepath.Separator == '\\' { 299 a = strings.Replace(a, `\`, `/`, -1) 300 } 301 302 // Put argument in canonical form, but preserve leading ./. 303 if strings.HasPrefix(a, "./") { 304 a = "./" + path.Clean(a) 305 if a == "./." { 306 a = "." 307 } 308 } else { 309 a = path.Clean(a) 310 } 311 if a == "all" || a == "std" { 312 out = append(out, allPackages(a)...) 313 continue 314 } 315 out = append(out, a) 316 } 317 return out 318 } 319 320 // importPaths returns the import paths to use for the given command line. 321 func importPaths(args []string) []string { 322 args = importPathsNoDotExpansion(args) 323 var out []string 324 for _, a := range args { 325 if strings.Contains(a, "...") { 326 if build.IsLocalImport(a) { 327 out = append(out, allPackagesInFS(a)...) 328 } else { 329 out = append(out, allPackages(a)...) 330 } 331 continue 332 } 333 out = append(out, a) 334 } 335 return out 336 } 337 338 var atexitFuncs []func() 339 340 func atexit(f func()) { 341 atexitFuncs = append(atexitFuncs, f) 342 } 343 344 func exit() { 345 for _, f := range atexitFuncs { 346 f() 347 } 348 os.Exit(exitStatus) 349 } 350 351 func fatalf(format string, args ...interface{}) { 352 errorf(format, args...) 353 exit() 354 } 355 356 func errorf(format string, args ...interface{}) { 357 log.Printf(format, args...) 358 setExitStatus(1) 359 } 360 361 var logf = log.Printf 362 363 func exitIfErrors() { 364 if exitStatus != 0 { 365 exit() 366 } 367 } 368 369 func run(cmdargs ...interface{}) { 370 cmdline := stringList(cmdargs...) 371 if buildN || buildX { 372 fmt.Printf("%s\n", strings.Join(cmdline, " ")) 373 if buildN { 374 return 375 } 376 } 377 378 cmd := exec.Command(cmdline[0], cmdline[1:]...) 379 cmd.Stdout = os.Stdout 380 cmd.Stderr = os.Stderr 381 if err := cmd.Run(); err != nil { 382 errorf("%v", err) 383 } 384 } 385 386 func runOut(dir string, cmdargs ...interface{}) []byte { 387 cmdline := stringList(cmdargs...) 388 cmd := exec.Command(cmdline[0], cmdline[1:]...) 389 cmd.Dir = dir 390 out, err := cmd.CombinedOutput() 391 if err != nil { 392 os.Stderr.Write(out) 393 errorf("%v", err) 394 out = nil 395 } 396 return out 397 } 398 399 // envForDir returns a copy of the environment 400 // suitable for running in the given directory. 401 // The environment is the current process's environment 402 // but with an updated $PWD, so that an os.Getwd in the 403 // child will be faster. 404 func envForDir(dir string) []string { 405 env := os.Environ() 406 // Internally we only use rooted paths, so dir is rooted. 407 // Even if dir is not rooted, no harm done. 408 return mergeEnvLists([]string{"PWD=" + dir}, env) 409 } 410 411 // mergeEnvLists merges the two environment lists such that 412 // variables with the same name in "in" replace those in "out". 413 func mergeEnvLists(in, out []string) []string { 414 NextVar: 415 for _, inkv := range in { 416 k := strings.SplitAfterN(inkv, "=", 2)[0] 417 for i, outkv := range out { 418 if strings.HasPrefix(outkv, k) { 419 out[i] = inkv 420 continue NextVar 421 } 422 } 423 out = append(out, inkv) 424 } 425 return out 426 } 427 428 // matchPattern(pattern)(name) reports whether 429 // name matches pattern. Pattern is a limited glob 430 // pattern in which '...' means 'any string' and there 431 // is no other special syntax. 432 func matchPattern(pattern string) func(name string) bool { 433 re := regexp.QuoteMeta(pattern) 434 re = strings.Replace(re, `\.\.\.`, `.*`, -1) 435 // Special case: foo/... matches foo too. 436 if strings.HasSuffix(re, `/.*`) { 437 re = re[:len(re)-len(`/.*`)] + `(/.*)?` 438 } 439 reg := regexp.MustCompile(`^` + re + `$`) 440 return func(name string) bool { 441 return reg.MatchString(name) 442 } 443 } 444 445 // hasPathPrefix reports whether the path s begins with the 446 // elements in prefix. 447 func hasPathPrefix(s, prefix string) bool { 448 switch { 449 default: 450 return false 451 case len(s) == len(prefix): 452 return s == prefix 453 case len(s) > len(prefix): 454 if prefix != "" && prefix[len(prefix)-1] == '/' { 455 return strings.HasPrefix(s, prefix) 456 } 457 return s[len(prefix)] == '/' && s[:len(prefix)] == prefix 458 } 459 } 460 461 // treeCanMatchPattern(pattern)(name) reports whether 462 // name or children of name can possibly match pattern. 463 // Pattern is the same limited glob accepted by matchPattern. 464 func treeCanMatchPattern(pattern string) func(name string) bool { 465 wildCard := false 466 if i := strings.Index(pattern, "..."); i >= 0 { 467 wildCard = true 468 pattern = pattern[:i] 469 } 470 return func(name string) bool { 471 return len(name) <= len(pattern) && hasPathPrefix(pattern, name) || 472 wildCard && strings.HasPrefix(name, pattern) 473 } 474 } 475 476 // allPackages returns all the packages that can be found 477 // under the $GOPATH directories and $GOROOT matching pattern. 478 // The pattern is either "all" (all packages), "std" (standard packages) 479 // or a path including "...". 480 func allPackages(pattern string) []string { 481 pkgs := matchPackages(pattern) 482 if len(pkgs) == 0 { 483 fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) 484 } 485 return pkgs 486 } 487 488 func matchPackages(pattern string) []string { 489 match := func(string) bool { return true } 490 treeCanMatch := func(string) bool { return true } 491 if pattern != "all" && pattern != "std" { 492 match = matchPattern(pattern) 493 treeCanMatch = treeCanMatchPattern(pattern) 494 } 495 496 have := map[string]bool{ 497 "builtin": true, // ignore pseudo-package that exists only for documentation 498 } 499 if !buildContext.CgoEnabled { 500 have["runtime/cgo"] = true // ignore during walk 501 } 502 var pkgs []string 503 504 // Commands 505 cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator) 506 filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error { 507 if err != nil || !fi.IsDir() || path == cmd { 508 return nil 509 } 510 name := path[len(cmd):] 511 if !treeCanMatch(name) { 512 return filepath.SkipDir 513 } 514 // Commands are all in cmd/, not in subdirectories. 515 if strings.Contains(name, string(filepath.Separator)) { 516 return filepath.SkipDir 517 } 518 519 // We use, e.g., cmd/gofmt as the pseudo import path for gofmt. 520 name = "cmd/" + name 521 if have[name] { 522 return nil 523 } 524 have[name] = true 525 if !match(name) { 526 return nil 527 } 528 _, err = buildContext.ImportDir(path, 0) 529 if err != nil { 530 if _, noGo := err.(*build.NoGoError); !noGo { 531 log.Print(err) 532 } 533 return nil 534 } 535 pkgs = append(pkgs, name) 536 return nil 537 }) 538 539 for _, src := range buildContext.SrcDirs() { 540 if pattern == "std" && src != gorootSrc { 541 continue 542 } 543 src = filepath.Clean(src) + string(filepath.Separator) 544 filepath.Walk(src, func(path string, fi os.FileInfo, err error) error { 545 if err != nil || !fi.IsDir() || path == src { 546 return nil 547 } 548 549 // Avoid .foo, _foo, and testdata directory trees. 550 _, elem := filepath.Split(path) 551 if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" { 552 return filepath.SkipDir 553 } 554 555 name := filepath.ToSlash(path[len(src):]) 556 if pattern == "std" && strings.Contains(name, ".") { 557 return filepath.SkipDir 558 } 559 if !treeCanMatch(name) { 560 return filepath.SkipDir 561 } 562 if have[name] { 563 return nil 564 } 565 have[name] = true 566 if !match(name) { 567 return nil 568 } 569 _, err = buildContext.ImportDir(path, 0) 570 if err != nil { 571 if _, noGo := err.(*build.NoGoError); noGo { 572 return nil 573 } 574 } 575 pkgs = append(pkgs, name) 576 return nil 577 }) 578 } 579 return pkgs 580 } 581 582 // allPackagesInFS is like allPackages but is passed a pattern 583 // beginning ./ or ../, meaning it should scan the tree rooted 584 // at the given directory. There are ... in the pattern too. 585 func allPackagesInFS(pattern string) []string { 586 pkgs := matchPackagesInFS(pattern) 587 if len(pkgs) == 0 { 588 fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) 589 } 590 return pkgs 591 } 592 593 func matchPackagesInFS(pattern string) []string { 594 // Find directory to begin the scan. 595 // Could be smarter but this one optimization 596 // is enough for now, since ... is usually at the 597 // end of a path. 598 i := strings.Index(pattern, "...") 599 dir, _ := path.Split(pattern[:i]) 600 601 // pattern begins with ./ or ../. 602 // path.Clean will discard the ./ but not the ../. 603 // We need to preserve the ./ for pattern matching 604 // and in the returned import paths. 605 prefix := "" 606 if strings.HasPrefix(pattern, "./") { 607 prefix = "./" 608 } 609 match := matchPattern(pattern) 610 611 var pkgs []string 612 filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { 613 if err != nil || !fi.IsDir() { 614 return nil 615 } 616 if path == dir { 617 // filepath.Walk starts at dir and recurses. For the recursive case, 618 // the path is the result of filepath.Join, which calls filepath.Clean. 619 // The initial case is not Cleaned, though, so we do this explicitly. 620 // 621 // This converts a path like "./io/" to "io". Without this step, running 622 // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io 623 // package, because prepending the prefix "./" to the unclean path would 624 // result in "././io", and match("././io") returns false. 625 path = filepath.Clean(path) 626 } 627 628 // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..". 629 _, elem := filepath.Split(path) 630 dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".." 631 if dot || strings.HasPrefix(elem, "_") || elem == "testdata" { 632 return filepath.SkipDir 633 } 634 635 name := prefix + filepath.ToSlash(path) 636 if !match(name) { 637 return nil 638 } 639 if _, err = build.ImportDir(path, 0); err != nil { 640 if _, noGo := err.(*build.NoGoError); !noGo { 641 log.Print(err) 642 } 643 return nil 644 } 645 pkgs = append(pkgs, name) 646 return nil 647 }) 648 return pkgs 649 } 650 651 // stringList's arguments should be a sequence of string or []string values. 652 // stringList flattens them into a single []string. 653 func stringList(args ...interface{}) []string { 654 var x []string 655 for _, arg := range args { 656 switch arg := arg.(type) { 657 case []string: 658 x = append(x, arg...) 659 case string: 660 x = append(x, arg) 661 default: 662 panic("stringList: invalid argument") 663 } 664 } 665 return x 666 } 667 668 // toFold returns a string with the property that 669 // strings.EqualFold(s, t) iff toFold(s) == toFold(t) 670 // This lets us test a large set of strings for fold-equivalent 671 // duplicates without making a quadratic number of calls 672 // to EqualFold. Note that strings.ToUpper and strings.ToLower 673 // have the desired property in some corner cases. 674 func toFold(s string) string { 675 // Fast path: all ASCII, no upper case. 676 // Most paths look like this already. 677 for i := 0; i < len(s); i++ { 678 c := s[i] 679 if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' { 680 goto Slow 681 } 682 } 683 return s 684 685 Slow: 686 var buf bytes.Buffer 687 for _, r := range s { 688 // SimpleFold(x) cycles to the next equivalent rune > x 689 // or wraps around to smaller values. Iterate until it wraps, 690 // and we've found the minimum value. 691 for { 692 r0 := r 693 r = unicode.SimpleFold(r0) 694 if r <= r0 { 695 break 696 } 697 } 698 // Exception to allow fast path above: A-Z => a-z 699 if 'A' <= r && r <= 'Z' { 700 r += 'a' - 'A' 701 } 702 buf.WriteRune(r) 703 } 704 return buf.String() 705 } 706 707 // foldDup reports a pair of strings from the list that are 708 // equal according to strings.EqualFold. 709 // It returns "", "" if there are no such strings. 710 func foldDup(list []string) (string, string) { 711 clash := map[string]string{} 712 for _, s := range list { 713 fold := toFold(s) 714 if t := clash[fold]; t != "" { 715 if s > t { 716 s, t = t, s 717 } 718 return s, t 719 } 720 clash[fold] = s 721 } 722 return "", "" 723 }