github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/go/loader/hash.go (about)

     1  package loader
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/amarpal/go-tools/go/buildid"
    10  	"github.com/amarpal/go-tools/lintcmd/cache"
    11  )
    12  
    13  // computeHash computes a package's hash. The hash is based on all Go
    14  // files that make up the package, as well as the hashes of imported
    15  // packages.
    16  func computeHash(c *cache.Cache, pkg *PackageSpec) (cache.ActionID, error) {
    17  	key := c.NewHash("package " + pkg.PkgPath)
    18  	fmt.Fprintf(key, "goos %s goarch %s\n", runtime.GOOS, runtime.GOARCH)
    19  	fmt.Fprintf(key, "import %q\n", pkg.PkgPath)
    20  
    21  	// Compute the hashes of all files making up the package. As an
    22  	// optimization, we use the build ID that Go already computed for
    23  	// us, because it is virtually identical to hashed all
    24  	// CompiledGoFiles.
    25  	success := false
    26  	if pkg.ExportFile != "" {
    27  		id, err := getBuildid(pkg.ExportFile)
    28  		if err == nil {
    29  			if idx := strings.IndexRune(id, '/'); idx > -1 {
    30  				fmt.Fprintf(key, "files %s\n", id[:idx])
    31  				success = true
    32  			}
    33  		}
    34  	}
    35  	if !success {
    36  		for _, f := range pkg.CompiledGoFiles {
    37  			h, err := cache.FileHash(f)
    38  			if err != nil {
    39  				return cache.ActionID{}, err
    40  			}
    41  			fmt.Fprintf(key, "file %s %x\n", f, h)
    42  		}
    43  	}
    44  
    45  	imps := make([]*PackageSpec, 0, len(pkg.Imports))
    46  	for _, v := range pkg.Imports {
    47  		imps = append(imps, v)
    48  	}
    49  	sort.Slice(imps, func(i, j int) bool {
    50  		return imps[i].PkgPath < imps[j].PkgPath
    51  	})
    52  
    53  	for _, dep := range imps {
    54  		if dep.ExportFile == "" {
    55  			fmt.Fprintf(key, "import %s \n", dep.PkgPath)
    56  		} else {
    57  			id, err := getBuildid(dep.ExportFile)
    58  			if err == nil {
    59  				fmt.Fprintf(key, "import %s %s\n", dep.PkgPath, id)
    60  			} else {
    61  				fh, err := cache.FileHash(dep.ExportFile)
    62  				if err != nil {
    63  					return cache.ActionID{}, err
    64  				}
    65  				fmt.Fprintf(key, "import %s %x\n", dep.PkgPath, fh)
    66  			}
    67  		}
    68  	}
    69  	return key.Sum(), nil
    70  }
    71  
    72  var buildidCache = map[string]string{}
    73  
    74  func getBuildid(f string) (string, error) {
    75  	if h, ok := buildidCache[f]; ok {
    76  		return h, nil
    77  	}
    78  	h, err := buildid.ReadFile(f)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  	buildidCache[f] = h
    83  	return h, nil
    84  }