github.com/tiagovtristao/plz@v13.4.0+incompatible/tools/please_go_test/gotest/find_cover_vars.go (about)

     1  // Package gotest contains utilities used by plz_go_test.
     2  package gotest
     3  
     4  import (
     5  	"go/build"
     6  	"io/ioutil"
     7  	"path"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"gopkg.in/op/go-logging.v1"
    12  
    13  	"github.com/thought-machine/please/src/fs"
    14  )
    15  
    16  var log = logging.MustGetLogger("buildgo")
    17  
    18  // A CoverVar is just a combination of package path and variable name
    19  // for one of the templated-in coverage variables.
    20  type CoverVar struct {
    21  	Dir, ImportPath, ImportName, Var, File string
    22  }
    23  
    24  // replacer is used to replace characters in cover variables.
    25  // The scheme here must match what we do in go_rules.build_defs
    26  var replacer = strings.NewReplacer(
    27  	".", "_",
    28  	"-", "_",
    29  )
    30  
    31  // FindCoverVars searches the given directory recursively to find all Go files with coverage variables.
    32  func FindCoverVars(dir, importPath string, exclude, srcs []string) ([]CoverVar, error) {
    33  	if dir == "" {
    34  		return nil, nil
    35  	}
    36  	excludeMap := map[string]struct{}{}
    37  	for _, e := range exclude {
    38  		excludeMap[e] = struct{}{}
    39  	}
    40  	ret := []CoverVar{}
    41  
    42  	err := fs.Walk(dir, func(name string, isDir bool) error {
    43  		if _, present := excludeMap[name]; present {
    44  			if isDir {
    45  				return filepath.SkipDir
    46  			}
    47  		} else if strings.HasSuffix(name, ".a") && !strings.ContainsRune(path.Base(name), '#') {
    48  			vars, err := findCoverVars(name, importPath, srcs)
    49  			if err != nil {
    50  				return err
    51  			}
    52  			for _, v := range vars {
    53  				ret = append(ret, v)
    54  			}
    55  		}
    56  		return nil
    57  	})
    58  	return ret, err
    59  }
    60  
    61  // findCoverVars scans a directory containing a .a file for any go files.
    62  func findCoverVars(filepath, importPath string, srcs []string) ([]CoverVar, error) {
    63  	dir, file := path.Split(filepath)
    64  	dir = strings.TrimRight(dir, "/")
    65  	fi, err := ioutil.ReadDir(dir)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	importPath = collapseFinalDir(strings.TrimSuffix(filepath, ".a"), importPath)
    70  	ret := make([]CoverVar, 0, len(fi))
    71  	for _, info := range fi {
    72  		name := info.Name()
    73  		if name != file && strings.HasSuffix(name, ".a") {
    74  			log.Warning("multiple .a files in %s, can't determine coverage variables accurately", dir)
    75  			return nil, nil
    76  		} else if strings.HasSuffix(name, ".go") && !info.IsDir() && !contains(path.Join(dir, name), srcs) {
    77  			if ok, err := build.Default.MatchFile(dir, name); ok && err == nil {
    78  				v := "GoCover_" + replacer.Replace(name)
    79  				ret = append(ret, coverVar(dir, importPath, v))
    80  			}
    81  		}
    82  	}
    83  	return ret, nil
    84  }
    85  
    86  func contains(needle string, haystack []string) bool {
    87  	for _, straw := range haystack {
    88  		if straw == needle {
    89  			return true
    90  		}
    91  	}
    92  	return false
    93  }
    94  
    95  func coverVar(dir, importPath, v string) CoverVar {
    96  	log.Info("Found cover variable: %s %s %s", dir, importPath, v)
    97  	f := path.Join(dir, strings.TrimPrefix(v, "GoCover_"))
    98  	if strings.HasSuffix(f, "_go") {
    99  		f = f[:len(f)-3] + ".go"
   100  	}
   101  	return CoverVar{
   102  		Dir:        dir,
   103  		ImportPath: importPath,
   104  		Var:        v,
   105  		File:       f,
   106  	}
   107  }
   108  
   109  // collapseFinalDir mimics what go does with import paths; if the final two components of
   110  // the given path are the same (eg. "src/core/core") it collapses them into one ("src/core")
   111  // Also if importPath is empty then it trims a leading src/
   112  func collapseFinalDir(s, importPath string) string {
   113  	if importPath == "" {
   114  		s = strings.TrimPrefix(s, "src/")
   115  	}
   116  	if path.Base(path.Dir(s)) == path.Base(s) {
   117  		return path.Dir(s)
   118  	}
   119  	return s
   120  }