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