Skip to content

Commit 857b4dd

Browse files
committed
internal/imports: avoid walking dir for mod file in mod cache
The root of the module containing a package in the module cache can be determined by looking at the directory path. Use this instead of scanning up the file tree to find the mod file of a package from a module cache. The go command prunes nested modules before populating the module cache, so there is only one go.mod within each module. Change-Id: I434a04350ef3ca2f44b7ffd08ccc5afe4209654f Reviewed-on: https://go-review.googlesource.com/c/tools/+/190906 Run-TryBot: Suzy Mueller <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
1 parent c940306 commit 857b4dd

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

internal/imports/mod.go

+28-17
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import (
2323
// ModuleResolver implements resolver for modules using the go command as little
2424
// as feasible.
2525
type ModuleResolver struct {
26-
env *ProcessEnv
26+
env *ProcessEnv
27+
moduleCacheDir string
2728

2829
Initialized bool
2930
Main *ModuleJSON
@@ -116,7 +117,7 @@ func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) {
116117
}
117118
pathInModule := importPath[len(m.Path):]
118119
pkgDir := filepath.Join(m.Dir, pathInModule)
119-
if dirIsNestedModule(pkgDir, m) {
120+
if r.dirIsNestedModule(pkgDir, m) {
120121
continue
121122
}
122123

@@ -155,7 +156,7 @@ func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON {
155156
continue
156157
}
157158

158-
if dirIsNestedModule(dir, m) {
159+
if r.dirIsNestedModule(dir, m) {
159160
continue
160161
}
161162

@@ -166,18 +167,28 @@ func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON {
166167

167168
// dirIsNestedModule reports if dir is contained in a nested module underneath
168169
// mod, not actually in mod.
169-
func dirIsNestedModule(dir string, mod *ModuleJSON) bool {
170+
func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool {
170171
if !strings.HasPrefix(dir, mod.Dir) {
171172
return false
172173
}
173-
mf := findModFile(dir)
174+
if r.dirInModuleCache(dir) {
175+
// Nested modules in the module cache are pruned,
176+
// so it cannot be a nested module.
177+
return false
178+
}
179+
mf := r.findModFile(dir)
174180
if mf == "" {
175181
return false
176182
}
177183
return filepath.Dir(mf) != mod.Dir
178184
}
179185

180-
func findModFile(dir string) string {
186+
func (r *ModuleResolver) findModFile(dir string) string {
187+
if r.dirInModuleCache(dir) {
188+
matches := modCacheRegexp.FindStringSubmatch(dir)
189+
index := strings.Index(dir, matches[1]+"@"+matches[2])
190+
return filepath.Join(dir[:index], matches[1]+"@"+matches[2], "go.mod")
191+
}
181192
for {
182193
f := filepath.Join(dir, "go.mod")
183194
info, err := os.Stat(f)
@@ -192,6 +203,13 @@ func findModFile(dir string) string {
192203
}
193204
}
194205

206+
func (r *ModuleResolver) dirInModuleCache(dir string) bool {
207+
if r.moduleCacheDir == "" {
208+
return false
209+
}
210+
return strings.HasPrefix(dir, r.moduleCacheDir)
211+
}
212+
195213
func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
196214
if err := r.init(); err != nil {
197215
return nil, err
@@ -223,9 +241,10 @@ func (r *ModuleResolver) scan(_ references) ([]*pkg, error) {
223241
if r.Main != nil {
224242
roots = append(roots, gopathwalk.Root{r.Main.Dir, gopathwalk.RootCurrentModule})
225243
}
226-
for _, p := range filepath.SplitList(r.env.GOPATH) {
227-
roots = append(roots, gopathwalk.Root{filepath.Join(p, "/pkg/mod"), gopathwalk.RootModuleCache})
244+
if r.moduleCacheDir == "" {
245+
r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod")
228246
}
247+
roots = append(roots, gopathwalk.Root{r.moduleCacheDir, gopathwalk.RootModuleCache})
229248

230249
// Walk replace targets, just in case they're not in any of the above.
231250
for _, mod := range r.ModsByModPath {
@@ -359,15 +378,7 @@ func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) (di
359378
}
360379

361380
// Check that this package is not obviously impossible to import.
362-
var modFile string
363-
switch root.Type {
364-
case gopathwalk.RootModuleCache:
365-
matches := modCacheRegexp.FindStringSubmatch(subdir)
366-
index := strings.Index(dir, matches[1]+"@"+matches[2])
367-
modFile = filepath.Join(dir[:index], matches[1]+"@"+matches[2], "go.mod")
368-
default:
369-
modFile = findModFile(dir)
370-
}
381+
modFile := r.findModFile(dir)
371382

372383
var needsReplace bool
373384
modBytes, err := ioutil.ReadFile(modFile)

internal/imports/mod_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -712,3 +712,24 @@ func writeProxyModule(base, arPath string) error {
712712
}
713713
return nil
714714
}
715+
716+
// Tests that findModFile can find the mod files from a path in the module cache.
717+
func TestFindModFileModCache(t *testing.T) {
718+
mt := setup(t, `
719+
-- go.mod --
720+
module x
721+
722+
require rsc.io/quote v1.5.2
723+
-- x.go --
724+
package x
725+
import _ "rsc.io/quote"
726+
`, "")
727+
defer mt.cleanup()
728+
want := filepath.Join(mt.resolver.env.GOPATH, "pkg/mod", "rsc.io/[email protected]", "go.mod")
729+
730+
found := mt.assertScanFinds("rsc.io/quote", "quote")
731+
modFile := mt.resolver.findModFile(found.dir)
732+
if modFile != want {
733+
t.Errorf("expected: %s, got: %s", want, modFile)
734+
}
735+
}

0 commit comments

Comments
 (0)