Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 31 additions & 26 deletions internal/loader/artifact_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import (
"encoding/hex"
"go/token"
"go/types"
"io"
"os"
"path/filepath"
"runtime"
"strconv"

"golang.org/x/tools/go/gcexportdata"
)
Expand Down Expand Up @@ -62,7 +62,7 @@ func loaderArtifactPath(env []string, meta *packageMeta, isLocal bool) (string,

func loaderArtifactKey(meta *packageMeta, isLocal bool) (string, error) {
sum := sha256.New()
sum.Write([]byte("wire-loader-artifact-v3\n"))
sum.Write([]byte("wire-loader-artifact-v4\n"))
sum.Write([]byte(runtime.Version()))
sum.Write([]byte{'\n'})
sum.Write([]byte(meta.ImportPath))
Expand All @@ -73,26 +73,15 @@ func loaderArtifactKey(meta *packageMeta, isLocal bool) (string, error) {
sum.Write([]byte(meta.Export))
sum.Write([]byte{'\n'})
if meta.Export != "" {
info, err := os.Stat(meta.Export)
h, err := hashFileContent(meta.Export)
if err != nil {
return "", err
}
sum.Write([]byte(strconv.FormatInt(info.Size(), 10)))
sum.Write([]byte{'\n'})
sum.Write([]byte(strconv.FormatInt(info.ModTime().UnixNano(), 10)))
sum.Write([]byte(h))
sum.Write([]byte{'\n'})
} else {
for _, name := range metaFiles(meta) {
info, err := os.Stat(name)
if err != nil {
return "", err
}
sum.Write([]byte(name))
sum.Write([]byte{'\n'})
sum.Write([]byte(strconv.FormatInt(info.Size(), 10)))
sum.Write([]byte{'\n'})
sum.Write([]byte(strconv.FormatInt(info.ModTime().UnixNano(), 10)))
sum.Write([]byte{'\n'})
if err := hashMetaFiles(sum, metaFiles(meta)); err != nil {
return "", err
}
}
if meta.Error != nil {
Expand All @@ -101,19 +90,35 @@ func loaderArtifactKey(meta *packageMeta, isLocal bool) (string, error) {
}
return hex.EncodeToString(sum.Sum(nil)), nil
}
for _, name := range metaFiles(meta) {
info, err := os.Stat(name)
if err != nil {
return "", err
}
if err := hashMetaFiles(sum, metaFiles(meta)); err != nil {
return "", err
}
return hex.EncodeToString(sum.Sum(nil)), nil
}

// hashFileContent returns the hex-encoded SHA-256 of the file content.
func hashFileContent(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
h := sha256.Sum256(data)
return hex.EncodeToString(h[:]), nil
}

// hashMetaFiles writes content-based hashes for each file into sum.
func hashMetaFiles(sum io.Writer, names []string) error {
for _, name := range names {
sum.Write([]byte(name))
sum.Write([]byte{'\n'})
sum.Write([]byte(strconv.FormatInt(info.Size(), 10)))
sum.Write([]byte{'\n'})
sum.Write([]byte(strconv.FormatInt(info.ModTime().UnixNano(), 10)))
h, err := hashFileContent(name)
if err != nil {
return err
}
sum.Write([]byte(h))
sum.Write([]byte{'\n'})
}
return hex.EncodeToString(sum.Sum(nil)), nil
return nil
}

func readLoaderArtifact(path string, fset *token.FileSet, imports map[string]*types.Package, pkgPath string) (*types.Package, error) {
Expand Down
43 changes: 29 additions & 14 deletions internal/loader/discovery_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ type discoveryLocalPackage struct {
}

type discoveryFileMeta struct {
Path string
Size int64
ModTime int64
IsDir bool
Path string
Size int64
ModTime int64 // deprecated: kept for gob compat, not used for matching
ContentHash string // sha256 of file content
IsDir bool
}

type discoveryDirMeta struct {
Expand All @@ -44,7 +45,7 @@ type discoveryFileFingerprint struct {
Hash string
}

const discoveryCacheVersion = 3
const discoveryCacheVersion = 4

func readDiscoveryCache(req goListRequest) (map[string]*packageMeta, bool) {
entry, err := loadDiscoveryCacheEntry(req)
Expand Down Expand Up @@ -121,10 +122,16 @@ func validateDiscoveryCacheEntry(entry *discoveryCacheEntry) bool {
return true
}

const discoveryCacheDirEnv = "WIRE_DISCOVERY_CACHE_DIR"

func discoveryCachePath(req goListRequest) (string, error) {
base, err := os.UserCacheDir()
if err != nil {
return "", err
dir := os.Getenv(discoveryCacheDirEnv)
if dir == "" {
base, err := os.UserCacheDir()
if err != nil {
return "", err
}
dir = filepath.Join(base, "wire", "discovery-cache")
}
sumReq := struct {
Version int
Expand All @@ -147,7 +154,7 @@ func discoveryCachePath(req goListRequest) (string, error) {
if err != nil {
return "", err
}
return filepath.Join(base, "wire", "discovery-cache", key+".gob"), nil
return filepath.Join(dir, key+".gob"), nil
}

func loadDiscoveryCacheEntry(req goListRequest) (*discoveryCacheEntry, error) {
Expand Down Expand Up @@ -188,11 +195,19 @@ func statDiscoveryFile(path string) (discoveryFileMeta, bool) {
if err != nil {
return discoveryFileMeta{}, false
}
h := ""
if !info.IsDir() {
var err error
h, err = hashFileContent(path)
if err != nil {
return discoveryFileMeta{}, false
}
}
return discoveryFileMeta{
Path: canonicalLoaderPath(path),
Size: info.Size(),
ModTime: info.ModTime().UnixNano(),
IsDir: info.IsDir(),
Path: canonicalLoaderPath(path),
Size: info.Size(),
ContentHash: h,
IsDir: info.IsDir(),
}, true
}

Expand All @@ -201,7 +216,7 @@ func matchesDiscoveryFile(fm discoveryFileMeta) bool {
if !ok {
return false
}
return cur.Size == fm.Size && cur.ModTime == fm.ModTime && cur.IsDir == fm.IsDir
return cur.ContentHash == fm.ContentHash && cur.IsDir == fm.IsDir
}

func statDiscoveryDir(path string) (discoveryDirMeta, bool) {
Expand Down