...

Source file src/pkg/cmd/go/internal/imports/scan.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 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	}
   107	

View as plain text