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