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 }