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