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 5package imports 6 7import ( 8 "fmt" 9 "io/fs" 10 "path/filepath" 11 "sort" 12 "strconv" 13 "strings" 14 15 "cmd/go/internal/fsys" 16) 17 18func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) { 19 infos, err := fsys.ReadDir(dir) 20 if err != nil { 21 return nil, nil, err 22 } 23 var files []string 24 for _, info := range infos { 25 name := info.Name() 26 27 // If the directory entry is a symlink, stat it to obtain the info for the 28 // link target instead of the link itself. 29 if info.Mode()&fs.ModeSymlink != 0 { 30 info, err = fsys.Stat(filepath.Join(dir, name)) 31 if err != nil { 32 continue // Ignore broken symlinks. 33 } 34 } 35 36 if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) { 37 files = append(files, filepath.Join(dir, name)) 38 } 39 } 40 return scanFiles(files, tags, false) 41} 42 43func ScanFiles(files []string, tags map[string]bool) ([]string, []string, error) { 44 return scanFiles(files, tags, true) 45} 46 47func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]string, []string, error) { 48 imports := make(map[string]bool) 49 testImports := make(map[string]bool) 50 numFiles := 0 51Files: 52 for _, name := range files { 53 r, err := fsys.Open(name) 54 if err != nil { 55 return nil, nil, err 56 } 57 var list []string 58 data, err := ReadImports(r, false, &list) 59 r.Close() 60 if err != nil { 61 return nil, nil, fmt.Errorf("reading %s: %v", name, err) 62 } 63 64 // import "C" is implicit requirement of cgo tag. 65 // When listing files on the command line (explicitFiles=true) 66 // we do not apply build tag filtering but we still do apply 67 // cgo filtering, so no explicitFiles check here. 68 // Why? Because we always have, and it's not worth breaking 69 // that behavior now. 70 for _, path := range list { 71 if path == `"C"` && !tags["cgo"] && !tags["*"] { 72 continue Files 73 } 74 } 75 76 if !explicitFiles && !ShouldBuild(data, tags) { 77 continue 78 } 79 numFiles++ 80 m := imports 81 if strings.HasSuffix(name, "_test.go") { 82 m = testImports 83 } 84 for _, p := range list { 85 q, err := strconv.Unquote(p) 86 if err != nil { 87 continue 88 } 89 m[q] = true 90 } 91 } 92 if numFiles == 0 { 93 return nil, nil, ErrNoGo 94 } 95 return keys(imports), keys(testImports), nil 96} 97 98var ErrNoGo = fmt.Errorf("no Go source files") 99 100func keys(m map[string]bool) []string { 101 var list []string 102 for k := range m { 103 list = append(list, k) 104 } 105 sort.Strings(list) 106 return list 107} 108