"io"
"io/fs"
"log"
+ "math/rand"
"os"
"os/exec"
"path/filepath"
}
os.Setenv("CMDGO_TEST_RUN_MAIN", "true")
+ if strings.HasPrefix(runtime.Version(), "devel ") && godebug.Get("goindexsalt") == "" {
+ // We're going to execute a lot of cmd/go tests, so set a consistent salt
+ // via GODEBUG so that the modindex package can avoid walking an entire
+ // GOROOT module whenever it tries to use an index for that module.
+ indexSalt := rand.Int63()
+ v := os.Getenv("GODEBUG")
+ if v == "" {
+ os.Setenv("GODEBUG", fmt.Sprintf("goindexsalt=%d", indexSalt))
+ } else {
+ os.Setenv("GODEBUG", fmt.Sprintf("%s,goindexsalt=%d", v, indexSalt))
+ }
+ }
+
// $GO_GCFLAGS a compiler debug flag known to cmd/dist, make.bash, etc.
// It is not a standard go command flag; use os.Getenv, not cfg.Getenv.
if os.Getenv("GO_GCFLAGS") != "" {
"go/build"
"go/build/constraint"
"go/token"
+ "internal/godebug"
"internal/goroot"
"internal/unsafeheader"
"io/fs"
"math"
- "os"
"path"
"path/filepath"
"runtime"
// It will be removed before the release.
// TODO(matloob): Remove enabled once we have more confidence on the
// module index.
-var enabled = func() bool {
- debug := strings.Split(os.Getenv("GODEBUG"), ",")
- for _, f := range debug {
- if f == "goindex=0" {
- return false
- }
- }
- return true
-}()
+var enabled bool = godebug.Get("goindex") != "0"
// ModuleIndex represents and encoded module index file. It is used to
// do the equivalent of build.Import of packages in the module and answer other
var fcache par.Cache
+var salt = godebug.Get("goindexsalt")
+
func moduleHash(modroot string, ismodcache bool) (cache.ActionID, error) {
// We expect modules stored within the module cache to be checksummed and
- // immutable, and we expect released Go modules to change only infrequently
- // (when the Go version changes).
- if !ismodcache || !str.HasFilePathPrefix(modroot, cfg.GOROOT) {
+ // immutable, and we expect released modules within GOROOT to change only
+ // infrequently (when the Go version changes).
+ if !ismodcache && !str.HasFilePathPrefix(modroot, cfg.GOROOT) {
+ // The contents of this module may change over time. We don't want to pay
+ // the cost to detect changes and re-index whenever they occur, so just
+ // don't index it at all.
return cache.ActionID{}, ErrNotIndexed
}
h := cache.NewHash("moduleIndex")
- fmt.Fprintf(h, "module index %s %s %v\n", runtime.Version(), indexVersion, modroot)
+ fmt.Fprintf(h, "module index %s %s %s %v\n", runtime.Version(), salt, indexVersion, modroot)
- if strings.HasPrefix(runtime.Version(), "devel ") {
+ if str.HasFilePathPrefix(modroot, cfg.GOROOT) && strings.HasPrefix(runtime.Version(), "devel ") && salt == "" {
// This copy of the standard library is a development version, not a
- // release. It could be based on a Git commit (like "devel go1.19-2a78e8afc0
- // Wed Jun 15 00:06:24 2022 +0000") with or without changes on top of that
- // commit, or it could be completly artificial due to lacking a `git` binary
- // (like "devel gomote.XXXXX", as synthesized by "gomote push" as of
- // 2022-06-15). Compute an inexpensive hash of its files using mtimes so
- // that during development we can continue to exercise the logic for cached
- // GOROOT indexes.
+ // release. It could be based on a Git commit (like
+ // "devel go1.19-2a78e8afc0 Wed Jun 15 00:06:24 2022 +0000") with or
+ // without changes on top of that commit, or it could be completly
+ // artificial due to lacking a `git` binary (like "devel gomote.XXXXX", as
+ // synthesized by "gomote push" as of 2022-06-15).
+ //
+ // If the user provided a unique salt via GODEBUG, we can trust that it is
+ // unique and just go with it. Otherwise, we compute an inexpensive hash of
+ // its files using mtimes so that during development we can continue to
+ // exercise the logic for cached GOROOT indexes.
//
// mtimes may be granular, imprecise, and loosely updated (see
// https://apenwarr.ca/log/20181113), but we don't expect Go contributors to