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