...

Source file src/pkg/cmd/go/internal/modload/search.go

     1	// Copyright 2018 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 modload
     6	
     7	import (
     8		"fmt"
     9		"os"
    10		"path/filepath"
    11		"strings"
    12	
    13		"cmd/go/internal/base"
    14		"cmd/go/internal/cfg"
    15		"cmd/go/internal/imports"
    16		"cmd/go/internal/module"
    17		"cmd/go/internal/search"
    18	)
    19	
    20	// matchPackages returns a list of packages in the list of modules
    21	// matching the pattern. Package loading assumes the given set of tags.
    22	func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
    23		match := func(string) bool { return true }
    24		treeCanMatch := func(string) bool { return true }
    25		if !search.IsMetaPackage(pattern) {
    26			match = search.MatchPattern(pattern)
    27			treeCanMatch = search.TreeCanMatchPattern(pattern)
    28		}
    29	
    30		have := map[string]bool{
    31			"builtin": true, // ignore pseudo-package that exists only for documentation
    32		}
    33		if !cfg.BuildContext.CgoEnabled {
    34			have["runtime/cgo"] = true // ignore during walk
    35		}
    36		var pkgs []string
    37	
    38		type pruning int8
    39		const (
    40			pruneVendor = pruning(1 << iota)
    41			pruneGoMod
    42		)
    43	
    44		walkPkgs := func(root, importPathRoot string, prune pruning) {
    45			root = filepath.Clean(root)
    46			filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
    47				if err != nil {
    48					return nil
    49				}
    50	
    51				// Don't use GOROOT/src but do walk down into it.
    52				if path == root && importPathRoot == "" {
    53					return nil
    54				}
    55	
    56				want := true
    57				// Avoid .foo, _foo, and testdata directory trees.
    58				_, elem := filepath.Split(path)
    59				if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
    60					want = false
    61				}
    62	
    63				name := importPathRoot + filepath.ToSlash(path[len(root):])
    64				if importPathRoot == "" {
    65					name = name[1:] // cut leading slash
    66				}
    67				if !treeCanMatch(name) {
    68					want = false
    69				}
    70	
    71				if !fi.IsDir() {
    72					if fi.Mode()&os.ModeSymlink != 0 && want {
    73						if target, err := os.Stat(path); err == nil && target.IsDir() {
    74							fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
    75						}
    76					}
    77					return nil
    78				}
    79	
    80				if !want {
    81					return filepath.SkipDir
    82				}
    83				// Stop at module boundaries.
    84				if (prune&pruneGoMod != 0) && path != root {
    85					if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() {
    86						return filepath.SkipDir
    87					}
    88				}
    89	
    90				if !have[name] {
    91					have[name] = true
    92					if match(name) {
    93						if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
    94							pkgs = append(pkgs, name)
    95						}
    96					}
    97				}
    98	
    99				if elem == "vendor" && (prune&pruneVendor != 0) {
   100					return filepath.SkipDir
   101				}
   102				return nil
   103			})
   104		}
   105	
   106		if useStd {
   107			walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
   108			if treeCanMatch("cmd") {
   109				walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
   110			}
   111		}
   112	
   113		if cfg.BuildMod == "vendor" {
   114			if HasModRoot() {
   115				walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
   116				walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
   117			}
   118			return pkgs
   119		}
   120	
   121		for _, mod := range modules {
   122			if !treeCanMatch(mod.Path) {
   123				continue
   124			}
   125	
   126			var (
   127				root, modPrefix string
   128				isLocal         bool
   129			)
   130			if mod == Target {
   131				if !HasModRoot() {
   132					continue // If there is no main module, we can't search in it.
   133				}
   134				root = ModRoot()
   135				modPrefix = targetPrefix
   136				isLocal = true
   137			} else {
   138				var err error
   139				root, isLocal, err = fetch(mod)
   140				if err != nil {
   141					base.Errorf("go: %v", err)
   142					continue
   143				}
   144				modPrefix = mod.Path
   145			}
   146	
   147			prune := pruneVendor
   148			if isLocal {
   149				prune |= pruneGoMod
   150			}
   151			walkPkgs(root, modPrefix, prune)
   152		}
   153	
   154		return pkgs
   155	}
   156	

View as plain text