@@ -62,8 +62,7 @@ import (
62
62
type ModuleResolver struct {
63
63
env * ProcessEnv
64
64
65
- // Module state, populated by init
66
- initialized bool
65
+ // Module state, populated during construction
67
66
dummyVendorMod * gocommand.ModuleJSON // if vendoring is enabled, a pseudo-module to represent the /vendor directory
68
67
moduleCacheDir string // GOMODCACHE, inferred from GOPATH if unset
69
68
roots []gopathwalk.Root // roots to scan, in approximate order of importance
@@ -87,24 +86,18 @@ type ModuleResolver struct {
87
86
otherCache * dirInfoCache
88
87
}
89
88
90
- func newModuleResolver (e * ProcessEnv ) * ModuleResolver {
89
+ func newModuleResolver (e * ProcessEnv ) ( * ModuleResolver , error ) {
91
90
r := & ModuleResolver {
92
91
env : e ,
93
92
scanSema : make (chan struct {}, 1 ),
94
93
}
95
94
r .scanSema <- struct {}{}
96
- return r
97
- }
98
-
99
- func (r * ModuleResolver ) init () error {
100
- if r .initialized {
101
- return nil
102
- }
103
95
104
96
goenv , err := r .env .goEnv ()
105
97
if err != nil {
106
- return err
98
+ return nil , err
107
99
}
100
+
108
101
// TODO(rfindley): can we refactor to share logic with r.env.invokeGo?
109
102
inv := gocommand.Invocation {
110
103
BuildFlags : r .env .BuildFlags ,
@@ -125,7 +118,7 @@ func (r *ModuleResolver) init() error {
125
118
// invocation?
126
119
vendorEnabled , mainModVendor , err = gocommand .VendorEnabled (context .TODO (), inv , r .env .GocmdRunner )
127
120
if err != nil {
128
- return err
121
+ return nil , err
129
122
}
130
123
}
131
124
@@ -146,19 +139,14 @@ func (r *ModuleResolver) init() error {
146
139
// GO111MODULE=on. Other errors are fatal.
147
140
if err != nil {
148
141
if errMsg := err .Error (); ! strings .Contains (errMsg , "working directory is not part of a module" ) && ! strings .Contains (errMsg , "go.mod file not found" ) {
149
- return err
142
+ return nil , err
150
143
}
151
144
}
152
145
}
153
146
154
- if gmc := r .env .Env ["GOMODCACHE" ]; gmc != "" {
155
- r .moduleCacheDir = gmc
156
- } else {
157
- gopaths := filepath .SplitList (goenv ["GOPATH" ])
158
- if len (gopaths ) == 0 {
159
- return fmt .Errorf ("empty GOPATH" )
160
- }
161
- r .moduleCacheDir = filepath .Join (gopaths [0 ], "/pkg/mod" )
147
+ r .moduleCacheDir = gomodcacheForEnv (goenv )
148
+ if r .moduleCacheDir == "" {
149
+ return nil , fmt .Errorf ("cannot resolve GOMODCACHE" )
162
150
}
163
151
164
152
sort .Slice (r .modsByModPath , func (i , j int ) bool {
@@ -212,20 +200,32 @@ func (r *ModuleResolver) init() error {
212
200
}
213
201
214
202
r .scannedRoots = map [gopathwalk.Root ]bool {}
215
- if r .moduleCacheCache == nil {
216
- r .moduleCacheCache = & dirInfoCache {
217
- dirs : map [string ]* directoryPackageInfo {},
218
- listeners : map [* int ]cacheListener {},
219
- }
203
+ r .moduleCacheCache = & dirInfoCache {
204
+ dirs : map [string ]* directoryPackageInfo {},
205
+ listeners : map [* int ]cacheListener {},
220
206
}
221
- if r .otherCache == nil {
222
- r .otherCache = & dirInfoCache {
223
- dirs : map [string ]* directoryPackageInfo {},
224
- listeners : map [* int ]cacheListener {},
225
- }
207
+ r .otherCache = & dirInfoCache {
208
+ dirs : map [string ]* directoryPackageInfo {},
209
+ listeners : map [* int ]cacheListener {},
226
210
}
227
- r .initialized = true
228
- return nil
211
+ return r , nil
212
+ }
213
+
214
+ // gomodcacheForEnv returns the GOMODCACHE value to use based on the given env
215
+ // map, which must have GOMODCACHE and GOPATH populated.
216
+ //
217
+ // TODO(rfindley): this is defensive refactoring.
218
+ // 1. Is this even relevant anymore? Can't we just read GOMODCACHE.
219
+ // 2. Use this to separate module cache scanning from other scanning.
220
+ func gomodcacheForEnv (goenv map [string ]string ) string {
221
+ if gmc := goenv ["GOMODCACHE" ]; gmc != "" {
222
+ return gmc
223
+ }
224
+ gopaths := filepath .SplitList (goenv ["GOPATH" ])
225
+ if len (gopaths ) == 0 {
226
+ return ""
227
+ }
228
+ return filepath .Join (gopaths [0 ], "/pkg/mod" )
229
229
}
230
230
231
231
func (r * ModuleResolver ) initAllMods () error {
@@ -271,21 +271,27 @@ func (r *ModuleResolver) ClearForNewScan() {
271
271
r .scanSema <- struct {}{}
272
272
}
273
273
274
- // ClearForNewMod invalidates resolver state that depends on the go.mod file
275
- // (essentially, the output of go list -m -json ...).
274
+ // ClearModuleInfo invalidates resolver state that depends on go.mod file
275
+ // contents (essentially, the output of go list -m -json ...).
276
276
//
277
277
// Notably, it does not forget directory contents, which are reset
278
278
// asynchronously via ClearForNewScan.
279
- func (r * ModuleResolver ) ClearForNewMod () {
280
- <- r .scanSema
281
- * r = ModuleResolver {
282
- env : r .env ,
283
- moduleCacheCache : r .moduleCacheCache ,
284
- otherCache : r .otherCache ,
285
- scanSema : r .scanSema ,
279
+ //
280
+ // If the ProcessEnv is a GOPATH environment, ClearModuleInfo is a no op.
281
+ //
282
+ // TODO(rfindley): move this to a new env.go, consolidating ProcessEnv methods.
283
+ func (e * ProcessEnv ) ClearModuleInfo () {
284
+ if r , ok := e .resolver .(* ModuleResolver ); ok {
285
+ resolver , resolverErr := newModuleResolver (e )
286
+ if resolverErr == nil {
287
+ <- r .scanSema // guards caches
288
+ resolver .moduleCacheCache = r .moduleCacheCache
289
+ resolver .otherCache = r .otherCache
290
+ r .scanSema <- struct {}{}
291
+ }
292
+ e .resolver = resolver
293
+ e .resolverErr = resolverErr
286
294
}
287
- r .init ()
288
- r .scanSema <- struct {}{}
289
295
}
290
296
291
297
// findPackage returns the module and directory that contains the package at
@@ -355,10 +361,6 @@ func (r *ModuleResolver) cacheStore(info directoryPackageInfo) {
355
361
}
356
362
}
357
363
358
- func (r * ModuleResolver ) cacheKeys () []string {
359
- return append (r .moduleCacheCache .Keys (), r .otherCache .Keys ()... )
360
- }
361
-
362
364
// cachePackageName caches the package name for a dir already in the cache.
363
365
func (r * ModuleResolver ) cachePackageName (info directoryPackageInfo ) (string , error ) {
364
366
if info .rootType == gopathwalk .RootModuleCache {
@@ -469,9 +471,6 @@ func (r *ModuleResolver) dirInModuleCache(dir string) bool {
469
471
}
470
472
471
473
func (r * ModuleResolver ) loadPackageNames (importPaths []string , srcDir string ) (map [string ]string , error ) {
472
- if err := r .init (); err != nil {
473
- return nil , err
474
- }
475
474
names := map [string ]string {}
476
475
for _ , path := range importPaths {
477
476
_ , packageDir := r .findPackage (path )
@@ -491,10 +490,6 @@ func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error
491
490
ctx , done := event .Start (ctx , "imports.ModuleResolver.scan" )
492
491
defer done ()
493
492
494
- if err := r .init (); err != nil {
495
- return err
496
- }
497
-
498
493
processDir := func (info directoryPackageInfo ) {
499
494
// Skip this directory if we were not able to get the package information successfully.
500
495
if scanned , err := info .reachedStatus (directoryScanned ); ! scanned || err != nil {
@@ -672,9 +667,6 @@ func (r *ModuleResolver) canonicalize(info directoryPackageInfo) (*pkg, error) {
672
667
}
673
668
674
669
func (r * ModuleResolver ) loadExports (ctx context.Context , pkg * pkg , includeTest bool ) (string , []string , error ) {
675
- if err := r .init (); err != nil {
676
- return "" , nil , err
677
- }
678
670
if info , ok := r .cacheLoad (pkg .dir ); ok && ! includeTest {
679
671
return r .cacheExports (ctx , r .env , info )
680
672
}
0 commit comments