github.com/gernest/nezuko@v0.1.2/internal/modload/search.go (about)

     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  	"github.com/gernest/nezuko/internal/base"
    14  	"github.com/gernest/nezuko/internal/imports"
    15  	"github.com/gernest/nezuko/internal/module"
    16  	"github.com/gernest/nezuko/internal/search"
    17  )
    18  
    19  // matchPackages returns a list of packages in the list of modules
    20  // matching the pattern. Package loading assumes the given set of tags.
    21  func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
    22  	match := func(string) bool { return true }
    23  	treeCanMatch := func(string) bool { return true }
    24  	if !search.IsMetaPackage(pattern) {
    25  		match = search.MatchPattern(pattern)
    26  		treeCanMatch = search.TreeCanMatchPattern(pattern)
    27  	}
    28  
    29  	have := map[string]bool{
    30  		"builtin": true, // ignore pseudo-package that exists only for documentation
    31  	}
    32  	var pkgs []string
    33  
    34  	walkPkgs := func(root, importPathRoot string) {
    35  		root = filepath.Clean(root)
    36  		var cmd string
    37  		filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
    38  			if err != nil {
    39  				return nil
    40  			}
    41  
    42  			// Don't use GOROOT/src but do walk down into it.
    43  			if path == root && importPathRoot == "" {
    44  				return nil
    45  			}
    46  
    47  			// GOROOT/src/cmd makes use of GOROOT/src/cmd/vendor,
    48  			// which module mode can't deal with. Eventually we'll stop using
    49  			// that vendor directory, and then we can remove this exclusion.
    50  			// golang.org/issue/26924.
    51  			if path == cmd {
    52  				return filepath.SkipDir
    53  			}
    54  
    55  			want := true
    56  			// Avoid .foo, _foo, and testdata directory trees.
    57  			_, elem := filepath.Split(path)
    58  			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
    59  				want = false
    60  			}
    61  
    62  			name := importPathRoot + filepath.ToSlash(path[len(root):])
    63  			if importPathRoot == "" {
    64  				name = name[1:] // cut leading slash
    65  			}
    66  			if !treeCanMatch(name) {
    67  				want = false
    68  			}
    69  
    70  			if !fi.IsDir() {
    71  				if fi.Mode()&os.ModeSymlink != 0 && want {
    72  					if target, err := os.Stat(path); err == nil && target.IsDir() {
    73  						fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
    74  					}
    75  				}
    76  				return nil
    77  			}
    78  
    79  			if !want {
    80  				return filepath.SkipDir
    81  			}
    82  			if path != root {
    83  				if _, err := os.Stat(filepath.Join(path, "z.mod")); err == nil {
    84  					return filepath.SkipDir
    85  				}
    86  			}
    87  
    88  			if !have[name] {
    89  				have[name] = true
    90  				if match(name) {
    91  					if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
    92  						pkgs = append(pkgs, name)
    93  					}
    94  				}
    95  			}
    96  
    97  			if elem == "vendor" {
    98  				return filepath.SkipDir
    99  			}
   100  			return nil
   101  		})
   102  	}
   103  
   104  	for _, mod := range modules {
   105  		if !treeCanMatch(mod.Path) {
   106  			continue
   107  		}
   108  		var root string
   109  		if mod.Version == "" {
   110  			if !HasModRoot() {
   111  				continue // If there is no main module, we can't search in it.
   112  			}
   113  			root = ModRoot()
   114  		} else {
   115  			var err error
   116  			root, _, err = fetch(mod)
   117  			if err != nil {
   118  				base.Errorf("z: %v", err)
   119  				continue
   120  			}
   121  		}
   122  		walkPkgs(root, mod.Path)
   123  	}
   124  
   125  	return pkgs
   126  }