aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/modload/modfile.go
diff options
context:
space:
mode:
authorBryan C. Mills <bcmills@google.com>2020-03-06 17:18:16 -0500
committerBryan C. Mills <bcmills@google.com>2020-03-09 19:17:27 +0000
commit2818a11b1824ca52803a3a335354970fbccfcf2e (patch)
treeb75a94adfd714040e5e0ab3e109bb21f58a9706d /src/cmd/go/internal/modload/modfile.go
parentb559a173f9f187e1185f8de00a9cc1f5b05aceef (diff)
downloadgo-2818a11b1824ca52803a3a335354970fbccfcf2e.tar.gz
go-2818a11b1824ca52803a3a335354970fbccfcf2e.zip
cmd/go/internal/modload: factor smaller files out of load.go and init.go
No semantic changes intended: just structural cleanup. Updates #36460 Change-Id: I405bc2572d3ff00f595dae645e673a11e01621ca Reviewed-on: https://go-review.googlesource.com/c/go/+/222340 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
Diffstat (limited to 'src/cmd/go/internal/modload/modfile.go')
-rw-r--r--src/cmd/go/internal/modload/modfile.go164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go
new file mode 100644
index 0000000000..9f4ec5a49f
--- /dev/null
+++ b/src/cmd/go/internal/modload/modfile.go
@@ -0,0 +1,164 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+
+ "golang.org/x/mod/modfile"
+ "golang.org/x/mod/module"
+)
+
+var modFile *modfile.File
+
+// A modFileIndex is an index of data corresponding to a modFile
+// at a specific point in time.
+type modFileIndex struct {
+ data []byte
+ dataNeedsFix bool // true if fixVersion applied a change while parsing data
+ module module.Version
+ goVersion string
+ require map[module.Version]requireMeta
+ replace map[module.Version]module.Version
+ exclude map[module.Version]bool
+}
+
+// index is the index of the go.mod file as of when it was last read or written.
+var index *modFileIndex
+
+type requireMeta struct {
+ indirect bool
+}
+
+// Allowed reports whether module m is allowed (not excluded) by the main module's go.mod.
+func Allowed(m module.Version) bool {
+ return index == nil || !index.exclude[m]
+}
+
+// Replacement returns the replacement for mod, if any, from go.mod.
+// If there is no replacement for mod, Replacement returns
+// a module.Version with Path == "".
+func Replacement(mod module.Version) module.Version {
+ if index != nil {
+ if r, ok := index.replace[mod]; ok {
+ return r
+ }
+ if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
+ return r
+ }
+ }
+ return module.Version{}
+}
+
+// indexModFile rebuilds the index of modFile.
+// If modFile has been changed since it was first read,
+// modFile.Cleanup must be called before indexModFile.
+func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileIndex {
+ i := new(modFileIndex)
+ i.data = data
+ i.dataNeedsFix = needsFix
+
+ i.module = module.Version{}
+ if modFile.Module != nil {
+ i.module = modFile.Module.Mod
+ }
+
+ i.goVersion = ""
+ if modFile.Go != nil {
+ i.goVersion = modFile.Go.Version
+ }
+
+ i.require = make(map[module.Version]requireMeta, len(modFile.Require))
+ for _, r := range modFile.Require {
+ i.require[r.Mod] = requireMeta{indirect: r.Indirect}
+ }
+
+ i.replace = make(map[module.Version]module.Version, len(modFile.Replace))
+ for _, r := range modFile.Replace {
+ if prev, dup := i.replace[r.Old]; dup && prev != r.New {
+ base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v", r.Old, prev, r.New)
+ }
+ i.replace[r.Old] = r.New
+ }
+
+ i.exclude = make(map[module.Version]bool, len(modFile.Exclude))
+ for _, x := range modFile.Exclude {
+ i.exclude[x.Mod] = true
+ }
+
+ return i
+}
+
+// modFileIsDirty reports whether the go.mod file differs meaningfully
+// from what was indexed.
+// If modFile has been changed (even cosmetically) since it was first read,
+// modFile.Cleanup must be called before modFileIsDirty.
+func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {
+ if i == nil {
+ return modFile != nil
+ }
+
+ if i.dataNeedsFix {
+ return true
+ }
+
+ if modFile.Module == nil {
+ if i.module != (module.Version{}) {
+ return true
+ }
+ } else if modFile.Module.Mod != i.module {
+ return true
+ }
+
+ if modFile.Go == nil {
+ if i.goVersion != "" {
+ return true
+ }
+ } else if modFile.Go.Version != i.goVersion {
+ if i.goVersion == "" && cfg.BuildMod == "readonly" {
+ // go.mod files did not always require a 'go' version, so do not error out
+ // if one is missing — we may be inside an older module in the module
+ // cache, and should bias toward providing useful behavior.
+ } else {
+ return true
+ }
+ }
+
+ if len(modFile.Require) != len(i.require) ||
+ len(modFile.Replace) != len(i.replace) ||
+ len(modFile.Exclude) != len(i.exclude) {
+ return true
+ }
+
+ for _, r := range modFile.Require {
+ if meta, ok := i.require[r.Mod]; !ok {
+ return true
+ } else if r.Indirect != meta.indirect {
+ if cfg.BuildMod == "readonly" {
+ // The module's requirements are consistent; only the "// indirect"
+ // comments that are wrong. But those are only guaranteed to be accurate
+ // after a "go mod tidy" — it's a good idea to run those before
+ // committing a change, but it's certainly not mandatory.
+ } else {
+ return true
+ }
+ }
+ }
+
+ for _, r := range modFile.Replace {
+ if r.New != i.replace[r.Old] {
+ return true
+ }
+ }
+
+ for _, x := range modFile.Exclude {
+ if !i.exclude[x.Mod] {
+ return true
+ }
+ }
+
+ return false
+}