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