// 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() }