mirror of
https://github.com/golang/go
synced 2024-11-18 20:04:52 -07:00
internal/lsp/cache: let gopls track go.mod files
We used to read the go.mod file information out of the imports.Resolver. Now that gopls tracks go.mod itself, we can use that instead. This is a slight regression, in that go.mods in replace targets will no longer be watched, but I don't think that's too important. This allows us to stop reading the ModuleResolver's internals, which were not sufficiently locked. Updates golang/go#36605. Change-Id: I42939e0248cba1f6b3850a003de67fcc11ab10b1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/215319 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
633b092c1e
commit
354bea8ca8
@ -29,10 +29,10 @@ type ModuleResolver struct {
|
|||||||
scanSema chan struct{} // scanSema prevents concurrent scans and guards scannedRoots.
|
scanSema chan struct{} // scanSema prevents concurrent scans and guards scannedRoots.
|
||||||
scannedRoots map[gopathwalk.Root]bool
|
scannedRoots map[gopathwalk.Root]bool
|
||||||
|
|
||||||
Initialized bool
|
initialized bool
|
||||||
Main *ModuleJSON
|
main *ModuleJSON
|
||||||
ModsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path...
|
modsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path...
|
||||||
ModsByDir []*ModuleJSON // ...or Dir.
|
modsByDir []*ModuleJSON // ...or Dir.
|
||||||
|
|
||||||
// moduleCacheCache stores information about the module cache.
|
// moduleCacheCache stores information about the module cache.
|
||||||
moduleCacheCache *dirInfoCache
|
moduleCacheCache *dirInfoCache
|
||||||
@ -59,7 +59,7 @@ func newModuleResolver(e *ProcessEnv) *ModuleResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *ModuleResolver) init() error {
|
func (r *ModuleResolver) init() error {
|
||||||
if r.Initialized {
|
if r.initialized {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
mainMod, vendorEnabled, err := vendorEnabled(r.env)
|
mainMod, vendorEnabled, err := vendorEnabled(r.env)
|
||||||
@ -70,13 +70,13 @@ func (r *ModuleResolver) init() error {
|
|||||||
if mainMod != nil && vendorEnabled {
|
if mainMod != nil && vendorEnabled {
|
||||||
// Vendor mode is on, so all the non-Main modules are irrelevant,
|
// Vendor mode is on, so all the non-Main modules are irrelevant,
|
||||||
// and we need to search /vendor for everything.
|
// and we need to search /vendor for everything.
|
||||||
r.Main = mainMod
|
r.main = mainMod
|
||||||
r.dummyVendorMod = &ModuleJSON{
|
r.dummyVendorMod = &ModuleJSON{
|
||||||
Path: "",
|
Path: "",
|
||||||
Dir: filepath.Join(mainMod.Dir, "vendor"),
|
Dir: filepath.Join(mainMod.Dir, "vendor"),
|
||||||
}
|
}
|
||||||
r.ModsByModPath = []*ModuleJSON{mainMod, r.dummyVendorMod}
|
r.modsByModPath = []*ModuleJSON{mainMod, r.dummyVendorMod}
|
||||||
r.ModsByDir = []*ModuleJSON{mainMod, r.dummyVendorMod}
|
r.modsByDir = []*ModuleJSON{mainMod, r.dummyVendorMod}
|
||||||
} else {
|
} else {
|
||||||
// Vendor mode is off, so run go list -m ... to find everything.
|
// Vendor mode is off, so run go list -m ... to find everything.
|
||||||
r.initAllMods()
|
r.initAllMods()
|
||||||
@ -84,15 +84,15 @@ func (r *ModuleResolver) init() error {
|
|||||||
|
|
||||||
r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod")
|
r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod")
|
||||||
|
|
||||||
sort.Slice(r.ModsByModPath, func(i, j int) bool {
|
sort.Slice(r.modsByModPath, func(i, j int) bool {
|
||||||
count := func(x int) int {
|
count := func(x int) int {
|
||||||
return strings.Count(r.ModsByModPath[x].Path, "/")
|
return strings.Count(r.modsByModPath[x].Path, "/")
|
||||||
}
|
}
|
||||||
return count(j) < count(i) // descending order
|
return count(j) < count(i) // descending order
|
||||||
})
|
})
|
||||||
sort.Slice(r.ModsByDir, func(i, j int) bool {
|
sort.Slice(r.modsByDir, func(i, j int) bool {
|
||||||
count := func(x int) int {
|
count := func(x int) int {
|
||||||
return strings.Count(r.ModsByDir[x].Dir, "/")
|
return strings.Count(r.modsByDir[x].Dir, "/")
|
||||||
}
|
}
|
||||||
return count(j) < count(i) // descending order
|
return count(j) < count(i) // descending order
|
||||||
})
|
})
|
||||||
@ -100,8 +100,8 @@ func (r *ModuleResolver) init() error {
|
|||||||
r.roots = []gopathwalk.Root{
|
r.roots = []gopathwalk.Root{
|
||||||
{filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT},
|
{filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT},
|
||||||
}
|
}
|
||||||
if r.Main != nil {
|
if r.main != nil {
|
||||||
r.roots = append(r.roots, gopathwalk.Root{r.Main.Dir, gopathwalk.RootCurrentModule})
|
r.roots = append(r.roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule})
|
||||||
}
|
}
|
||||||
if vendorEnabled {
|
if vendorEnabled {
|
||||||
r.roots = append(r.roots, gopathwalk.Root{r.dummyVendorMod.Dir, gopathwalk.RootOther})
|
r.roots = append(r.roots, gopathwalk.Root{r.dummyVendorMod.Dir, gopathwalk.RootOther})
|
||||||
@ -115,12 +115,12 @@ func (r *ModuleResolver) init() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Walk dependent modules before scanning the full mod cache, direct deps first.
|
// Walk dependent modules before scanning the full mod cache, direct deps first.
|
||||||
for _, mod := range r.ModsByModPath {
|
for _, mod := range r.modsByModPath {
|
||||||
if !mod.Indirect && !mod.Main {
|
if !mod.Indirect && !mod.Main {
|
||||||
addDep(mod)
|
addDep(mod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, mod := range r.ModsByModPath {
|
for _, mod := range r.modsByModPath {
|
||||||
if mod.Indirect && !mod.Main {
|
if mod.Indirect && !mod.Main {
|
||||||
addDep(mod)
|
addDep(mod)
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ func (r *ModuleResolver) init() error {
|
|||||||
listeners: map[*int]cacheListener{},
|
listeners: map[*int]cacheListener{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.Initialized = true
|
r.initialized = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,10 +162,10 @@ func (r *ModuleResolver) initAllMods() error {
|
|||||||
// Can't do anything with a module that's not downloaded.
|
// Can't do anything with a module that's not downloaded.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r.ModsByModPath = append(r.ModsByModPath, mod)
|
r.modsByModPath = append(r.modsByModPath, mod)
|
||||||
r.ModsByDir = append(r.ModsByDir, mod)
|
r.modsByDir = append(r.modsByDir, mod)
|
||||||
if mod.Main {
|
if mod.Main {
|
||||||
r.Main = mod
|
r.main = mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -198,7 +198,7 @@ func (r *ModuleResolver) ClearForNewMod() {
|
|||||||
func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) {
|
func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) {
|
||||||
// This can't find packages in the stdlib, but that's harmless for all
|
// This can't find packages in the stdlib, but that's harmless for all
|
||||||
// the existing code paths.
|
// the existing code paths.
|
||||||
for _, m := range r.ModsByModPath {
|
for _, m := range r.modsByModPath {
|
||||||
if !strings.HasPrefix(importPath, m.Path) {
|
if !strings.HasPrefix(importPath, m.Path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -292,7 +292,7 @@ func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON {
|
|||||||
// - in /vendor/ in -mod=vendor mode.
|
// - in /vendor/ in -mod=vendor mode.
|
||||||
// - nested module? Dunno.
|
// - nested module? Dunno.
|
||||||
// Rumor has it that replace targets cannot contain other replace targets.
|
// Rumor has it that replace targets cannot contain other replace targets.
|
||||||
for _, m := range r.ModsByDir {
|
for _, m := range r.modsByDir {
|
||||||
if !strings.HasPrefix(dir, m.Dir) {
|
if !strings.HasPrefix(dir, m.Dir) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -570,7 +570,7 @@ func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) dir
|
|||||||
}
|
}
|
||||||
switch root.Type {
|
switch root.Type {
|
||||||
case gopathwalk.RootCurrentModule:
|
case gopathwalk.RootCurrentModule:
|
||||||
importPath = path.Join(r.Main.Path, filepath.ToSlash(subdir))
|
importPath = path.Join(r.main.Path, filepath.ToSlash(subdir))
|
||||||
case gopathwalk.RootModuleCache:
|
case gopathwalk.RootModuleCache:
|
||||||
matches := modCacheRegexp.FindStringSubmatch(subdir)
|
matches := modCacheRegexp.FindStringSubmatch(subdir)
|
||||||
if len(matches) == 0 {
|
if len(matches) == 0 {
|
||||||
|
48
internal/lsp/cache/view.go
vendored
48
internal/lsp/cache/view.go
vendored
@ -69,11 +69,7 @@ type view struct {
|
|||||||
processEnv *imports.ProcessEnv
|
processEnv *imports.ProcessEnv
|
||||||
cacheRefreshDuration time.Duration
|
cacheRefreshDuration time.Duration
|
||||||
cacheRefreshTimer *time.Timer
|
cacheRefreshTimer *time.Timer
|
||||||
|
cachedModFileVersion source.FileIdentity
|
||||||
// modFileVersions stores the last seen versions of the module files that are used
|
|
||||||
// by processEnvs resolver.
|
|
||||||
// TODO(suzmue): These versions may not actually be on disk.
|
|
||||||
modFileVersions map[string]string
|
|
||||||
|
|
||||||
// keep track of files by uri and by basename, a single file may be mapped
|
// keep track of files by uri and by basename, a single file may be mapped
|
||||||
// to multiple uris, and the same basename may map to multiple files
|
// to multiple uris, and the same basename may map to multiple files
|
||||||
@ -287,9 +283,12 @@ func (v *view) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before running the user provided function, clear caches in the resolver.
|
// In module mode, check if the mod file has changed.
|
||||||
if v.modFilesChanged() {
|
if mod, _, err := v.Snapshot().ModFiles(ctx); err == nil && mod != nil {
|
||||||
v.processEnv.GetResolver().(*imports.ModuleResolver).ClearForNewMod()
|
if mod.Identity() != v.cachedModFileVersion {
|
||||||
|
v.processEnv.GetResolver().(*imports.ModuleResolver).ClearForNewMod()
|
||||||
|
}
|
||||||
|
v.cachedModFileVersion = mod.Identity()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the user function.
|
// Run the user function.
|
||||||
@ -308,10 +307,6 @@ func (v *view) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If applicable, store the file versions of the 'go.mod' files that are
|
|
||||||
// looked at by the resolver.
|
|
||||||
v.storeModFileVersions()
|
|
||||||
|
|
||||||
if v.cacheRefreshTimer == nil {
|
if v.cacheRefreshTimer == nil {
|
||||||
// Don't refresh more than twice per minute.
|
// Don't refresh more than twice per minute.
|
||||||
delay := 30 * time.Second
|
delay := 30 * time.Second
|
||||||
@ -377,35 +372,6 @@ func (v *view) buildProcessEnv(ctx context.Context) (*imports.ProcessEnv, error)
|
|||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *view) modFilesChanged() bool {
|
|
||||||
// Check the versions of the 'go.mod' files of the main module
|
|
||||||
// and modules included by a replace directive. Return true if
|
|
||||||
// any of these file versions do not match.
|
|
||||||
for filename, version := range v.modFileVersions {
|
|
||||||
if version != v.fileVersion(filename) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *view) storeModFileVersions() {
|
|
||||||
// Store the mod files versions, if we are using a ModuleResolver.
|
|
||||||
r, moduleMode := v.processEnv.GetResolver().(*imports.ModuleResolver)
|
|
||||||
if !moduleMode || !r.Initialized {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v.modFileVersions = make(map[string]string)
|
|
||||||
|
|
||||||
// Get the file versions of the 'go.mod' files of the main module
|
|
||||||
// and modules included by a replace directive in the resolver.
|
|
||||||
for _, mod := range r.ModsByModPath {
|
|
||||||
if (mod.Main || mod.Replace != nil) && mod.GoMod != "" {
|
|
||||||
v.modFileVersions[mod.GoMod] = v.fileVersion(mod.GoMod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *view) fileVersion(filename string) string {
|
func (v *view) fileVersion(filename string) string {
|
||||||
uri := span.FileURI(filename)
|
uri := span.FileURI(filename)
|
||||||
fh := v.session.GetFile(uri)
|
fh := v.session.GetFile(uri)
|
||||||
|
Loading…
Reference in New Issue
Block a user