mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.cmdgo] cmd/go: replace Target with MainModules, allowing for multiple targets
This change replaces the Target variable that represents the main module and the pathPrefix and inGorootSrc which provide other information about the main module with a single MainModules value that represents multiple main modules and holds their path prefixes, module roots, and whether they are in GOROOT/src. In cases where the code checks Target or its previously associated variables, the code now checks or iterates over MainModules. In some cases, the code still assumes a single main module by calling MainModules.MustGetSingleMainModule. Some of those cases are correct: for instance, there is always only one main module for mod=vendor. Other cases are accompanied with TODOs and will have to be fixed in future CLs to properly support multiple main modules. This CL (and other cls on top of it) are planned to be checked into a branch to allow for those evaluating the workspaces proposal to try it hands on. For #45713 Change-Id: I3b699e1d5cad8c76d62dc567b8460de8c73a87ea Reviewed-on: https://go-review.googlesource.com/c/go/+/334932 Trust: Michael Matloob <matloob@golang.org> Run-TryBot: Michael Matloob <matloob@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
parent
ab361499ef
commit
a627fcd3c4
21 changed files with 565 additions and 316 deletions
|
|
@ -225,7 +225,8 @@ func downloadPaths(patterns []string) []string {
|
||||||
base.ExitIfErrors()
|
base.ExitIfErrors()
|
||||||
|
|
||||||
var pkgs []string
|
var pkgs []string
|
||||||
for _, m := range search.ImportPathsQuiet(patterns) {
|
noModRoots := []string{}
|
||||||
|
for _, m := range search.ImportPathsQuiet(patterns, noModRoots) {
|
||||||
if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
|
if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
|
||||||
pkgs = append(pkgs, m.Pattern())
|
pkgs = append(pkgs, m.Pattern())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -315,7 +316,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||||
if wildcardOkay && strings.Contains(arg, "...") {
|
if wildcardOkay && strings.Contains(arg, "...") {
|
||||||
match := search.NewMatch(arg)
|
match := search.NewMatch(arg)
|
||||||
if match.IsLocal() {
|
if match.IsLocal() {
|
||||||
match.MatchDirs()
|
noModRoots := []string{} // We're in gopath mode, so there are no modroots.
|
||||||
|
match.MatchDirs(noModRoots)
|
||||||
args = match.Dirs
|
args = match.Dirs
|
||||||
} else {
|
} else {
|
||||||
match.MatchPackages()
|
match.MatchPackages()
|
||||||
|
|
|
||||||
|
|
@ -1450,9 +1450,9 @@ func disallowInternal(ctx context.Context, srcDir string, importer *Package, imp
|
||||||
// The importer is a list of command-line files.
|
// The importer is a list of command-line files.
|
||||||
// Pretend that the import path is the import path of the
|
// Pretend that the import path is the import path of the
|
||||||
// directory containing them.
|
// directory containing them.
|
||||||
// If the directory is outside the main module, this will resolve to ".",
|
// If the directory is outside the main modules, this will resolve to ".",
|
||||||
// which is not a prefix of any valid module.
|
// which is not a prefix of any valid module.
|
||||||
importerPath = modload.DirImportPath(ctx, importer.Dir)
|
importerPath, _ = modload.MainModules.DirImportPath(ctx, importer.Dir)
|
||||||
}
|
}
|
||||||
parentOfInternal := p.ImportPath[:i]
|
parentOfInternal := p.ImportPath[:i]
|
||||||
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
||||||
|
|
@ -2447,7 +2447,8 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
|
||||||
}
|
}
|
||||||
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
|
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
|
||||||
} else {
|
} else {
|
||||||
matches = search.ImportPaths(patterns)
|
noModRoots := []string{}
|
||||||
|
matches = search.ImportPaths(patterns, noModRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,18 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
args = []string{"all"}
|
args = []string{"all"}
|
||||||
}
|
}
|
||||||
if modload.HasModRoot() {
|
if modload.HasModRoot() {
|
||||||
modload.LoadModFile(ctx) // to fill Target
|
modload.LoadModFile(ctx) // to fill MainModules
|
||||||
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
|
||||||
targetAtPatch := modload.Target.Path + "@patch"
|
if len(modload.MainModules.Versions()) != 1 {
|
||||||
|
panic(modload.TODOWorkspaces("TODO: multiple main modules not supported in Download"))
|
||||||
|
}
|
||||||
|
mainModule := modload.MainModules.Versions()[0]
|
||||||
|
|
||||||
|
targetAtUpgrade := mainModule.Path + "@upgrade"
|
||||||
|
targetAtPatch := mainModule.Path + "@patch"
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
switch arg {
|
switch arg {
|
||||||
case modload.Target.Path, targetAtUpgrade, targetAtPatch:
|
case mainModule.Path, targetAtUpgrade, targetAtPatch:
|
||||||
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
|
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
modpkgs := make(map[module.Version][]string)
|
modpkgs := make(map[module.Version][]string)
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
m := modload.PackageModule(pkg)
|
m := modload.PackageModule(pkg)
|
||||||
if m.Path == "" || m == modload.Target {
|
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
modpkgs[m] = append(modpkgs[m], pkg)
|
modpkgs[m] = append(modpkgs[m], pkg)
|
||||||
|
|
|
||||||
|
|
@ -389,11 +389,13 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
|
||||||
haveExternalExe := false
|
haveExternalExe := false
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
if pkg.Name == "main" && pkg.Module != nil && pkg.Module.Path != modload.Target.Path {
|
if pkg.Name == "main" && pkg.Module != nil {
|
||||||
|
if !modload.MainModules.Contains(pkg.Module.Path) {
|
||||||
haveExternalExe = true
|
haveExternalExe = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if haveExternalExe {
|
if haveExternalExe {
|
||||||
fmt.Fprint(os.Stderr, "go get: installing executables with 'go get' in module mode is deprecated.")
|
fmt.Fprint(os.Stderr, "go get: installing executables with 'go get' in module mode is deprecated.")
|
||||||
var altMsg string
|
var altMsg string
|
||||||
|
|
@ -675,7 +677,9 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
||||||
|
|
||||||
if !q.isWildcard() {
|
if !q.isWildcard() {
|
||||||
q.pathOnce(q.pattern, func() pathSet {
|
q.pathOnce(q.pattern, func() pathSet {
|
||||||
if modload.HasModRoot() && q.pattern == modload.Target.Path {
|
hasModRoot := modload.HasModRoot()
|
||||||
|
if hasModRoot && modload.MainModules.Contains(q.pattern) {
|
||||||
|
v := module.Version{Path: q.pattern}
|
||||||
// The user has explicitly requested to downgrade their own module to
|
// The user has explicitly requested to downgrade their own module to
|
||||||
// version "none". This is not an entirely unreasonable request: it
|
// version "none". This is not an entirely unreasonable request: it
|
||||||
// could plausibly mean “downgrade away everything that depends on any
|
// could plausibly mean “downgrade away everything that depends on any
|
||||||
|
|
@ -686,7 +690,7 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
||||||
// However, neither of those behaviors would be consistent with the
|
// However, neither of those behaviors would be consistent with the
|
||||||
// plain meaning of the query. To try to reduce confusion, reject the
|
// plain meaning of the query. To try to reduce confusion, reject the
|
||||||
// query explicitly.
|
// query explicitly.
|
||||||
return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version})
|
return errSet(&modload.QueryMatchesMainModuleError{MainModule: v, Pattern: q.pattern, Query: q.version})
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
|
return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
|
||||||
|
|
@ -698,8 +702,8 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
q.pathOnce(curM.Path, func() pathSet {
|
q.pathOnce(curM.Path, func() pathSet {
|
||||||
if modload.HasModRoot() && curM == modload.Target {
|
if modload.HasModRoot() && curM.Version == "" && modload.MainModules.Contains(curM.Path) {
|
||||||
return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version})
|
return errSet(&modload.QueryMatchesMainModuleError{MainModule: curM, Pattern: q.pattern, Query: q.version})
|
||||||
}
|
}
|
||||||
return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
|
return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
|
||||||
})
|
})
|
||||||
|
|
@ -718,12 +722,12 @@ func (r *resolver) performLocalQueries(ctx context.Context) {
|
||||||
|
|
||||||
// Absolute paths like C:\foo and relative paths like ../foo... are
|
// Absolute paths like C:\foo and relative paths like ../foo... are
|
||||||
// restricted to matching packages in the main module.
|
// restricted to matching packages in the main module.
|
||||||
pkgPattern := modload.DirImportPath(ctx, q.pattern)
|
pkgPattern, mainModule := modload.MainModules.DirImportPath(ctx, q.pattern)
|
||||||
if pkgPattern == "." {
|
if pkgPattern == "." {
|
||||||
return errSet(fmt.Errorf("%s%s is not within module rooted at %s", q.pattern, absDetail, modload.ModRoot()))
|
return errSet(fmt.Errorf("%s%s is not within module rooted at %s", q.pattern, absDetail, modload.ModRoot()))
|
||||||
}
|
}
|
||||||
|
|
||||||
match := modload.MatchInModule(ctx, pkgPattern, modload.Target, imports.AnyTags())
|
match := modload.MatchInModule(ctx, pkgPattern, mainModule, imports.AnyTags())
|
||||||
if len(match.Errs) > 0 {
|
if len(match.Errs) > 0 {
|
||||||
return pathSet{err: match.Errs[0]}
|
return pathSet{err: match.Errs[0]}
|
||||||
}
|
}
|
||||||
|
|
@ -739,7 +743,7 @@ func (r *resolver) performLocalQueries(ctx context.Context) {
|
||||||
return pathSet{}
|
return pathSet{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathSet{pkgMods: []module.Version{modload.Target}}
|
return pathSet{pkgMods: []module.Version{mainModule}}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -789,9 +793,10 @@ func (r *resolver) queryWildcard(ctx context.Context, q *query) {
|
||||||
return pathSet{}
|
return pathSet{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if curM.Path == modload.Target.Path && !versionOkForMainModule(q.version) {
|
if modload.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) {
|
||||||
if q.matchesPath(curM.Path) {
|
if q.matchesPath(curM.Path) {
|
||||||
return errSet(&modload.QueryMatchesMainModuleError{
|
return errSet(&modload.QueryMatchesMainModuleError{
|
||||||
|
MainModule: curM,
|
||||||
Pattern: q.pattern,
|
Pattern: q.pattern,
|
||||||
Query: q.version,
|
Query: q.version,
|
||||||
})
|
})
|
||||||
|
|
@ -1159,8 +1164,8 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
|
opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
|
||||||
if m.Path == "" || m == modload.Target {
|
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
|
||||||
// Packages in the standard library and main module are already at their
|
// Packages in the standard library and main modules are already at their
|
||||||
// latest (and only) available versions.
|
// latest (and only) available versions.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1370,11 +1375,11 @@ func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Path == modload.Target.Path {
|
if modload.MainModules.Contains(m.Path) {
|
||||||
if m.Version == modload.Target.Version {
|
if m.Version == "" {
|
||||||
return pathSet{}, true, m, true
|
return pathSet{}, true, m, true
|
||||||
}
|
}
|
||||||
// The main module can only be set to its own version.
|
// A main module can only be set to its own version.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1744,8 +1749,9 @@ func (r *resolver) resolve(q *query, m module.Version) {
|
||||||
panic("internal error: resolving a module.Version with an empty path")
|
panic("internal error: resolving a module.Version with an empty path")
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Path == modload.Target.Path && m.Version != modload.Target.Version {
|
if modload.MainModules.Contains(m.Path) && m.Version != "" {
|
||||||
reportError(q, &modload.QueryMatchesMainModuleError{
|
reportError(q, &modload.QueryMatchesMainModuleError{
|
||||||
|
MainModule: module.Version{Path: m.Path},
|
||||||
Pattern: q.pattern,
|
Pattern: q.pattern,
|
||||||
Query: q.version,
|
Query: q.version,
|
||||||
})
|
})
|
||||||
|
|
@ -1775,7 +1781,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
|
||||||
|
|
||||||
resolved := make([]module.Version, 0, len(r.resolvedVersion))
|
resolved := make([]module.Version, 0, len(r.resolvedVersion))
|
||||||
for mPath, rv := range r.resolvedVersion {
|
for mPath, rv := range r.resolvedVersion {
|
||||||
if mPath != modload.Target.Path {
|
if !modload.MainModules.Contains(mPath) {
|
||||||
resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
|
resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,8 +192,8 @@ func (q *query) validate() error {
|
||||||
// TODO(bcmills): "all@none" seems like a totally reasonable way to
|
// TODO(bcmills): "all@none" seems like a totally reasonable way to
|
||||||
// request that we remove all module requirements, leaving only the main
|
// request that we remove all module requirements, leaving only the main
|
||||||
// module and standard library. Perhaps we should implement that someday.
|
// module and standard library. Perhaps we should implement that someday.
|
||||||
return &modload.QueryMatchesMainModuleError{
|
return &modload.QueryUpgradesAllError{
|
||||||
Pattern: q.pattern,
|
MainModules: modload.MainModules.Versions(),
|
||||||
Query: q.version,
|
Query: q.version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,20 +212,21 @@ func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) {
|
||||||
// in rs (which may be nil to indicate that m was not loaded from a requirement
|
// in rs (which may be nil to indicate that m was not loaded from a requirement
|
||||||
// graph).
|
// graph).
|
||||||
func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode ListMode) *modinfo.ModulePublic {
|
func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode ListMode) *modinfo.ModulePublic {
|
||||||
if m == Target {
|
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||||
info := &modinfo.ModulePublic{
|
info := &modinfo.ModulePublic{
|
||||||
Path: m.Path,
|
Path: m.Path,
|
||||||
Version: m.Version,
|
Version: m.Version,
|
||||||
Main: true,
|
Main: true,
|
||||||
}
|
}
|
||||||
if v, ok := rawGoVersion.Load(Target); ok {
|
_ = TODOWorkspaces("handle rawGoVersion here")
|
||||||
|
if v, ok := rawGoVersion.Load(m); ok {
|
||||||
info.GoVersion = v.(string)
|
info.GoVersion = v.(string)
|
||||||
} else {
|
} else {
|
||||||
panic("internal error: GoVersion not set for main module")
|
panic("internal error: GoVersion not set for main module")
|
||||||
}
|
}
|
||||||
if HasModRoot() {
|
if modRoot := MainModules.ModRoot(m); modRoot != "" {
|
||||||
info.Dir = ModRoot()
|
info.Dir = modRoot
|
||||||
info.GoMod = ModFilePath()
|
info.GoMod = modFilePath(modRoot)
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +398,8 @@ func mustFindModule(ld *loader, target, path string) module.Version {
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == "command-line-arguments" {
|
if path == "command-line-arguments" {
|
||||||
return Target
|
_ = TODOWorkspaces("support multiple main modules; search by modroot")
|
||||||
|
return MainModules.mustGetSingleMainModule()
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Fatalf("build %v: cannot find module for path %v", target, path)
|
base.Fatalf("build %v: cannot find module for path %v", target, path)
|
||||||
|
|
@ -406,13 +408,14 @@ func mustFindModule(ld *loader, target, path string) module.Version {
|
||||||
|
|
||||||
// findModule searches for the module that contains the package at path.
|
// findModule searches for the module that contains the package at path.
|
||||||
// If the package was loaded, its containing module and true are returned.
|
// If the package was loaded, its containing module and true are returned.
|
||||||
// Otherwise, module.Version{} and false are returend.
|
// Otherwise, module.Version{} and false are returned.
|
||||||
func findModule(ld *loader, path string) (module.Version, bool) {
|
func findModule(ld *loader, path string) (module.Version, bool) {
|
||||||
if pkg, ok := ld.pkgCache.Get(path).(*loadPkg); ok {
|
if pkg, ok := ld.pkgCache.Get(path).(*loadPkg); ok {
|
||||||
return pkg.mod, pkg.mod != module.Version{}
|
return pkg.mod, pkg.mod != module.Version{}
|
||||||
}
|
}
|
||||||
if path == "command-line-arguments" {
|
if path == "command-line-arguments" {
|
||||||
return Target, true
|
_ = TODOWorkspaces("support multiple main modules; search by modroot")
|
||||||
|
return MainModules.mustGetSingleMainModule(), true
|
||||||
}
|
}
|
||||||
return module.Version{}, false
|
return module.Version{}, false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ type Requirements struct {
|
||||||
depth modDepth
|
depth modDepth
|
||||||
|
|
||||||
// rootModules is the set of module versions explicitly required by the main
|
// rootModules is the set of module versions explicitly required by the main
|
||||||
// module, sorted and capped to length. It may contain duplicates, and may
|
// modules, sorted and capped to length. It may contain duplicates, and may
|
||||||
// contain multiple versions for a given module path.
|
// contain multiple versions for a given module path.
|
||||||
rootModules []module.Version
|
rootModules []module.Version
|
||||||
maxRootVersion map[string]string
|
maxRootVersion map[string]string
|
||||||
|
|
@ -99,8 +99,8 @@ var requirements *Requirements
|
||||||
// *Requirements before any other method.
|
// *Requirements before any other method.
|
||||||
func newRequirements(depth modDepth, rootModules []module.Version, direct map[string]bool) *Requirements {
|
func newRequirements(depth modDepth, rootModules []module.Version, direct map[string]bool) *Requirements {
|
||||||
for i, m := range rootModules {
|
for i, m := range rootModules {
|
||||||
if m == Target {
|
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||||
panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is Target", i))
|
panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is a main module", i))
|
||||||
}
|
}
|
||||||
if m.Path == "" || m.Version == "" {
|
if m.Path == "" || m.Version == "" {
|
||||||
panic(fmt.Sprintf("bad requirement: rootModules[%v] = %v", i, m))
|
panic(fmt.Sprintf("bad requirement: rootModules[%v] = %v", i, m))
|
||||||
|
|
@ -135,9 +135,14 @@ func newRequirements(depth modDepth, rootModules []module.Version, direct map[st
|
||||||
func (rs *Requirements) initVendor(vendorList []module.Version) {
|
func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
rs.graphOnce.Do(func() {
|
rs.graphOnce.Do(func() {
|
||||||
mg := &ModuleGraph{
|
mg := &ModuleGraph{
|
||||||
g: mvs.NewGraph(cmpVersion, []module.Version{Target}),
|
g: mvs.NewGraph(cmpVersion, MainModules.Versions()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if MainModules.Len() != 1 {
|
||||||
|
panic("There should be exactly one main moudle in Vendor mode.")
|
||||||
|
}
|
||||||
|
mainModule := MainModules.Versions()[0]
|
||||||
|
|
||||||
if rs.depth == lazy {
|
if rs.depth == lazy {
|
||||||
// The roots of a lazy module should already include every module in the
|
// The roots of a lazy module should already include every module in the
|
||||||
// vendor list, because the vendored modules are the same as those
|
// vendor list, because the vendored modules are the same as those
|
||||||
|
|
@ -158,7 +163,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
// Now we can treat the rest of the module graph as effectively “pruned
|
// Now we can treat the rest of the module graph as effectively “pruned
|
||||||
// out”, like a more aggressive version of lazy loading: in vendor mode,
|
// out”, like a more aggressive version of lazy loading: in vendor mode,
|
||||||
// the root requirements *are* the complete module graph.
|
// the root requirements *are* the complete module graph.
|
||||||
mg.g.Require(Target, rs.rootModules)
|
mg.g.Require(mainModule, rs.rootModules)
|
||||||
} else {
|
} else {
|
||||||
// The transitive requirements of the main module are not in general available
|
// The transitive requirements of the main module are not in general available
|
||||||
// from the vendor directory, and we don't actually know how we got from
|
// from the vendor directory, and we don't actually know how we got from
|
||||||
|
|
@ -170,7 +175,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
// graph, but still distinguishes between direct and indirect
|
// graph, but still distinguishes between direct and indirect
|
||||||
// dependencies.
|
// dependencies.
|
||||||
vendorMod := module.Version{Path: "vendor/modules.txt", Version: ""}
|
vendorMod := module.Version{Path: "vendor/modules.txt", Version: ""}
|
||||||
mg.g.Require(Target, append(rs.rootModules, vendorMod))
|
mg.g.Require(mainModule, append(rs.rootModules, vendorMod))
|
||||||
mg.g.Require(vendorMod, vendorList)
|
mg.g.Require(vendorMod, vendorList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,8 +187,8 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
// path, or the zero module.Version and ok=false if the module is not a root
|
// path, or the zero module.Version and ok=false if the module is not a root
|
||||||
// dependency.
|
// dependency.
|
||||||
func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
|
func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
|
||||||
if path == Target.Path {
|
if MainModules.Contains(path) {
|
||||||
return Target.Version, true
|
return "", true
|
||||||
}
|
}
|
||||||
if v, ok := rs.maxRootVersion[path]; ok {
|
if v, ok := rs.maxRootVersion[path]; ok {
|
||||||
return v, true
|
return v, true
|
||||||
|
|
@ -261,10 +266,15 @@ func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (
|
||||||
mu sync.Mutex // guards mg.g and hasError during loading
|
mu sync.Mutex // guards mg.g and hasError during loading
|
||||||
hasError bool
|
hasError bool
|
||||||
mg = &ModuleGraph{
|
mg = &ModuleGraph{
|
||||||
g: mvs.NewGraph(cmpVersion, []module.Version{Target}),
|
g: mvs.NewGraph(cmpVersion, MainModules.Versions()),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
mg.g.Require(Target, roots)
|
for _, m := range MainModules.Versions() {
|
||||||
|
// Require all roots from all main modules.
|
||||||
|
_ = TODOWorkspaces("This isn't the correct behavior. " +
|
||||||
|
"Fix this when the requirements struct is updated to reflect the struct of the module graph.")
|
||||||
|
mg.g.Require(m, roots)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
loadQueue = par.NewQueue(runtime.GOMAXPROCS(0))
|
loadQueue = par.NewQueue(runtime.GOMAXPROCS(0))
|
||||||
|
|
@ -391,12 +401,14 @@ func (mg *ModuleGraph) findError() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mg *ModuleGraph) allRootsSelected() bool {
|
func (mg *ModuleGraph) allRootsSelected() bool {
|
||||||
roots, _ := mg.g.RequiredBy(Target)
|
for _, mm := range MainModules.Versions() {
|
||||||
|
roots, _ := mg.g.RequiredBy(mm)
|
||||||
for _, m := range roots {
|
for _, m := range roots {
|
||||||
if mg.Selected(m.Path) != m.Version {
|
if mg.Selected(m.Path) != m.Version {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,10 +545,11 @@ type Conflict struct {
|
||||||
// both retain the same versions of all packages in pkgs and satisfy the
|
// both retain the same versions of all packages in pkgs and satisfy the
|
||||||
// lazy loading invariants (if applicable).
|
// lazy loading invariants (if applicable).
|
||||||
func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) {
|
func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) {
|
||||||
|
mainModule := MainModules.mustGetSingleMainModule()
|
||||||
if rs.depth == eager {
|
if rs.depth == eager {
|
||||||
return tidyEagerRoots(ctx, rs.direct, pkgs)
|
return tidyEagerRoots(ctx, mainModule, rs.direct, pkgs)
|
||||||
}
|
}
|
||||||
return tidyLazyRoots(ctx, rs.direct, pkgs)
|
return tidyLazyRoots(ctx, mainModule, rs.direct, pkgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
|
func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
|
||||||
|
|
@ -561,10 +574,10 @@ func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements,
|
||||||
// To ensure that the loading process eventually converges, the caller should
|
// To ensure that the loading process eventually converges, the caller should
|
||||||
// add any needed roots from the tidy root set (without removing existing untidy
|
// add any needed roots from the tidy root set (without removing existing untidy
|
||||||
// roots) until the set of roots has converged.
|
// roots) until the set of roots has converged.
|
||||||
func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
func tidyLazyRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
||||||
var (
|
var (
|
||||||
roots []module.Version
|
roots []module.Version
|
||||||
pathIncluded = map[string]bool{Target.Path: true}
|
pathIncluded = map[string]bool{mainModule.Path: true}
|
||||||
)
|
)
|
||||||
// We start by adding roots for every package in "all".
|
// We start by adding roots for every package in "all".
|
||||||
//
|
//
|
||||||
|
|
@ -842,7 +855,9 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
|
||||||
roots = make([]module.Version, 0, len(rs.rootModules))
|
roots = make([]module.Version, 0, len(rs.rootModules))
|
||||||
rootsUpgraded = false
|
rootsUpgraded = false
|
||||||
inRootPaths := make(map[string]bool, len(rs.rootModules)+1)
|
inRootPaths := make(map[string]bool, len(rs.rootModules)+1)
|
||||||
inRootPaths[Target.Path] = true
|
for _, mm := range MainModules.Versions() {
|
||||||
|
inRootPaths[mm.Path] = true
|
||||||
|
}
|
||||||
for _, m := range rs.rootModules {
|
for _, m := range rs.rootModules {
|
||||||
if inRootPaths[m.Path] {
|
if inRootPaths[m.Path] {
|
||||||
// This root specifies a redundant path. We already retained the
|
// This root specifies a redundant path. We already retained the
|
||||||
|
|
@ -939,7 +954,7 @@ func spotCheckRoots(ctx context.Context, rs *Requirements, mods map[module.Versi
|
||||||
// tidyEagerRoots returns a minimal set of root requirements that maintains the
|
// tidyEagerRoots returns a minimal set of root requirements that maintains the
|
||||||
// selected version of every module that provided a package in pkgs, and
|
// selected version of every module that provided a package in pkgs, and
|
||||||
// includes the selected version of every such module in direct as a root.
|
// includes the selected version of every such module in direct as a root.
|
||||||
func tidyEagerRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
func tidyEagerRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
||||||
var (
|
var (
|
||||||
keep []module.Version
|
keep []module.Version
|
||||||
keptPath = map[string]bool{}
|
keptPath = map[string]bool{}
|
||||||
|
|
@ -962,7 +977,7 @@ func tidyEagerRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
min, err := mvs.Req(Target, rootPaths, &mvsReqs{roots: keep})
|
min, err := mvs.Req(mainModule, rootPaths, &mvsReqs{roots: keep})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1051,7 +1066,7 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
|
||||||
// This is only for convenience and clarity for end users: in an eager module,
|
// This is only for convenience and clarity for end users: in an eager module,
|
||||||
// the choice of explicit vs. implicit dependency has no impact on MVS
|
// the choice of explicit vs. implicit dependency has no impact on MVS
|
||||||
// selection (for itself or any other module).
|
// selection (for itself or any other module).
|
||||||
keep := append(mg.BuildList()[1:], add...)
|
keep := append(mg.BuildList()[MainModules.Len():], add...)
|
||||||
for _, m := range keep {
|
for _, m := range keep {
|
||||||
if direct[m.Path] && !inRootPaths[m.Path] {
|
if direct[m.Path] && !inRootPaths[m.Path] {
|
||||||
rootPaths = append(rootPaths, m.Path)
|
rootPaths = append(rootPaths, m.Path)
|
||||||
|
|
@ -1059,16 +1074,22 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
min, err := mvs.Req(Target, rootPaths, &mvsReqs{roots: keep})
|
// TODO(matloob): Make roots into a map.
|
||||||
|
var roots []module.Version
|
||||||
|
for _, mainModule := range MainModules.Versions() {
|
||||||
|
min, err := mvs.Req(mainModule, rootPaths, &mvsReqs{roots: keep})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rs, err
|
return rs, err
|
||||||
}
|
}
|
||||||
if rs.depth == eager && reflect.DeepEqual(min, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
|
roots = append(roots, min...)
|
||||||
|
}
|
||||||
|
if rs.depth == eager && reflect.DeepEqual(roots, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
|
||||||
// The root set is unchanged and rs was already eager, so keep rs to
|
// The root set is unchanged and rs was already eager, so keep rs to
|
||||||
// preserve its cached ModuleGraph (if any).
|
// preserve its cached ModuleGraph (if any).
|
||||||
return rs, nil
|
return rs, nil
|
||||||
}
|
}
|
||||||
return newRequirements(eager, min, direct), nil
|
|
||||||
|
return newRequirements(eager, roots, direct), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertDepth returns a version of rs with the given depth.
|
// convertDepth returns a version of rs with the given depth.
|
||||||
|
|
@ -1098,5 +1119,5 @@ func convertDepth(ctx context.Context, rs *Requirements, depth modDepth) (*Requi
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rs, err
|
return rs, err
|
||||||
}
|
}
|
||||||
return newRequirements(lazy, mg.BuildList()[1:], rs.direct), nil
|
return newRequirements(lazy, mg.BuildList()[MainModules.Len():], rs.direct), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
|
||||||
// We promote the modules in mustSelect to be explicit requirements.
|
// We promote the modules in mustSelect to be explicit requirements.
|
||||||
var rootPaths []string
|
var rootPaths []string
|
||||||
for _, m := range mustSelect {
|
for _, m := range mustSelect {
|
||||||
if m.Version != "none" && m.Path != Target.Path {
|
if !MainModules.Contains(m.Path) && m.Version != "none" {
|
||||||
rootPaths = append(rootPaths, m.Path)
|
rootPaths = append(rootPaths, m.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +97,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
roots, err = mvs.Req(Target, rootPaths, &mvsReqs{roots: mods})
|
roots, err = mvs.Req(MainModules.mustGetSingleMainModule(), rootPaths, &mvsReqs{roots: mods})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
@ -218,8 +218,8 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||||
eagerUpgrades = tryUpgrade
|
eagerUpgrades = tryUpgrade
|
||||||
} else {
|
} else {
|
||||||
for _, m := range tryUpgrade {
|
for _, m := range tryUpgrade {
|
||||||
if m.Path == Target.Path {
|
if MainModules.Contains(m.Path) {
|
||||||
// Target is already considered to be higher than any possible m, so we
|
// The main module versions are already considered to be higher than any possible m, so we
|
||||||
// won't be upgrading to it anyway and there is no point scanning its
|
// won't be upgrading to it anyway and there is no point scanning its
|
||||||
// dependencies.
|
// dependencies.
|
||||||
continue
|
continue
|
||||||
|
|
@ -318,7 +318,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
|
||||||
|
|
||||||
mods = make([]module.Version, 0, len(limiter.selected))
|
mods = make([]module.Version, 0, len(limiter.selected))
|
||||||
for path, v := range limiter.selected {
|
for path, v := range limiter.selected {
|
||||||
if v != "none" && path != Target.Path {
|
if v != "none" && !MainModules.Contains(path) {
|
||||||
mods = append(mods, module.Version{Path: path, Version: v})
|
mods = append(mods, module.Version{Path: path, Version: v})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +334,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
|
||||||
}
|
}
|
||||||
mods = make([]module.Version, 0, len(limiter.selected))
|
mods = make([]module.Version, 0, len(limiter.selected))
|
||||||
for path, _ := range limiter.selected {
|
for path, _ := range limiter.selected {
|
||||||
if path != Target.Path {
|
if !MainModules.Contains(path) {
|
||||||
if v := mg.Selected(path); v != "none" {
|
if v := mg.Selected(path); v != "none" {
|
||||||
mods = append(mods, module.Version{Path: path, Version: v})
|
mods = append(mods, module.Version{Path: path, Version: v})
|
||||||
}
|
}
|
||||||
|
|
@ -415,10 +415,14 @@ func (dq dqState) isDisqualified() bool {
|
||||||
// itself lazy, its unrestricted dependencies are skipped when scanning
|
// itself lazy, its unrestricted dependencies are skipped when scanning
|
||||||
// requirements.
|
// requirements.
|
||||||
func newVersionLimiter(depth modDepth, max map[string]string) *versionLimiter {
|
func newVersionLimiter(depth modDepth, max map[string]string) *versionLimiter {
|
||||||
|
selected := make(map[string]string)
|
||||||
|
for _, m := range MainModules.Versions() {
|
||||||
|
selected[m.Path] = m.Version
|
||||||
|
}
|
||||||
return &versionLimiter{
|
return &versionLimiter{
|
||||||
depth: depth,
|
depth: depth,
|
||||||
max: max,
|
max: max,
|
||||||
selected: map[string]string{Target.Path: Target.Version},
|
selected: selected,
|
||||||
dqReason: map[module.Version]dqState{},
|
dqReason: map[module.Version]dqState{},
|
||||||
requiring: map[module.Version][]module.Version{},
|
requiring: map[module.Version][]module.Version{},
|
||||||
}
|
}
|
||||||
|
|
@ -492,7 +496,7 @@ func (l *versionLimiter) Select(m module.Version) (conflict module.Version, err
|
||||||
// as is feasible, we don't want to retain test dependencies that are only
|
// as is feasible, we don't want to retain test dependencies that are only
|
||||||
// marginally relevant at best.
|
// marginally relevant at best.
|
||||||
func (l *versionLimiter) check(m module.Version, depth modDepth) dqState {
|
func (l *versionLimiter) check(m module.Version, depth modDepth) dqState {
|
||||||
if m.Version == "none" || m == Target {
|
if m.Version == "none" || m == MainModules.mustGetSingleMainModule() {
|
||||||
// version "none" has no requirements, and the dependencies of Target are
|
// version "none" has no requirements, and the dependencies of Target are
|
||||||
// tautological.
|
// tautological.
|
||||||
return dqState{}
|
return dqState{}
|
||||||
|
|
|
||||||
|
|
@ -257,11 +257,13 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||||
// Is the package in the standard library?
|
// Is the package in the standard library?
|
||||||
pathIsStd := search.IsStandardImportPath(path)
|
pathIsStd := search.IsStandardImportPath(path)
|
||||||
if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
|
if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
|
||||||
if targetInGorootSrc {
|
for _, mainModule := range MainModules.Versions() {
|
||||||
if dir, ok, err := dirInModule(path, targetPrefix, ModRoot(), true); err != nil {
|
if MainModules.InGorootSrc(mainModule) {
|
||||||
|
if dir, ok, err := dirInModule(path, MainModules.PathPrefix(mainModule), MainModules.ModRoot(mainModule), true); err != nil {
|
||||||
return module.Version{}, dir, err
|
return module.Version{}, dir, err
|
||||||
} else if ok {
|
} else if ok {
|
||||||
return Target, dir, nil
|
return mainModule, dir, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dir := filepath.Join(cfg.GOROOT, "src", path)
|
dir := filepath.Join(cfg.GOROOT, "src", path)
|
||||||
|
|
@ -271,8 +273,10 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||||
// -mod=vendor is special.
|
// -mod=vendor is special.
|
||||||
// Everything must be in the main module or the main module's vendor directory.
|
// Everything must be in the main module or the main module's vendor directory.
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
mainDir, mainOK, mainErr := dirInModule(path, targetPrefix, ModRoot(), true)
|
mainModule := MainModules.mustGetSingleMainModule()
|
||||||
vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
|
modRoot := MainModules.ModRoot(mainModule)
|
||||||
|
mainDir, mainOK, mainErr := dirInModule(path, MainModules.PathPrefix(mainModule), modRoot, true)
|
||||||
|
vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(modRoot, "vendor"), false)
|
||||||
if mainOK && vendorOK {
|
if mainOK && vendorOK {
|
||||||
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
|
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
|
||||||
}
|
}
|
||||||
|
|
@ -280,7 +284,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||||
// Note that we're not checking that the package exists.
|
// Note that we're not checking that the package exists.
|
||||||
// We'll leave that for load.
|
// We'll leave that for load.
|
||||||
if !vendorOK && mainDir != "" {
|
if !vendorOK && mainDir != "" {
|
||||||
return Target, mainDir, nil
|
return mainModule, mainDir, nil
|
||||||
}
|
}
|
||||||
if mainErr != nil {
|
if mainErr != nil {
|
||||||
return module.Version{}, "", mainErr
|
return module.Version{}, "", mainErr
|
||||||
|
|
@ -638,8 +642,8 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
|
||||||
// The isLocal return value reports whether the replacement,
|
// The isLocal return value reports whether the replacement,
|
||||||
// if any, is local to the filesystem.
|
// if any, is local to the filesystem.
|
||||||
func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, isLocal bool, err error) {
|
func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, isLocal bool, err error) {
|
||||||
if mod == Target {
|
if modRoot := MainModules.ModRoot(mod); modRoot != "" {
|
||||||
return ModRoot(), true, nil
|
return modRoot, true, nil
|
||||||
}
|
}
|
||||||
if r := Replacement(mod); r.Path != "" {
|
if r := Replacement(mod); r.Path != "" {
|
||||||
if r.Version == "" {
|
if r.Version == "" {
|
||||||
|
|
|
||||||
|
|
@ -45,26 +45,108 @@ var (
|
||||||
allowMissingModuleImports bool
|
allowMissingModuleImports bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TODOWorkspaces(s string) error {
|
||||||
|
return fmt.Errorf("need to support this for workspaces: %s", s)
|
||||||
|
}
|
||||||
|
|
||||||
// Variables set in Init.
|
// Variables set in Init.
|
||||||
var (
|
var (
|
||||||
initialized bool
|
initialized bool
|
||||||
modRoot string
|
|
||||||
|
// The directory containing go.work file. Set if in a go.work file is found
|
||||||
|
// and the go command is operating in workspace mode.
|
||||||
|
workRoot string
|
||||||
|
|
||||||
|
// These are primarily used to initialize the MainModules, and should be
|
||||||
|
// eventually superceded by them but are still used in cases where the module
|
||||||
|
// roots are required but MainModules hasn't been initialized yet. Set to
|
||||||
|
// the modRoots of the main modules.
|
||||||
|
// modRoots != nil implies len(modRoots) > 0
|
||||||
|
modRoots []string
|
||||||
gopath string
|
gopath string
|
||||||
)
|
)
|
||||||
|
|
||||||
// Variables set in initTarget (during {Load,Create}ModFile).
|
type MainModuleSet struct {
|
||||||
var (
|
// versions are the module.Version values of each of the main modules.
|
||||||
Target module.Version
|
// For each of them, the Path fields are ordinary module paths and the Version
|
||||||
|
// fields are empty strings.
|
||||||
|
versions []module.Version
|
||||||
|
|
||||||
// targetPrefix is the path prefix for packages in Target, without a trailing
|
// modRoot maps each module in versions to its absolute filesystem path.
|
||||||
// slash. For most modules, targetPrefix is just Target.Path, but the
|
modRoot map[module.Version]string
|
||||||
|
|
||||||
|
// pathPrefix is the path prefix for packages in the module, without a trailing
|
||||||
|
// slash. For most modules, pathPrefix is just version.Path, but the
|
||||||
// standard-library module "std" has an empty prefix.
|
// standard-library module "std" has an empty prefix.
|
||||||
targetPrefix string
|
pathPrefix map[module.Version]string
|
||||||
|
|
||||||
// targetInGorootSrc caches whether modRoot is within GOROOT/src.
|
// inGorootSrc caches whether modRoot is within GOROOT/src.
|
||||||
// The "std" module is special within GOROOT/src, but not otherwise.
|
// The "std" module is special within GOROOT/src, but not otherwise.
|
||||||
targetInGorootSrc bool
|
inGorootSrc map[module.Version]bool
|
||||||
)
|
}
|
||||||
|
|
||||||
|
func (mms *MainModuleSet) PathPrefix(m module.Version) string {
|
||||||
|
return mms.pathPrefix[m]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Versions returns the module.Version values of each of the main modules.
|
||||||
|
// For each of them, the Path fields are ordinary module paths and the Version
|
||||||
|
// fields are empty strings.
|
||||||
|
// Callers should not modify the returned slice.
|
||||||
|
func (mms *MainModuleSet) Versions() []module.Version {
|
||||||
|
if mms == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return mms.versions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mms *MainModuleSet) Contains(path string) bool {
|
||||||
|
if mms == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, v := range mms.versions {
|
||||||
|
if v.Path == path {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mms *MainModuleSet) ModRoot(m module.Version) string {
|
||||||
|
_ = TODOWorkspaces(" Do we need the Init? The original modRoot calls it. Audit callers.")
|
||||||
|
Init()
|
||||||
|
if mms == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return mms.modRoot[m]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mms *MainModuleSet) InGorootSrc(m module.Version) bool {
|
||||||
|
if mms == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return mms.inGorootSrc[m]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mms *MainModuleSet) mustGetSingleMainModule() module.Version {
|
||||||
|
if mms == nil || len(mms.versions) == 0 {
|
||||||
|
panic("internal error: mustGetSingleMainModule called in context with no main modules")
|
||||||
|
}
|
||||||
|
if len(mms.versions) != 1 {
|
||||||
|
_ = TODOWorkspaces("Check if we're in workspace mode before returning the below error.")
|
||||||
|
panic("internal error: mustGetSingleMainModule called in workspace mode")
|
||||||
|
}
|
||||||
|
return mms.versions[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mms *MainModuleSet) Len() int {
|
||||||
|
if mms == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(mms.versions)
|
||||||
|
}
|
||||||
|
|
||||||
|
var MainModules *MainModuleSet
|
||||||
|
|
||||||
type Root int
|
type Root int
|
||||||
|
|
||||||
|
|
@ -169,18 +251,17 @@ func Init() {
|
||||||
if os.Getenv("GCM_INTERACTIVE") == "" {
|
if os.Getenv("GCM_INTERACTIVE") == "" {
|
||||||
os.Setenv("GCM_INTERACTIVE", "never")
|
os.Setenv("GCM_INTERACTIVE", "never")
|
||||||
}
|
}
|
||||||
|
if modRoots != nil {
|
||||||
if modRoot != "" {
|
|
||||||
// modRoot set before Init was called ("go mod init" does this).
|
// modRoot set before Init was called ("go mod init" does this).
|
||||||
// No need to search for go.mod.
|
// No need to search for go.mod.
|
||||||
} else if RootMode == NoRoot {
|
} else if RootMode == NoRoot {
|
||||||
if cfg.ModFile != "" && !base.InGOFLAGS("-modfile") {
|
if cfg.ModFile != "" && !base.InGOFLAGS("-modfile") {
|
||||||
base.Fatalf("go: -modfile cannot be used with commands that ignore the current module")
|
base.Fatalf("go: -modfile cannot be used with commands that ignore the current module")
|
||||||
}
|
}
|
||||||
modRoot = ""
|
modRoots = nil
|
||||||
} else {
|
} else {
|
||||||
modRoot = findModuleRoot(base.Cwd())
|
modRoots = findModuleRoots(base.Cwd())
|
||||||
if modRoot == "" {
|
if modRoots == nil {
|
||||||
if cfg.ModFile != "" {
|
if cfg.ModFile != "" {
|
||||||
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
|
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
|
||||||
}
|
}
|
||||||
|
|
@ -192,13 +273,13 @@ func Init() {
|
||||||
// Stay in GOPATH mode.
|
// Stay in GOPATH mode.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if search.InDir(modRoot, os.TempDir()) == "." {
|
} else if search.InDir(modRoots[0], os.TempDir()) == "." {
|
||||||
// If you create /tmp/go.mod for experimenting,
|
// If you create /tmp/go.mod for experimenting,
|
||||||
// then any tests that create work directories under /tmp
|
// then any tests that create work directories under /tmp
|
||||||
// will find it and get modules when they're not expecting them.
|
// will find it and get modules when they're not expecting them.
|
||||||
// It's a bit of a peculiar thing to disallow but quite mysterious
|
// It's a bit of a peculiar thing to disallow but quite mysterious
|
||||||
// when it happens. See golang.org/issue/26708.
|
// when it happens. See golang.org/issue/26708.
|
||||||
modRoot = ""
|
modRoots = nil
|
||||||
fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
|
fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
|
||||||
if !mustUseModules {
|
if !mustUseModules {
|
||||||
return
|
return
|
||||||
|
|
@ -221,7 +302,7 @@ func Init() {
|
||||||
base.Fatalf("$GOPATH/go.mod exists but should not")
|
base.Fatalf("$GOPATH/go.mod exists but should not")
|
||||||
}
|
}
|
||||||
|
|
||||||
if modRoot == "" {
|
if modRoots == nil {
|
||||||
// We're in module mode, but not inside a module.
|
// We're in module mode, but not inside a module.
|
||||||
//
|
//
|
||||||
// Commands like 'go build', 'go run', 'go list' have no go.mod file to
|
// Commands like 'go build', 'go run', 'go list' have no go.mod file to
|
||||||
|
|
@ -240,8 +321,8 @@ func Init() {
|
||||||
//
|
//
|
||||||
// See golang.org/issue/32027.
|
// See golang.org/issue/32027.
|
||||||
} else {
|
} else {
|
||||||
|
_ = TODOWorkspaces("Instead of modfile path, find modfile OR workfile path depending on mode")
|
||||||
modfetch.GoSumFile = strings.TrimSuffix(ModFilePath(), ".mod") + ".sum"
|
modfetch.GoSumFile = strings.TrimSuffix(ModFilePath(), ".mod") + ".sum"
|
||||||
search.SetModRoot(modRoot)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,7 +336,7 @@ func Init() {
|
||||||
// be called until the command is installed and flags are parsed. Instead of
|
// be called until the command is installed and flags are parsed. Instead of
|
||||||
// calling Init and Enabled, the main package can call this function.
|
// calling Init and Enabled, the main package can call this function.
|
||||||
func WillBeEnabled() bool {
|
func WillBeEnabled() bool {
|
||||||
if modRoot != "" || cfg.ModulesEnabled {
|
if modRoots != nil || cfg.ModulesEnabled {
|
||||||
// Already enabled.
|
// Already enabled.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -276,11 +357,12 @@ func WillBeEnabled() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if modRoot := findModuleRoot(base.Cwd()); modRoot == "" {
|
if modRoots := findModuleRoots(base.Cwd()); modRoots == nil {
|
||||||
// GO111MODULE is 'auto', and we can't find a module root.
|
// GO111MODULE is 'auto', and we can't find a module root.
|
||||||
// Stay in GOPATH mode.
|
// Stay in GOPATH mode.
|
||||||
return false
|
return false
|
||||||
} else if search.InDir(modRoot, os.TempDir()) == "." {
|
} else if search.InDir(modRoots[0], os.TempDir()) == "." {
|
||||||
|
_ = TODOWorkspaces("modRoots[0] is not right here")
|
||||||
// If you create /tmp/go.mod for experimenting,
|
// If you create /tmp/go.mod for experimenting,
|
||||||
// then any tests that create work directories under /tmp
|
// then any tests that create work directories under /tmp
|
||||||
// will find it and get modules when they're not expecting them.
|
// will find it and get modules when they're not expecting them.
|
||||||
|
|
@ -297,7 +379,7 @@ func WillBeEnabled() bool {
|
||||||
// (usually through MustModRoot).
|
// (usually through MustModRoot).
|
||||||
func Enabled() bool {
|
func Enabled() bool {
|
||||||
Init()
|
Init()
|
||||||
return modRoot != "" || cfg.ModulesEnabled
|
return modRoots != nil || cfg.ModulesEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModRoot returns the root of the main module.
|
// ModRoot returns the root of the main module.
|
||||||
|
|
@ -306,7 +388,10 @@ func ModRoot() string {
|
||||||
if !HasModRoot() {
|
if !HasModRoot() {
|
||||||
die()
|
die()
|
||||||
}
|
}
|
||||||
return modRoot
|
if len(modRoots) != 1 {
|
||||||
|
panic(TODOWorkspaces("need to handle multiple modroots here"))
|
||||||
|
}
|
||||||
|
return modRoots[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasModRoot reports whether a main module is present.
|
// HasModRoot reports whether a main module is present.
|
||||||
|
|
@ -314,7 +399,7 @@ func ModRoot() string {
|
||||||
// does not require a main module.
|
// does not require a main module.
|
||||||
func HasModRoot() bool {
|
func HasModRoot() bool {
|
||||||
Init()
|
Init()
|
||||||
return modRoot != ""
|
return modRoots != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModFilePath returns the effective path of the go.mod file. Normally, this
|
// ModFilePath returns the effective path of the go.mod file. Normally, this
|
||||||
|
|
@ -322,9 +407,10 @@ func HasModRoot() bool {
|
||||||
// change its location. ModFilePath calls base.Fatalf if there is no main
|
// change its location. ModFilePath calls base.Fatalf if there is no main
|
||||||
// module, even if -modfile is set.
|
// module, even if -modfile is set.
|
||||||
func ModFilePath() string {
|
func ModFilePath() string {
|
||||||
if !HasModRoot() {
|
return modFilePath(ModRoot())
|
||||||
die()
|
}
|
||||||
}
|
|
||||||
|
func modFilePath(modRoot string) string {
|
||||||
if cfg.ModFile != "" {
|
if cfg.ModFile != "" {
|
||||||
return cfg.ModFile
|
return cfg.ModFile
|
||||||
}
|
}
|
||||||
|
|
@ -402,11 +488,12 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Init()
|
Init()
|
||||||
if modRoot == "" {
|
if len(modRoots) == 0 {
|
||||||
Target = module.Version{Path: "command-line-arguments"}
|
_ = TODOWorkspaces("Instead of creating a fake module with an empty modroot, make MainModules.Len() == 0 mean that we're in module mode but not inside any module.")
|
||||||
targetPrefix = "command-line-arguments"
|
mainModule := module.Version{Path: "command-line-arguments"}
|
||||||
|
MainModules = makeMainModules([]module.Version{mainModule}, []string{""})
|
||||||
goVersion := LatestGoVersion()
|
goVersion := LatestGoVersion()
|
||||||
rawGoVersion.Store(Target, goVersion)
|
rawGoVersion.Store(mainModule, goVersion)
|
||||||
requirements = newRequirements(modDepthFromGoVersion(goVersion), nil, nil)
|
requirements = newRequirements(modDepthFromGoVersion(goVersion), nil, nil)
|
||||||
return requirements, false
|
return requirements, false
|
||||||
}
|
}
|
||||||
|
|
@ -428,9 +515,13 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
|
||||||
base.Fatalf("go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
|
base.Fatalf("go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For now, this code assumes there's a single main module, because there's
|
||||||
|
// no way to specify multiple main modules yet. TODO(#45713): update this
|
||||||
|
// in a later CL.
|
||||||
modFile = f
|
modFile = f
|
||||||
initTarget(f.Module.Mod)
|
mainModule := f.Module.Mod
|
||||||
index = indexModFile(data, f, fixed)
|
MainModules = makeMainModules([]module.Version{mainModule}, modRoots)
|
||||||
|
index = indexModFile(data, f, mainModule, fixed)
|
||||||
|
|
||||||
if err := module.CheckImportPath(f.Module.Mod.Path); err != nil {
|
if err := module.CheckImportPath(f.Module.Mod.Path); err != nil {
|
||||||
if pathErr, ok := err.(*module.InvalidPathError); ok {
|
if pathErr, ok := err.(*module.InvalidPathError); ok {
|
||||||
|
|
@ -451,7 +542,7 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
|
||||||
// TODO(#45551): Do something more principled instead of checking
|
// TODO(#45551): Do something more principled instead of checking
|
||||||
// cfg.CmdName directly here.
|
// cfg.CmdName directly here.
|
||||||
if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" {
|
if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" {
|
||||||
addGoStmt(LatestGoVersion())
|
addGoStmt(mainModule, LatestGoVersion())
|
||||||
if go117EnableLazyLoading {
|
if go117EnableLazyLoading {
|
||||||
// We need to add a 'go' version to the go.mod file, but we must assume
|
// We need to add a 'go' version to the go.mod file, but we must assume
|
||||||
// that its existing contents match something between Go 1.11 and 1.16.
|
// that its existing contents match something between Go 1.11 and 1.16.
|
||||||
|
|
@ -464,7 +555,7 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rawGoVersion.Store(Target, modFileGoVersion())
|
rawGoVersion.Store(mainModule, modFileGoVersion())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -482,7 +573,8 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
|
||||||
// exactly the same as in the legacy configuration (for example, we can't get
|
// exactly the same as in the legacy configuration (for example, we can't get
|
||||||
// packages at multiple versions from the same module).
|
// packages at multiple versions from the same module).
|
||||||
func CreateModFile(ctx context.Context, modPath string) {
|
func CreateModFile(ctx context.Context, modPath string) {
|
||||||
modRoot = base.Cwd()
|
modRoot := base.Cwd()
|
||||||
|
modRoots = []string{modRoot}
|
||||||
Init()
|
Init()
|
||||||
modFilePath := ModFilePath()
|
modFilePath := ModFilePath()
|
||||||
if _, err := fsys.Stat(modFilePath); err == nil {
|
if _, err := fsys.Stat(modFilePath); err == nil {
|
||||||
|
|
@ -510,8 +602,8 @@ func CreateModFile(ctx context.Context, modPath string) {
|
||||||
fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath)
|
fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath)
|
||||||
modFile = new(modfile.File)
|
modFile = new(modfile.File)
|
||||||
modFile.AddModuleStmt(modPath)
|
modFile.AddModuleStmt(modPath)
|
||||||
initTarget(modFile.Module.Mod)
|
MainModules = makeMainModules([]module.Version{modFile.Module.Mod}, []string{modRoot})
|
||||||
addGoStmt(LatestGoVersion()) // Add the go directive before converted module requirements.
|
addGoStmt(modFile.Module.Mod, LatestGoVersion()) // Add the go directive before converted module requirements.
|
||||||
|
|
||||||
convertedFrom, err := convertLegacyConfig(modPath)
|
convertedFrom, err := convertLegacyConfig(modPath)
|
||||||
if convertedFrom != "" {
|
if convertedFrom != "" {
|
||||||
|
|
@ -609,13 +701,26 @@ func AllowMissingModuleImports() {
|
||||||
allowMissingModuleImports = true
|
allowMissingModuleImports = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// initTarget sets Target and associated variables according to modFile,
|
// makeMainModules creates a MainModuleSet and associated variables according to
|
||||||
func initTarget(m module.Version) {
|
// the given main modules.
|
||||||
Target = m
|
func makeMainModules(ms []module.Version, rootDirs []string) *MainModuleSet {
|
||||||
targetPrefix = m.Path
|
for _, m := range ms {
|
||||||
|
if m.Version != "" {
|
||||||
|
panic("mainModulesCalled with module.Version with non empty Version field: " + fmt.Sprintf("%#v", m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mainModules := &MainModuleSet{
|
||||||
|
versions: ms[:len(ms):len(ms)],
|
||||||
|
inGorootSrc: map[module.Version]bool{},
|
||||||
|
pathPrefix: map[module.Version]string{},
|
||||||
|
modRoot: map[module.Version]string{},
|
||||||
|
}
|
||||||
|
for i, m := range ms {
|
||||||
|
mainModules.pathPrefix[m] = m.Path
|
||||||
|
mainModules.modRoot[m] = rootDirs[i]
|
||||||
|
|
||||||
if rel := search.InDir(base.Cwd(), cfg.GOROOTsrc); rel != "" {
|
if rel := search.InDir(rootDirs[i], cfg.GOROOTsrc); rel != "" {
|
||||||
targetInGorootSrc = true
|
mainModules.inGorootSrc[m] = true
|
||||||
if m.Path == "std" {
|
if m.Path == "std" {
|
||||||
// The "std" module in GOROOT/src is the Go standard library. Unlike other
|
// The "std" module in GOROOT/src is the Go standard library. Unlike other
|
||||||
// modules, the packages in the "std" module have no import-path prefix.
|
// modules, the packages in the "std" module have no import-path prefix.
|
||||||
|
|
@ -625,16 +730,21 @@ func initTarget(m module.Version) {
|
||||||
// test individual packages using a combination of the modified package
|
// test individual packages using a combination of the modified package
|
||||||
// and the ordinary standard library.
|
// and the ordinary standard library.
|
||||||
// (See https://golang.org/issue/30756.)
|
// (See https://golang.org/issue/30756.)
|
||||||
targetPrefix = ""
|
mainModules.pathPrefix[m] = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return mainModules
|
||||||
}
|
}
|
||||||
|
|
||||||
// requirementsFromModFile returns the set of non-excluded requirements from
|
// requirementsFromModFile returns the set of non-excluded requirements from
|
||||||
// the global modFile.
|
// the global modFile.
|
||||||
func requirementsFromModFile(ctx context.Context) *Requirements {
|
func requirementsFromModFile(ctx context.Context) *Requirements {
|
||||||
roots := make([]module.Version, 0, len(modFile.Require))
|
roots := make([]module.Version, 0, len(modFile.Require))
|
||||||
mPathCount := map[string]int{Target.Path: 1}
|
mPathCount := make(map[string]int)
|
||||||
|
for _, m := range MainModules.Versions() {
|
||||||
|
mPathCount[m.Path] = 1
|
||||||
|
}
|
||||||
direct := map[string]bool{}
|
direct := map[string]bool{}
|
||||||
for _, r := range modFile.Require {
|
for _, r := range modFile.Require {
|
||||||
if index != nil && index.exclude[r.Mod] {
|
if index != nil && index.exclude[r.Mod] {
|
||||||
|
|
@ -687,7 +797,7 @@ func setDefaultBuildMod() {
|
||||||
cfg.BuildMod = "mod"
|
cfg.BuildMod = "mod"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if modRoot == "" {
|
if modRoots == nil {
|
||||||
if allowMissingModuleImports {
|
if allowMissingModuleImports {
|
||||||
cfg.BuildMod = "mod"
|
cfg.BuildMod = "mod"
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -696,7 +806,8 @@ func setDefaultBuildMod() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if fi, err := fsys.Stat(filepath.Join(modRoot, "vendor")); err == nil && fi.IsDir() {
|
if len(modRoots) == 1 {
|
||||||
|
if fi, err := fsys.Stat(filepath.Join(modRoots[0], "vendor")); err == nil && fi.IsDir() {
|
||||||
modGo := "unspecified"
|
modGo := "unspecified"
|
||||||
if index != nil && index.goVersionV != "" {
|
if index != nil && index.goVersionV != "" {
|
||||||
if semver.Compare(index.goVersionV, "v1.14") >= 0 {
|
if semver.Compare(index.goVersionV, "v1.14") >= 0 {
|
||||||
|
|
@ -714,6 +825,7 @@ func setDefaultBuildMod() {
|
||||||
// This message won't normally be shown, but it may appear with import errors.
|
// This message won't normally be shown, but it may appear with import errors.
|
||||||
cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s, so vendor directory was not used.", modGo)
|
cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s, so vendor directory was not used.", modGo)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg.BuildMod = "readonly"
|
cfg.BuildMod = "readonly"
|
||||||
}
|
}
|
||||||
|
|
@ -733,7 +845,10 @@ func convertLegacyConfig(modPath string) (from string, err error) {
|
||||||
return modOnly.Mod, nil
|
return modOnly.Mod, nil
|
||||||
}
|
}
|
||||||
for _, name := range altConfigs {
|
for _, name := range altConfigs {
|
||||||
cfg := filepath.Join(modRoot, name)
|
if len(modRoots) != 1 {
|
||||||
|
panic(TODOWorkspaces("what do do here?"))
|
||||||
|
}
|
||||||
|
cfg := filepath.Join(modRoots[0], name)
|
||||||
data, err := os.ReadFile(cfg)
|
data, err := os.ReadFile(cfg)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
convert := modconv.Converters[name]
|
convert := modconv.Converters[name]
|
||||||
|
|
@ -751,14 +866,14 @@ func convertLegacyConfig(modPath string) (from string, err error) {
|
||||||
// addGoStmt adds a go directive to the go.mod file if it does not already
|
// addGoStmt adds a go directive to the go.mod file if it does not already
|
||||||
// include one. The 'go' version added, if any, is the latest version supported
|
// include one. The 'go' version added, if any, is the latest version supported
|
||||||
// by this toolchain.
|
// by this toolchain.
|
||||||
func addGoStmt(v string) {
|
func addGoStmt(mod module.Version, v string) {
|
||||||
if modFile.Go != nil && modFile.Go.Version != "" {
|
if modFile.Go != nil && modFile.Go.Version != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := modFile.AddGoStmt(v); err != nil {
|
if err := modFile.AddGoStmt(v); err != nil {
|
||||||
base.Fatalf("go: internal error: %v", err)
|
base.Fatalf("go: internal error: %v", err)
|
||||||
}
|
}
|
||||||
rawGoVersion.Store(Target, v)
|
rawGoVersion.Store(mod, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LatestGoVersion returns the latest version of the Go language supported by
|
// LatestGoVersion returns the latest version of the Go language supported by
|
||||||
|
|
@ -809,7 +924,7 @@ var altConfigs = []string{
|
||||||
".git/config",
|
".git/config",
|
||||||
}
|
}
|
||||||
|
|
||||||
func findModuleRoot(dir string) (root string) {
|
func findModuleRoots(dir string) (roots []string) {
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
panic("dir not set")
|
panic("dir not set")
|
||||||
}
|
}
|
||||||
|
|
@ -818,7 +933,7 @@ func findModuleRoot(dir string) (root string) {
|
||||||
// Look for enclosing go.mod.
|
// Look for enclosing go.mod.
|
||||||
for {
|
for {
|
||||||
if fi, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
|
if fi, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
|
||||||
return dir
|
return []string{dir}
|
||||||
}
|
}
|
||||||
d := filepath.Dir(dir)
|
d := filepath.Dir(dir)
|
||||||
if d == dir {
|
if d == dir {
|
||||||
|
|
@ -826,7 +941,7 @@ func findModuleRoot(dir string) (root string) {
|
||||||
}
|
}
|
||||||
dir = d
|
dir = d
|
||||||
}
|
}
|
||||||
return ""
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAltConfig(dir string) (root, name string) {
|
func findAltConfig(dir string) (root, name string) {
|
||||||
|
|
@ -987,7 +1102,8 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if modRoot == "" {
|
if MainModules.Len() != 1 || MainModules.ModRoot(MainModules.Versions()[0]) == "" {
|
||||||
|
_ = TODOWorkspaces("also check that workspace mode is off")
|
||||||
// We aren't in a module, so we don't have anywhere to write a go.mod file.
|
// We aren't in a module, so we don't have anywhere to write a go.mod file.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1032,8 +1148,14 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
if MainModules.Len() != 1 {
|
||||||
|
panic(TODOWorkspaces("There should be exactly one main module when committing reqs"))
|
||||||
|
}
|
||||||
|
|
||||||
|
mainModule := MainModules.Versions()[0]
|
||||||
|
|
||||||
// At this point we have determined to make the go.mod file on disk equal to new.
|
// At this point we have determined to make the go.mod file on disk equal to new.
|
||||||
index = indexModFile(new, modFile, false)
|
index = indexModFile(new, modFile, mainModule, false)
|
||||||
|
|
||||||
// Update go.sum after releasing the side lock and refreshing the index.
|
// Update go.sum after releasing the side lock and refreshing the index.
|
||||||
// 'go mod init' shouldn't write go.sum, since it will be incomplete.
|
// 'go mod init' shouldn't write go.sum, since it will be incomplete.
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,11 @@ func ListModules(ctx context.Context, args []string, mode ListMode) ([]*modinfo.
|
||||||
|
|
||||||
func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
|
func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return rs, []*modinfo.ModulePublic{moduleInfo(ctx, rs, Target, mode)}, nil
|
var ms []*modinfo.ModulePublic
|
||||||
|
for _, m := range MainModules.Versions() {
|
||||||
|
ms = append(ms, moduleInfo(ctx, rs, m, mode))
|
||||||
|
}
|
||||||
|
return rs, ms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
needFullGraph := false
|
needFullGraph := false
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,9 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||||
|
|
||||||
// If we're outside of a module, ensure that the failure mode
|
// If we're outside of a module, ensure that the failure mode
|
||||||
// indicates that.
|
// indicates that.
|
||||||
ModRoot()
|
if !HasModRoot() {
|
||||||
|
die()
|
||||||
|
}
|
||||||
|
|
||||||
if ld != nil {
|
if ld != nil {
|
||||||
m.AddError(err)
|
m.AddError(err)
|
||||||
|
|
@ -306,7 +308,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||||
// The initial roots are the packages in the main module.
|
// The initial roots are the packages in the main module.
|
||||||
// loadFromRoots will expand that to "all".
|
// loadFromRoots will expand that to "all".
|
||||||
m.Errs = m.Errs[:0]
|
m.Errs = m.Errs[:0]
|
||||||
matchPackages(ctx, m, opts.Tags, omitStd, []module.Version{Target})
|
matchPackages(ctx, m, opts.Tags, omitStd, MainModules.Versions())
|
||||||
} else {
|
} else {
|
||||||
// Starting with the packages in the main module,
|
// Starting with the packages in the main module,
|
||||||
// enumerate the full list of "all".
|
// enumerate the full list of "all".
|
||||||
|
|
@ -443,7 +445,7 @@ func matchLocalDirs(ctx context.Context, m *search.Match, rs *Requirements) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.MatchDirs()
|
m.MatchDirs(modRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveLocalPackage resolves a filesystem path to a package path.
|
// resolveLocalPackage resolves a filesystem path to a package path.
|
||||||
|
|
@ -485,16 +487,23 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, mod := range MainModules.Versions() {
|
||||||
|
modRoot := MainModules.ModRoot(mod)
|
||||||
if modRoot != "" && absDir == modRoot {
|
if modRoot != "" && absDir == modRoot {
|
||||||
if absDir == cfg.GOROOTsrc {
|
if absDir == cfg.GOROOTsrc {
|
||||||
return "", errPkgIsGorootSrc
|
return "", errPkgIsGorootSrc
|
||||||
}
|
}
|
||||||
return targetPrefix, nil
|
return MainModules.PathPrefix(mod), nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: The checks for @ here are just to avoid misinterpreting
|
// Note: The checks for @ here are just to avoid misinterpreting
|
||||||
// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
|
// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
|
||||||
// It's not strictly necessary but helpful to keep the checks.
|
// It's not strictly necessary but helpful to keep the checks.
|
||||||
|
var pkgNotFoundErr error
|
||||||
|
pkgNotFoundLongestPrefix := ""
|
||||||
|
for _, mainModule := range MainModules.Versions() {
|
||||||
|
modRoot := MainModules.ModRoot(mainModule)
|
||||||
if modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") {
|
if modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") {
|
||||||
suffix := filepath.ToSlash(absDir[len(modRoot):])
|
suffix := filepath.ToSlash(absDir[len(modRoot):])
|
||||||
if strings.HasPrefix(suffix, "/vendor/") {
|
if strings.HasPrefix(suffix, "/vendor/") {
|
||||||
|
|
@ -510,7 +519,8 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetPrefix == "" {
|
mainModulePrefix := MainModules.PathPrefix(mainModule)
|
||||||
|
if mainModulePrefix == "" {
|
||||||
pkg := strings.TrimPrefix(suffix, "/")
|
pkg := strings.TrimPrefix(suffix, "/")
|
||||||
if pkg == "builtin" {
|
if pkg == "builtin" {
|
||||||
// "builtin" is a pseudo-package with a real source file.
|
// "builtin" is a pseudo-package with a real source file.
|
||||||
|
|
@ -521,14 +531,27 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg := targetPrefix + suffix
|
pkg := mainModulePrefix + suffix
|
||||||
if _, ok, err := dirInModule(pkg, targetPrefix, modRoot, true); err != nil {
|
if _, ok, err := dirInModule(pkg, mainModulePrefix, modRoot, true); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
return "", &PackageNotInModuleError{Mod: Target, Pattern: pkg}
|
// This main module could contain the directory but doesn't. Other main
|
||||||
|
// modules might contain the directory, so wait till we finish the loop
|
||||||
|
// to see if another main module contains directory. But if not,
|
||||||
|
// return an error.
|
||||||
|
if len(mainModulePrefix) > len(pkgNotFoundLongestPrefix) {
|
||||||
|
pkgNotFoundLongestPrefix = mainModulePrefix
|
||||||
|
pkgNotFoundErr = &PackageNotInModuleError{Mod: mainModule, Pattern: pkg}
|
||||||
|
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if pkgNotFoundErr != nil {
|
||||||
|
return "", pkgNotFoundErr
|
||||||
|
}
|
||||||
|
|
||||||
if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
|
if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
|
||||||
pkg := filepath.ToSlash(sub)
|
pkg := filepath.ToSlash(sub)
|
||||||
|
|
@ -649,10 +672,10 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirImportPath returns the effective import path for dir,
|
// DirImportPath returns the effective import path for dir,
|
||||||
// provided it is within the main module, or else returns ".".
|
// provided it is within a main module, or else returns ".".
|
||||||
func DirImportPath(ctx context.Context, dir string) string {
|
func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path string, m module.Version) {
|
||||||
if !HasModRoot() {
|
if !HasModRoot() {
|
||||||
return "."
|
return ".", module.Version{}
|
||||||
}
|
}
|
||||||
LoadModFile(ctx) // Sets targetPrefix.
|
LoadModFile(ctx) // Sets targetPrefix.
|
||||||
|
|
||||||
|
|
@ -662,17 +685,32 @@ func DirImportPath(ctx context.Context, dir string) string {
|
||||||
dir = filepath.Clean(dir)
|
dir = filepath.Clean(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var longestPrefix string
|
||||||
|
var longestPrefixPath string
|
||||||
|
var longestPrefixVersion module.Version
|
||||||
|
for _, v := range mms.Versions() {
|
||||||
|
modRoot := mms.ModRoot(v)
|
||||||
if dir == modRoot {
|
if dir == modRoot {
|
||||||
return targetPrefix
|
return mms.PathPrefix(v), v
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
|
if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
|
||||||
|
pathPrefix := MainModules.PathPrefix(v)
|
||||||
|
if pathPrefix > longestPrefix {
|
||||||
|
longestPrefix = pathPrefix
|
||||||
|
longestPrefixVersion = v
|
||||||
suffix := filepath.ToSlash(dir[len(modRoot):])
|
suffix := filepath.ToSlash(dir[len(modRoot):])
|
||||||
if strings.HasPrefix(suffix, "/vendor/") {
|
if strings.HasPrefix(suffix, "/vendor/") {
|
||||||
return strings.TrimPrefix(suffix, "/vendor/")
|
longestPrefixPath = strings.TrimPrefix(suffix, "/vendor/")
|
||||||
}
|
}
|
||||||
return targetPrefix + suffix
|
longestPrefixPath = mms.PathPrefix(v) + suffix
|
||||||
}
|
}
|
||||||
return "."
|
}
|
||||||
|
}
|
||||||
|
if len(longestPrefix) > 0 {
|
||||||
|
return longestPrefixPath, longestPrefixVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
return ".", module.Version{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TargetPackages returns the list of packages in the target (top-level) module
|
// TargetPackages returns the list of packages in the target (top-level) module
|
||||||
|
|
@ -685,7 +723,7 @@ func TargetPackages(ctx context.Context, pattern string) *search.Match {
|
||||||
ModRoot() // Emits an error if Target cannot contain packages.
|
ModRoot() // Emits an error if Target cannot contain packages.
|
||||||
|
|
||||||
m := search.NewMatch(pattern)
|
m := search.NewMatch(pattern)
|
||||||
matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{Target})
|
matchPackages(ctx, m, imports.AnyTags(), omitStd, MainModules.Versions())
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -931,10 +969,7 @@ func (pkg *loadPkg) fromExternalModule() bool {
|
||||||
if pkg.mod.Path == "" {
|
if pkg.mod.Path == "" {
|
||||||
return false // loaded from the standard library, not a module
|
return false // loaded from the standard library, not a module
|
||||||
}
|
}
|
||||||
if pkg.mod.Path == Target.Path {
|
return !MainModules.Contains(pkg.mod.Path)
|
||||||
return false // loaded from the main module.
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var errMissing = errors.New("cannot find package")
|
var errMissing = errors.New("cannot find package")
|
||||||
|
|
@ -1205,7 +1240,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range ld.pkgs {
|
for _, pkg := range ld.pkgs {
|
||||||
if pkg.mod != Target {
|
if pkg.mod.Version != "" || !MainModules.Contains(pkg.mod.Path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, dep := range pkg.imports {
|
for _, dep := range pkg.imports {
|
||||||
|
|
@ -1462,7 +1497,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
|
||||||
// so it's ok if we call it more than is strictly necessary.
|
// so it's ok if we call it more than is strictly necessary.
|
||||||
wantTest := false
|
wantTest := false
|
||||||
switch {
|
switch {
|
||||||
case ld.allPatternIsRoot && pkg.mod == Target:
|
case ld.allPatternIsRoot && MainModules.Contains(pkg.mod.Path):
|
||||||
// We are loading the "all" pattern, which includes packages imported by
|
// We are loading the "all" pattern, which includes packages imported by
|
||||||
// tests in the main module. This package is in the main module, so we
|
// tests in the main module. This package is in the main module, so we
|
||||||
// need to identify the imports of its test even if LoadTests is not set.
|
// need to identify the imports of its test even if LoadTests is not set.
|
||||||
|
|
@ -1483,7 +1518,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
|
||||||
|
|
||||||
if wantTest {
|
if wantTest {
|
||||||
var testFlags loadPkgFlags
|
var testFlags loadPkgFlags
|
||||||
if pkg.mod == Target || (ld.allClosesOverTests && new.has(pkgInAll)) {
|
if MainModules.Contains(pkg.mod.Path) || (ld.allClosesOverTests && new.has(pkgInAll)) {
|
||||||
// Tests of packages in the main module are in "all", in the sense that
|
// Tests of packages in the main module are in "all", in the sense that
|
||||||
// they cause the packages they import to also be in "all". So are tests
|
// they cause the packages they import to also be in "all". So are tests
|
||||||
// of packages in "all" if "all" closes over test dependencies.
|
// of packages in "all" if "all" closes over test dependencies.
|
||||||
|
|
@ -1630,7 +1665,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
|
||||||
if pkg.dir == "" {
|
if pkg.dir == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if pkg.mod == Target {
|
if MainModules.Contains(pkg.mod.Path) {
|
||||||
// Go ahead and mark pkg as in "all". This provides the invariant that a
|
// Go ahead and mark pkg as in "all". This provides the invariant that a
|
||||||
// package that is *only* imported by other packages in "all" is always
|
// package that is *only* imported by other packages in "all" is always
|
||||||
// marked as such before loading its imports.
|
// marked as such before loading its imports.
|
||||||
|
|
@ -1735,13 +1770,14 @@ func (ld *loader) stdVendor(parentPath, path string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if str.HasPathPrefix(parentPath, "cmd") {
|
if str.HasPathPrefix(parentPath, "cmd") {
|
||||||
if !ld.VendorModulesInGOROOTSrc || Target.Path != "cmd" {
|
if !ld.VendorModulesInGOROOTSrc || !MainModules.Contains("cmd") {
|
||||||
vendorPath := pathpkg.Join("cmd", "vendor", path)
|
vendorPath := pathpkg.Join("cmd", "vendor", path)
|
||||||
|
|
||||||
if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
|
if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
|
||||||
return vendorPath
|
return vendorPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !ld.VendorModulesInGOROOTSrc || Target.Path != "std" || str.HasPathPrefix(parentPath, "vendor") {
|
} else if !ld.VendorModulesInGOROOTSrc || !MainModules.Contains("std") || str.HasPathPrefix(parentPath, "vendor") {
|
||||||
// If we are outside of the 'std' module, resolve imports from within 'std'
|
// If we are outside of the 'std' module, resolve imports from within 'std'
|
||||||
// to the vendor directory.
|
// to the vendor directory.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,7 @@ func resolveReplacement(m module.Version) module.Version {
|
||||||
// indexModFile rebuilds the index of modFile.
|
// indexModFile rebuilds the index of modFile.
|
||||||
// If modFile has been changed since it was first read,
|
// If modFile has been changed since it was first read,
|
||||||
// modFile.Cleanup must be called before indexModFile.
|
// modFile.Cleanup must be called before indexModFile.
|
||||||
func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileIndex {
|
func indexModFile(data []byte, modFile *modfile.File, mod module.Version, needsFix bool) *modFileIndex {
|
||||||
i := new(modFileIndex)
|
i := new(modFileIndex)
|
||||||
i.data = data
|
i.data = data
|
||||||
i.dataNeedsFix = needsFix
|
i.dataNeedsFix = needsFix
|
||||||
|
|
@ -343,12 +343,12 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
|
||||||
|
|
||||||
i.goVersionV = ""
|
i.goVersionV = ""
|
||||||
if modFile.Go == nil {
|
if modFile.Go == nil {
|
||||||
rawGoVersion.Store(Target, "")
|
rawGoVersion.Store(mod, "")
|
||||||
} else {
|
} else {
|
||||||
// We're going to use the semver package to compare Go versions, so go ahead
|
// We're going to use the semver package to compare Go versions, so go ahead
|
||||||
// and add the "v" prefix it expects once instead of every time.
|
// and add the "v" prefix it expects once instead of every time.
|
||||||
i.goVersionV = "v" + modFile.Go.Version
|
i.goVersionV = "v" + modFile.Go.Version
|
||||||
rawGoVersion.Store(Target, modFile.Go.Version)
|
rawGoVersion.Store(mod, modFile.Go.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
i.require = make(map[module.Version]requireMeta, len(modFile.Require))
|
i.require = make(map[module.Version]requireMeta, len(modFile.Require))
|
||||||
|
|
@ -488,8 +488,8 @@ type retraction struct {
|
||||||
//
|
//
|
||||||
// The caller must not modify the returned summary.
|
// The caller must not modify the returned summary.
|
||||||
func goModSummary(m module.Version) (*modFileSummary, error) {
|
func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
if m == Target {
|
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||||
panic("internal error: goModSummary called on the Target module")
|
panic("internal error: goModSummary called on a main module")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
|
|
@ -583,7 +583,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
//
|
//
|
||||||
// rawGoModSummary cannot be used on the Target module.
|
// rawGoModSummary cannot be used on the Target module.
|
||||||
func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
if m == Target {
|
if m.Path == "" && MainModules.Contains(m.Path) {
|
||||||
panic("internal error: rawGoModSummary called on the Target module")
|
panic("internal error: rawGoModSummary called on the Target module")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ type mvsReqs struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
|
func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
|
||||||
if mod == Target {
|
if MainModules.Contains(mod.Path) {
|
||||||
// Use the build list as it existed when r was constructed, not the current
|
// Use the build list as it existed when r was constructed, not the current
|
||||||
// global build list.
|
// global build list.
|
||||||
return r.roots, nil
|
return r.roots, nil
|
||||||
|
|
@ -113,7 +113,7 @@ func versions(ctx context.Context, path string, allowed AllowedFunc) ([]string,
|
||||||
func previousVersion(m module.Version) (module.Version, error) {
|
func previousVersion(m module.Version) (module.Version, error) {
|
||||||
// TODO(golang.org/issue/38714): thread tracing context through MVS.
|
// TODO(golang.org/issue/38714): thread tracing context through MVS.
|
||||||
|
|
||||||
if m == Target {
|
if MainModules.Contains(m.Path) {
|
||||||
return module.Version{Path: m.Path, Version: "none"}, nil
|
return module.Version{Path: m.Path, Version: "none"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,11 +110,12 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
|
||||||
allowed = func(context.Context, module.Version) error { return nil }
|
allowed = func(context.Context, module.Version) error { return nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == Target.Path && (query == "upgrade" || query == "patch") {
|
if MainModules.Contains(path) && (query == "upgrade" || query == "patch") {
|
||||||
if err := allowed(ctx, Target); err != nil {
|
m := module.Version{Path: path}
|
||||||
|
if err := allowed(ctx, m); err != nil {
|
||||||
return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
|
return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
|
||||||
}
|
}
|
||||||
return &modfetch.RevInfo{Version: Target.Version}, nil
|
return &modfetch.RevInfo{Version: m.Version}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == "std" || path == "cmd" {
|
if path == "std" || path == "cmd" {
|
||||||
|
|
@ -551,7 +552,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
return m.Errs[0]
|
return m.Errs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
var match func(mod module.Version, root string, isLocal bool) *search.Match
|
var match func(mod module.Version, roots []string, isLocal bool) *search.Match
|
||||||
matchPattern := search.MatchPattern(pattern)
|
matchPattern := search.MatchPattern(pattern)
|
||||||
|
|
||||||
if i := strings.Index(pattern, "..."); i >= 0 {
|
if i := strings.Index(pattern, "..."); i >= 0 {
|
||||||
|
|
@ -559,30 +560,32 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
if base == "." {
|
if base == "." {
|
||||||
return nil, nil, &WildcardInFirstElementError{Pattern: pattern, Query: query}
|
return nil, nil, &WildcardInFirstElementError{Pattern: pattern, Query: query}
|
||||||
}
|
}
|
||||||
match = func(mod module.Version, root string, isLocal bool) *search.Match {
|
match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
|
||||||
m := search.NewMatch(pattern)
|
m := search.NewMatch(pattern)
|
||||||
matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
|
matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match = func(mod module.Version, root string, isLocal bool) *search.Match {
|
match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
|
||||||
m := search.NewMatch(pattern)
|
m := search.NewMatch(pattern)
|
||||||
prefix := mod.Path
|
prefix := mod.Path
|
||||||
if mod == Target {
|
if MainModules.Contains(mod.Path) {
|
||||||
prefix = targetPrefix
|
prefix = MainModules.PathPrefix(module.Version{Path: mod.Path})
|
||||||
}
|
}
|
||||||
|
for _, root := range roots {
|
||||||
if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
|
if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
|
||||||
m.AddError(err)
|
m.AddError(err)
|
||||||
} else if ok {
|
} else if ok {
|
||||||
m.Pkgs = []string{pattern}
|
m.Pkgs = []string{pattern}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryMatchesMainModule bool
|
var mainModuleMatches []module.Version
|
||||||
if HasModRoot() {
|
for _, mainModule := range MainModules.Versions() {
|
||||||
m := match(Target, modRoot, true)
|
m := match(mainModule, modRoots, true)
|
||||||
if len(m.Pkgs) > 0 {
|
if len(m.Pkgs) > 0 {
|
||||||
if query != "upgrade" && query != "patch" {
|
if query != "upgrade" && query != "patch" {
|
||||||
return nil, nil, &QueryMatchesPackagesInMainModuleError{
|
return nil, nil, &QueryMatchesPackagesInMainModuleError{
|
||||||
|
|
@ -591,12 +594,12 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
Packages: m.Pkgs,
|
Packages: m.Pkgs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := allowed(ctx, Target); err != nil {
|
if err := allowed(ctx, mainModule); err != nil {
|
||||||
return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, Target.Path, err)
|
return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, mainModule.Path, err)
|
||||||
}
|
}
|
||||||
return []QueryResult{{
|
return []QueryResult{{
|
||||||
Mod: Target,
|
Mod: mainModule,
|
||||||
Rev: &modfetch.RevInfo{Version: Target.Version},
|
Rev: &modfetch.RevInfo{Version: mainModule.Version},
|
||||||
Packages: m.Pkgs,
|
Packages: m.Pkgs,
|
||||||
}}, nil, nil
|
}}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -604,15 +607,17 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchPattern(Target.Path) {
|
var matchesMainModule bool
|
||||||
queryMatchesMainModule = true
|
if matchPattern(mainModule.Path) {
|
||||||
|
mainModuleMatches = append(mainModuleMatches, mainModule)
|
||||||
|
matchesMainModule = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query == "upgrade" || query == "patch") && queryMatchesMainModule {
|
if (query == "upgrade" || query == "patch") && matchesMainModule {
|
||||||
if err := allowed(ctx, Target); err == nil {
|
if err := allowed(ctx, mainModule); err == nil {
|
||||||
modOnly = &QueryResult{
|
modOnly = &QueryResult{
|
||||||
Mod: Target,
|
Mod: mainModule,
|
||||||
Rev: &modfetch.RevInfo{Version: Target.Version},
|
Rev: &modfetch.RevInfo{Version: mainModule.Version},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -625,14 +630,17 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
if len(candidateModules) == 0 {
|
if len(candidateModules) == 0 {
|
||||||
if modOnly != nil {
|
if modOnly != nil {
|
||||||
return nil, modOnly, nil
|
return nil, modOnly, nil
|
||||||
} else if queryMatchesMainModule {
|
} else if len(mainModuleMatches) != 0 {
|
||||||
|
_ = TODOWorkspaces("add multiple main modules to the error?")
|
||||||
return nil, nil, &QueryMatchesMainModuleError{
|
return nil, nil, &QueryMatchesMainModuleError{
|
||||||
|
MainModule: mainModuleMatches[0],
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
Query: query,
|
Query: query,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
_ = TODOWorkspaces("This should maybe be PackageNotInModule*s* error with the main modules that are prefixes of base")
|
||||||
return nil, nil, &PackageNotInModuleError{
|
return nil, nil, &PackageNotInModuleError{
|
||||||
Mod: Target,
|
Mod: MainModules.Versions()[0],
|
||||||
Query: query,
|
Query: query,
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
}
|
}
|
||||||
|
|
@ -656,7 +664,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
m := match(r.Mod, root, isLocal)
|
m := match(r.Mod, []string{root}, isLocal)
|
||||||
r.Packages = m.Pkgs
|
r.Packages = m.Pkgs
|
||||||
if len(r.Packages) == 0 && !matchPattern(path) {
|
if len(r.Packages) == 0 && !matchPattern(path) {
|
||||||
if err := firstError(m); err != nil {
|
if err := firstError(m); err != nil {
|
||||||
|
|
@ -684,7 +692,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
if queryMatchesMainModule && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
|
if len(mainModuleMatches) > 0 && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
|
||||||
return nil, nil, &QueryMatchesMainModuleError{
|
return nil, nil, &QueryMatchesMainModuleError{
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
Query: query,
|
Query: query,
|
||||||
|
|
@ -701,8 +709,13 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
func modulePrefixesExcludingTarget(path string) []string {
|
func modulePrefixesExcludingTarget(path string) []string {
|
||||||
prefixes := make([]string, 0, strings.Count(path, "/")+1)
|
prefixes := make([]string, 0, strings.Count(path, "/")+1)
|
||||||
|
|
||||||
|
mainModulePrefixes := make(map[string]bool)
|
||||||
|
for _, m := range MainModules.Versions() {
|
||||||
|
mainModulePrefixes[m.Path] = true
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if path != targetPrefix {
|
if !mainModulePrefixes[path] {
|
||||||
if _, _, ok := module.SplitPathVersion(path); ok {
|
if _, _, ok := module.SplitPathVersion(path); ok {
|
||||||
prefixes = append(prefixes, path)
|
prefixes = append(prefixes, path)
|
||||||
}
|
}
|
||||||
|
|
@ -759,7 +772,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod
|
||||||
case *PackageNotInModuleError:
|
case *PackageNotInModuleError:
|
||||||
// Given the option, prefer to attribute “package not in module”
|
// Given the option, prefer to attribute “package not in module”
|
||||||
// to modules other than the main one.
|
// to modules other than the main one.
|
||||||
if noPackage == nil || noPackage.Mod == Target {
|
if noPackage == nil || MainModules.Contains(noPackage.Mod.Path) {
|
||||||
noPackage = rErr
|
noPackage = rErr
|
||||||
}
|
}
|
||||||
case *NoMatchingVersionError:
|
case *NoMatchingVersionError:
|
||||||
|
|
@ -885,11 +898,11 @@ type PackageNotInModuleError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PackageNotInModuleError) Error() string {
|
func (e *PackageNotInModuleError) Error() string {
|
||||||
if e.Mod == Target {
|
if MainModules.Contains(e.Mod.Path) {
|
||||||
if strings.Contains(e.Pattern, "...") {
|
if strings.Contains(e.Pattern, "...") {
|
||||||
return fmt.Sprintf("main module (%s) does not contain packages matching %s", Target.Path, e.Pattern)
|
return fmt.Sprintf("main module (%s) does not contain packages matching %s", e.Mod.Path, e.Pattern)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("main module (%s) does not contain package %s", Target.Path, e.Pattern)
|
return fmt.Sprintf("main module (%s) does not contain package %s", e.Mod.Path, e.Pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
found := ""
|
found := ""
|
||||||
|
|
@ -1094,16 +1107,34 @@ func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error)
|
||||||
// a version of the main module that cannot be satisfied.
|
// a version of the main module that cannot be satisfied.
|
||||||
// (The main module's version cannot be changed.)
|
// (The main module's version cannot be changed.)
|
||||||
type QueryMatchesMainModuleError struct {
|
type QueryMatchesMainModuleError struct {
|
||||||
|
MainModule module.Version
|
||||||
Pattern string
|
Pattern string
|
||||||
Query string
|
Query string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *QueryMatchesMainModuleError) Error() string {
|
func (e *QueryMatchesMainModuleError) Error() string {
|
||||||
if e.Pattern == Target.Path {
|
if MainModules.Contains(e.Pattern) {
|
||||||
return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern)
|
return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("can't request version %q of pattern %q that includes the main module (%s)", e.Query, e.Pattern, Target.Path)
|
return fmt.Sprintf("can't request version %q of pattern %q that includes the main module (%s)", e.Query, e.Pattern, e.MainModule.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A QueryUpgradesAllError indicates that a query requests
|
||||||
|
// an upgrade on the all pattern.
|
||||||
|
// (The main module's version cannot be changed.)
|
||||||
|
type QueryUpgradesAllError struct {
|
||||||
|
MainModules []module.Version
|
||||||
|
Query string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *QueryUpgradesAllError) Error() string {
|
||||||
|
var plural string = ""
|
||||||
|
if len(e.MainModules) != 1 {
|
||||||
|
plural = "s"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("can't request version %q of pattern \"all\" that includes the main module%s", e.Query, plural)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A QueryMatchesPackagesInMainModuleError indicates that a query cannot be
|
// A QueryMatchesPackagesInMainModuleError indicates that a query cannot be
|
||||||
|
|
|
||||||
|
|
@ -131,9 +131,10 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
if HasModRoot() {
|
mod := MainModules.mustGetSingleMainModule()
|
||||||
walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
|
if modRoot := MainModules.ModRoot(mod); modRoot != "" {
|
||||||
walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
|
walkPkgs(modRoot, MainModules.PathPrefix(mod), pruneGoMod|pruneVendor)
|
||||||
|
walkPkgs(filepath.Join(modRoot, "vendor"), "", pruneVendor)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -147,12 +148,12 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
|
||||||
root, modPrefix string
|
root, modPrefix string
|
||||||
isLocal bool
|
isLocal bool
|
||||||
)
|
)
|
||||||
if mod == Target {
|
if MainModules.Contains(mod.Path) {
|
||||||
if !HasModRoot() {
|
if MainModules.ModRoot(mod) == "" {
|
||||||
continue // If there is no main module, we can't search in it.
|
continue // If there is no main module, we can't search in it.
|
||||||
}
|
}
|
||||||
root = ModRoot()
|
root = MainModules.ModRoot(mod)
|
||||||
modPrefix = targetPrefix
|
modPrefix = MainModules.PathPrefix(mod)
|
||||||
isLocal = true
|
isLocal = true
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,7 @@ func checkVendorConsistency() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if vendErrors.Len() > 0 {
|
if vendErrors.Len() > 0 {
|
||||||
|
modRoot := MainModules.ModRoot(MainModules.mustGetSingleMainModule())
|
||||||
base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors)
|
base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ package mvs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
@ -85,11 +86,11 @@ type DowngradeReqs interface {
|
||||||
// of the list are sorted by path.
|
// of the list are sorted by path.
|
||||||
//
|
//
|
||||||
// See https://research.swtch.com/vgo-mvs for details.
|
// See https://research.swtch.com/vgo-mvs for details.
|
||||||
func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
|
func BuildList(targets []module.Version, reqs Reqs) ([]module.Version, error) {
|
||||||
return buildList(target, reqs, nil)
|
return buildList(targets, reqs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
|
func buildList(targets []module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
|
||||||
cmp := func(v1, v2 string) int {
|
cmp := func(v1, v2 string) int {
|
||||||
if reqs.Max(v1, v2) != v1 {
|
if reqs.Max(v1, v2) != v1 {
|
||||||
return -1
|
return -1
|
||||||
|
|
@ -102,7 +103,7 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
g = NewGraph(cmp, []module.Version{target})
|
g = NewGraph(cmp, targets)
|
||||||
upgrades = map[module.Version]module.Version{}
|
upgrades = map[module.Version]module.Version{}
|
||||||
errs = map[module.Version]error{} // (non-nil errors only)
|
errs = map[module.Version]error{} // (non-nil errors only)
|
||||||
)
|
)
|
||||||
|
|
@ -110,7 +111,9 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
// Explore work graph in parallel in case reqs.Required
|
// Explore work graph in parallel in case reqs.Required
|
||||||
// does high-latency network operations.
|
// does high-latency network operations.
|
||||||
var work par.Work
|
var work par.Work
|
||||||
|
for _, target := range targets {
|
||||||
work.Add(target)
|
work.Add(target)
|
||||||
|
}
|
||||||
work.Do(10, func(item interface{}) {
|
work.Do(10, func(item interface{}) {
|
||||||
m := item.(module.Version)
|
m := item.(module.Version)
|
||||||
|
|
||||||
|
|
@ -168,12 +171,12 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
|
|
||||||
// The final list is the minimum version of each module found in the graph.
|
// The final list is the minimum version of each module found in the graph.
|
||||||
list := g.BuildList()
|
list := g.BuildList()
|
||||||
if v := list[0]; v != target {
|
if vs := list[:len(targets)]; !reflect.DeepEqual(vs, targets) {
|
||||||
// target.Version will be "" for modload, the main client of MVS.
|
// target.Version will be "" for modload, the main client of MVS.
|
||||||
// "" denotes the main module, which has no version. However, MVS treats
|
// "" denotes the main module, which has no version. However, MVS treats
|
||||||
// version strings as opaque, so "" is not a special value here.
|
// version strings as opaque, so "" is not a special value here.
|
||||||
// See golang.org/issue/31491, golang.org/issue/29773.
|
// See golang.org/issue/31491, golang.org/issue/29773.
|
||||||
panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target))
|
panic(fmt.Sprintf("mistake: chose versions %+v instead of targets %+v", vs, targets))
|
||||||
}
|
}
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
@ -181,8 +184,8 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
// Req returns the minimal requirement list for the target module,
|
// Req returns the minimal requirement list for the target module,
|
||||||
// with the constraint that all module paths listed in base must
|
// with the constraint that all module paths listed in base must
|
||||||
// appear in the returned list.
|
// appear in the returned list.
|
||||||
func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, error) {
|
func Req(mainModule module.Version, base []string, reqs Reqs) ([]module.Version, error) {
|
||||||
list, err := BuildList(target, reqs)
|
list, err := BuildList([]module.Version{mainModule}, reqs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +197,8 @@ func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, err
|
||||||
// Compute postorder, cache requirements.
|
// Compute postorder, cache requirements.
|
||||||
var postorder []module.Version
|
var postorder []module.Version
|
||||||
reqCache := map[module.Version][]module.Version{}
|
reqCache := map[module.Version][]module.Version{}
|
||||||
reqCache[target] = nil
|
reqCache[mainModule] = nil
|
||||||
|
|
||||||
var walk func(module.Version) error
|
var walk func(module.Version) error
|
||||||
walk = func(m module.Version) error {
|
walk = func(m module.Version) error {
|
||||||
_, ok := reqCache[m]
|
_, ok := reqCache[m]
|
||||||
|
|
@ -273,7 +277,7 @@ func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, err
|
||||||
// UpgradeAll returns a build list for the target module
|
// UpgradeAll returns a build list for the target module
|
||||||
// in which every module is upgraded to its latest version.
|
// in which every module is upgraded to its latest version.
|
||||||
func UpgradeAll(target module.Version, reqs UpgradeReqs) ([]module.Version, error) {
|
func UpgradeAll(target module.Version, reqs UpgradeReqs) ([]module.Version, error) {
|
||||||
return buildList(target, reqs, func(m module.Version) (module.Version, error) {
|
return buildList([]module.Version{target}, reqs, func(m module.Version) (module.Version, error) {
|
||||||
if m.Path == target.Path {
|
if m.Path == target.Path {
|
||||||
return target, nil
|
return target, nil
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +312,7 @@ func Upgrade(target module.Version, reqs UpgradeReqs, upgrade ...module.Version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildList(target, &override{target, list, reqs}, func(m module.Version) (module.Version, error) {
|
return buildList([]module.Version{target}, &override{target, list, reqs}, func(m module.Version) (module.Version, error) {
|
||||||
if v, ok := upgradeTo[m.Path]; ok {
|
if v, ok := upgradeTo[m.Path]; ok {
|
||||||
return module.Version{Path: m.Path, Version: v}, nil
|
return module.Version{Path: m.Path, Version: v}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -331,7 +335,7 @@ func Downgrade(target module.Version, reqs DowngradeReqs, downgrade ...module.Ve
|
||||||
//
|
//
|
||||||
// In order to generate those new requirements, we need to identify versions
|
// In order to generate those new requirements, we need to identify versions
|
||||||
// for every module in the build list — not just reqs.Required(target).
|
// for every module in the build list — not just reqs.Required(target).
|
||||||
list, err := BuildList(target, reqs)
|
list, err := BuildList([]module.Version{target}, reqs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -446,7 +450,7 @@ List:
|
||||||
// list with the actual versions of the downgraded modules as selected by MVS,
|
// list with the actual versions of the downgraded modules as selected by MVS,
|
||||||
// instead of our initial downgrades.
|
// instead of our initial downgrades.
|
||||||
// (See the downhiddenartifact and downhiddencross test cases).
|
// (See the downhiddenartifact and downhiddencross test cases).
|
||||||
actual, err := BuildList(target, &override{
|
actual, err := BuildList([]module.Version{target}, &override{
|
||||||
target: target,
|
target: target,
|
||||||
list: downgraded,
|
list: downgraded,
|
||||||
Reqs: reqs,
|
Reqs: reqs,
|
||||||
|
|
@ -466,7 +470,7 @@ List:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BuildList(target, &override{
|
return BuildList([]module.Version{target}, &override{
|
||||||
target: target,
|
target: target,
|
||||||
list: downgraded,
|
list: downgraded,
|
||||||
Reqs: reqs,
|
Reqs: reqs,
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,7 @@ func Test(t *testing.T) {
|
||||||
t.Fatalf("build takes one argument: %q", line)
|
t.Fatalf("build takes one argument: %q", line)
|
||||||
}
|
}
|
||||||
fns = append(fns, func(t *testing.T) {
|
fns = append(fns, func(t *testing.T) {
|
||||||
list, err := BuildList(m(kf[1]), reqs)
|
list, err := BuildList([]module.Version{m(kf[1])}, reqs)
|
||||||
checkList(t, key, list, err, val)
|
checkList(t, key, list, err, val)
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -202,12 +202,6 @@ func (m *Match) MatchPackages() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var modRoot string
|
|
||||||
|
|
||||||
func SetModRoot(dir string) {
|
|
||||||
modRoot = dir
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchDirs sets m.Dirs to a non-nil slice containing all directories that
|
// MatchDirs sets m.Dirs to a non-nil slice containing all directories that
|
||||||
// potentially match a local pattern. The pattern must begin with an absolute
|
// potentially match a local pattern. The pattern must begin with an absolute
|
||||||
// path, or "./", or "../". On Windows, the pattern may use slash or backslash
|
// path, or "./", or "../". On Windows, the pattern may use slash or backslash
|
||||||
|
|
@ -215,7 +209,7 @@ func SetModRoot(dir string) {
|
||||||
//
|
//
|
||||||
// If any errors may have caused the set of directories to be incomplete,
|
// If any errors may have caused the set of directories to be incomplete,
|
||||||
// MatchDirs appends those errors to m.Errs.
|
// MatchDirs appends those errors to m.Errs.
|
||||||
func (m *Match) MatchDirs() {
|
func (m *Match) MatchDirs(modRoots []string) {
|
||||||
m.Dirs = []string{}
|
m.Dirs = []string{}
|
||||||
if !m.IsLocal() {
|
if !m.IsLocal() {
|
||||||
m.AddError(fmt.Errorf("internal error: MatchDirs: %s is not a valid filesystem pattern", m.pattern))
|
m.AddError(fmt.Errorf("internal error: MatchDirs: %s is not a valid filesystem pattern", m.pattern))
|
||||||
|
|
@ -253,15 +247,24 @@ func (m *Match) MatchDirs() {
|
||||||
// We need to preserve the ./ for pattern matching
|
// We need to preserve the ./ for pattern matching
|
||||||
// and in the returned import paths.
|
// and in the returned import paths.
|
||||||
|
|
||||||
if modRoot != "" {
|
if len(modRoots) > 1 {
|
||||||
abs, err := filepath.Abs(dir)
|
abs, err := filepath.Abs(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.AddError(err)
|
m.AddError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !hasFilepathPrefix(abs, modRoot) {
|
var found bool
|
||||||
m.AddError(fmt.Errorf("directory %s is outside module root (%s)", abs, modRoot))
|
for _, modRoot := range modRoots {
|
||||||
return
|
if modRoot != "" && hasFilepathPrefix(abs, modRoot) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
plural := ""
|
||||||
|
if len(modRoots) > 1 {
|
||||||
|
plural = "s"
|
||||||
|
}
|
||||||
|
m.AddError(fmt.Errorf("directory %s is outside module root%s (%s)", abs, plural, strings.Join(modRoots, ", ")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,19 +427,19 @@ func WarnUnmatched(matches []*Match) {
|
||||||
|
|
||||||
// ImportPaths returns the matching paths to use for the given command line.
|
// ImportPaths returns the matching paths to use for the given command line.
|
||||||
// It calls ImportPathsQuiet and then WarnUnmatched.
|
// It calls ImportPathsQuiet and then WarnUnmatched.
|
||||||
func ImportPaths(patterns []string) []*Match {
|
func ImportPaths(patterns, modRoots []string) []*Match {
|
||||||
matches := ImportPathsQuiet(patterns)
|
matches := ImportPathsQuiet(patterns, modRoots)
|
||||||
WarnUnmatched(matches)
|
WarnUnmatched(matches)
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches.
|
// ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches.
|
||||||
func ImportPathsQuiet(patterns []string) []*Match {
|
func ImportPathsQuiet(patterns, modRoots []string) []*Match {
|
||||||
var out []*Match
|
var out []*Match
|
||||||
for _, a := range CleanPatterns(patterns) {
|
for _, a := range CleanPatterns(patterns) {
|
||||||
m := NewMatch(a)
|
m := NewMatch(a)
|
||||||
if m.IsLocal() {
|
if m.IsLocal() {
|
||||||
m.MatchDirs()
|
m.MatchDirs(modRoots)
|
||||||
|
|
||||||
// Change the file import path to a regular import path if the package
|
// Change the file import path to a regular import path if the package
|
||||||
// is in GOPATH or GOROOT. We don't report errors here; LoadImport
|
// is in GOPATH or GOROOT. We don't report errors here; LoadImport
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue