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