aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/modload/buildlist.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/go/internal/modload/buildlist.go')
-rw-r--r--src/cmd/go/internal/modload/buildlist.go122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
new file mode 100644
index 0000000000..581a1b944a
--- /dev/null
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -0,0 +1,122 @@
+// Copyright 2018 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"
+ "cmd/go/internal/imports"
+ "cmd/go/internal/mvs"
+ "context"
+ "fmt"
+ "os"
+
+ "golang.org/x/mod/module"
+)
+
+// buildList is the list of modules to use for building packages.
+// It is initialized by calling ImportPaths, ImportFromFiles,
+// LoadALL, or LoadBuildList, each of which uses loaded.load.
+//
+// Ideally, exactly ONE of those functions would be called,
+// and exactly once. Most of the time, that's true.
+// During "go get" it may not be. TODO(rsc): Figure out if
+// that restriction can be established, or else document why not.
+//
+var buildList []module.Version
+
+// LoadAllModules loads and returns the list of modules matching the "all"
+// module pattern, starting with the Target module and in a deterministic
+// (stable) order, without loading any packages.
+//
+// Modules are loaded automatically (and lazily) in ImportPaths:
+// LoadAllModules need only be called if ImportPaths is not,
+// typically in commands that care about modules but no particular package.
+//
+// The caller must not modify the returned list.
+func LoadAllModules(ctx context.Context) []module.Version {
+ InitMod(ctx)
+ ReloadBuildList()
+ WriteGoMod()
+ return buildList
+}
+
+// LoadedModules returns the list of module requirements loaded or set by a
+// previous call (typically LoadAllModules or ImportPaths), starting with the
+// Target module and in a deterministic (stable) order.
+//
+// The caller must not modify the returned list.
+func LoadedModules() []module.Version {
+ return buildList
+}
+
+// SetBuildList sets the module build list.
+// The caller is responsible for ensuring that the list is valid.
+// SetBuildList does not retain a reference to the original list.
+func SetBuildList(list []module.Version) {
+ buildList = append([]module.Version{}, list...)
+}
+
+// ReloadBuildList resets the state of loaded packages, then loads and returns
+// the build list set in SetBuildList.
+func ReloadBuildList() []module.Version {
+ loaded = loadFromRoots(loaderParams{
+ tags: imports.Tags(),
+ listRoots: func() []string { return nil },
+ allClosesOverTests: index.allPatternClosesOverTests(), // but doesn't matter because the root list is empty.
+ })
+ return buildList
+}
+
+// TidyBuildList trims the build list to the minimal requirements needed to
+// retain the same versions of all packages from the preceding Load* or
+// ImportPaths* call.
+func TidyBuildList() {
+ used := map[module.Version]bool{Target: true}
+ for _, pkg := range loaded.pkgs {
+ used[pkg.mod] = true
+ }
+
+ keep := []module.Version{Target}
+ var direct []string
+ for _, m := range buildList[1:] {
+ if used[m] {
+ keep = append(keep, m)
+ if loaded.direct[m.Path] {
+ direct = append(direct, m.Path)
+ }
+ } else if cfg.BuildV {
+ if _, ok := index.require[m]; ok {
+ fmt.Fprintf(os.Stderr, "unused %s\n", m.Path)
+ }
+ }
+ }
+
+ min, err := mvs.Req(Target, direct, &mvsReqs{buildList: keep})
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ buildList = append([]module.Version{Target}, min...)
+}
+
+// checkMultiplePaths verifies that a given module path is used as itself
+// or as a replacement for another module, but not both at the same time.
+//
+// (See https://golang.org/issue/26607 and https://golang.org/issue/34650.)
+func checkMultiplePaths() {
+ firstPath := make(map[module.Version]string, len(buildList))
+ for _, mod := range buildList {
+ src := mod
+ if rep := Replacement(mod); rep.Path != "" {
+ src = rep
+ }
+ if prev, ok := firstPath[src]; !ok {
+ firstPath[src] = mod.Path
+ } else if prev != mod.Path {
+ base.Errorf("go: %s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path)
+ }
+ }
+ base.ExitIfErrors()
+}