From 083250894cb96690f15467ed5651b00ee3e252ce Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 16 Apr 2025 00:39:42 +0200 Subject: [PATCH 1/2] fix: use go.mod as cache salt --- pkg/commands/run.go | 43 ++++++++++++++++++++++++++++++++++++++-- pkg/config/config.go | 12 ++++++++--- pkg/config/loader.go | 2 +- pkg/logutils/logutils.go | 1 + 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/pkg/commands/run.go b/pkg/commands/run.go index a3e9df6de3fc..83f1423b3d64 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -21,10 +21,12 @@ import ( "github.com/fatih/color" "github.com/gofrs/flock" + "github.com/ldez/grignotin/goenv" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" "go.uber.org/automaxprocs/maxprocs" + "golang.org/x/mod/sumdb/dirhash" "gopkg.in/yaml.v3" "github.com/golangci/golangci-lint/v2/internal/cache" @@ -216,7 +218,7 @@ func (c *runCommand) preRunE(_ *cobra.Command, args []string) error { c.contextBuilder = lint.NewContextBuilder(c.cfg, pkgLoader, pkgCache, guard) - if err = initHashSalt(c.buildInfo.Version, c.cfg); err != nil { + if err = initHashSalt(c.log.Child(logutils.DebugKeyGoModSalt), c.buildInfo.Version, c.cfg); err != nil { return fmt.Errorf("failed to init hash salt: %w", err) } @@ -618,7 +620,7 @@ func formatMemory(memBytes uint64) string { // Related to cache. -func initHashSalt(version string, cfg *config.Config) error { +func initHashSalt(logger logutils.Log, version string, cfg *config.Config) error { binSalt, err := computeBinarySalt(version) if err != nil { return fmt.Errorf("failed to calculate binary salt: %w", err) @@ -629,9 +631,18 @@ func initHashSalt(version string, cfg *config.Config) error { return fmt.Errorf("failed to calculate config salt: %w", err) } + goModSalt, err := computeGoModSalt() + if err != nil { + // NOTE: missing go.mod must be ignored. + logger.Warnf("failed to calculate go.mod salt: %v", err) + } + b := bytes.NewBuffer(binSalt) b.Write(configSalt) + b.WriteString(goModSalt) + cache.SetSalt(b) + return nil } @@ -648,15 +659,19 @@ func computeBinarySalt(version string) ([]byte, error) { if err != nil { return nil, err } + f, err := os.Open(p) if err != nil { return nil, err } + defer f.Close() + h := sha256.New() if _, err := io.Copy(h, f); err != nil { return nil, err } + return h.Sum(nil), nil } @@ -678,5 +693,29 @@ func computeConfigSalt(cfg *config.Config) ([]byte, error) { if _, err := h.Write(configData.Bytes()); err != nil { return nil, err } + return h.Sum(nil), nil } + +func computeGoModSalt() (string, error) { + values, err := goenv.Get(context.Background(), goenv.GOMOD) + if err != nil { + return "", fmt.Errorf("failed to get goenv: %w", err) + } + + goModPath := filepath.Clean(values[goenv.GOMOD]) + + data, err := os.ReadFile(goModPath) + if err != nil { + return "", fmt.Errorf("failed to read go.mod: %w", err) + } + + sum, err := dirhash.Hash1([]string{goModPath}, func(string) (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader(data)), nil + }) + if err != nil { + return "", fmt.Errorf("failed to compute go.sum: %w", err) + } + + return sum, nil +} diff --git a/pkg/config/config.go b/pkg/config/config.go index a6236a23f3af..6d7586621d8b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -13,6 +13,8 @@ import ( "github.com/ldez/grignotin/goenv" "github.com/ldez/grignotin/gomod" "golang.org/x/mod/modfile" + + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) // defaultGoVersion the value should be "oldstable" - 1. @@ -102,8 +104,8 @@ func IsGoGreaterThanOrEqual(current, limit string) bool { return v1.GreaterThanOrEqual(l) } -func detectGoVersion(ctx context.Context) string { - return cmp.Or(detectGoVersionFromGoMod(ctx), defaultGoVersion) +func detectGoVersion(ctx context.Context, log logutils.Log) string { + return cmp.Or(detectGoVersionFromGoMod(ctx, log), defaultGoVersion) } // detectGoVersionFromGoMod tries to get Go version from go.mod. @@ -111,7 +113,7 @@ func detectGoVersion(ctx context.Context) string { // else it returns `go` version if present, // else it returns `GOVERSION` version if present, // else it returns empty. -func detectGoVersionFromGoMod(ctx context.Context) string { +func detectGoVersionFromGoMod(ctx context.Context, log logutils.Log) string { values, err := goenv.Get(ctx, goenv.GOMOD, goenv.GOVERSION) if err != nil { values = map[string]string{ @@ -128,6 +130,10 @@ func detectGoVersionFromGoMod(ctx context.Context) string { return parseGoVersion(values[goenv.GOVERSION]) } + if file.Module != nil { + log.Infof("Module name %q", file.Module.Mod.Path) + } + // The toolchain exists only if 'toolchain' version > 'go' version. // If 'toolchain' version <= 'go' version, `go mod tidy` will remove 'toolchain' version from go.mod. if file.Toolchain != nil && file.Toolchain.Name != "" { diff --git a/pkg/config/loader.go b/pkg/config/loader.go index 19a17e7d71db..3ff9306486ab 100644 --- a/pkg/config/loader.go +++ b/pkg/config/loader.go @@ -161,7 +161,7 @@ func (l *Loader) checkConfigurationVersion() error { func (l *Loader) handleGoVersion() { if l.cfg.Run.Go == "" { - l.cfg.Run.Go = detectGoVersion(context.Background()) + l.cfg.Run.Go = detectGoVersion(context.Background(), l.log) } l.cfg.Linters.Settings.Govet.Go = l.cfg.Run.Go diff --git a/pkg/logutils/logutils.go b/pkg/logutils/logutils.go index 2fbb4a7b2493..0ee48a3664bd 100644 --- a/pkg/logutils/logutils.go +++ b/pkg/logutils/logutils.go @@ -17,6 +17,7 @@ const envDebug = "GL_DEBUG" const ( DebugKeyBinSalt = "bin_salt" + DebugKeyGoModSalt = "gomod_salt" DebugKeyConfigReader = "config_reader" DebugKeyEmpty = "" DebugKeyEnabledLinters = "enabled_linters" From d3ed097da63605e162219c117fbc64d977f06684 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 16 Apr 2025 16:14:17 +0200 Subject: [PATCH 2/2] review --- pkg/commands/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/run.go b/pkg/commands/run.go index 83f1423b3d64..53902eafac24 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -634,7 +634,7 @@ func initHashSalt(logger logutils.Log, version string, cfg *config.Config) error goModSalt, err := computeGoModSalt() if err != nil { // NOTE: missing go.mod must be ignored. - logger.Warnf("failed to calculate go.mod salt: %v", err) + logger.Warnf("Failed to calculate go.mod salt: %v", err) } b := bytes.NewBuffer(binSalt)