aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp/cache/imports.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/lsp/cache/imports.go')
-rw-r--r--internal/lsp/cache/imports.go201
1 files changed, 0 insertions, 201 deletions
diff --git a/internal/lsp/cache/imports.go b/internal/lsp/cache/imports.go
deleted file mode 100644
index 01a2468ef..000000000
--- a/internal/lsp/cache/imports.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cache
-
-import (
- "context"
- "fmt"
- "reflect"
- "strings"
- "sync"
- "time"
-
- "golang.org/x/tools/internal/event"
- "golang.org/x/tools/internal/event/keys"
- "golang.org/x/tools/internal/gocommand"
- "golang.org/x/tools/internal/imports"
- "golang.org/x/tools/internal/lsp/source"
-)
-
-type importsState struct {
- ctx context.Context
-
- mu sync.Mutex
- processEnv *imports.ProcessEnv
- cleanupProcessEnv func()
- cacheRefreshDuration time.Duration
- cacheRefreshTimer *time.Timer
- cachedModFileHash string
- cachedBuildFlags []string
-}
-
-func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot, fn func(*imports.Options) error) error {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- // Find the hash of the active mod file, if any. Using the unsaved content
- // is slightly wasteful, since we'll drop caches a little too often, but
- // the mod file shouldn't be changing while people are autocompleting.
- var modFileHash string
- // If we are using 'legacyWorkspace' mode, we can just read the modfile from
- // the snapshot. Otherwise, we need to get the synthetic workspace mod file.
- //
- // TODO(rfindley): we should be able to just always use the synthetic
- // workspace module, or alternatively use the go.work file.
- if snapshot.workspace.moduleSource == legacyWorkspace {
- for m := range snapshot.workspace.getActiveModFiles() { // range to access the only element
- modFH, err := snapshot.GetFile(ctx, m)
- if err != nil {
- return err
- }
- modFileHash = modFH.FileIdentity().Hash
- }
- } else {
- modFile, err := snapshot.workspace.modFile(ctx, snapshot)
- if err != nil {
- return err
- }
- modBytes, err := modFile.Format()
- if err != nil {
- return err
- }
- modFileHash = hashContents(modBytes)
- }
-
- // view.goEnv is immutable -- changes make a new view. Options can change.
- // We can't compare build flags directly because we may add -modfile.
- snapshot.view.optionsMu.Lock()
- localPrefix := snapshot.view.options.Local
- currentBuildFlags := snapshot.view.options.BuildFlags
- changed := !reflect.DeepEqual(currentBuildFlags, s.cachedBuildFlags) ||
- snapshot.view.options.VerboseOutput != (s.processEnv.Logf != nil) ||
- modFileHash != s.cachedModFileHash
- snapshot.view.optionsMu.Unlock()
-
- // If anything relevant to imports has changed, clear caches and
- // update the processEnv. Clearing caches blocks on any background
- // scans.
- if changed {
- // As a special case, skip cleanup the first time -- we haven't fully
- // initialized the environment yet and calling GetResolver will do
- // unnecessary work and potentially mess up the go.mod file.
- if s.cleanupProcessEnv != nil {
- if resolver, err := s.processEnv.GetResolver(); err == nil {
- if modResolver, ok := resolver.(*imports.ModuleResolver); ok {
- modResolver.ClearForNewMod()
- }
- }
- s.cleanupProcessEnv()
- }
- s.cachedModFileHash = modFileHash
- s.cachedBuildFlags = currentBuildFlags
- var err error
- s.cleanupProcessEnv, err = s.populateProcessEnv(ctx, snapshot)
- if err != nil {
- return err
- }
- }
-
- // Run the user function.
- opts := &imports.Options{
- // Defaults.
- AllErrors: true,
- Comments: true,
- Fragment: true,
- FormatOnly: false,
- TabIndent: true,
- TabWidth: 8,
- Env: s.processEnv,
- LocalPrefix: localPrefix,
- }
-
- if err := fn(opts); err != nil {
- return err
- }
-
- if s.cacheRefreshTimer == nil {
- // Don't refresh more than twice per minute.
- delay := 30 * time.Second
- // Don't spend more than a couple percent of the time refreshing.
- if adaptive := 50 * s.cacheRefreshDuration; adaptive > delay {
- delay = adaptive
- }
- s.cacheRefreshTimer = time.AfterFunc(delay, s.refreshProcessEnv)
- }
-
- return nil
-}
-
-// populateProcessEnv sets the dynamically configurable fields for the view's
-// process environment. Assumes that the caller is holding the s.view.importsMu.
-func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapshot) (cleanup func(), err error) {
- pe := s.processEnv
-
- if snapshot.view.Options().VerboseOutput {
- pe.Logf = func(format string, args ...interface{}) {
- event.Log(ctx, fmt.Sprintf(format, args...))
- }
- } else {
- pe.Logf = nil
- }
-
- // Take an extra reference to the snapshot so that its workspace directory
- // (if any) isn't destroyed while we're using it.
- release := snapshot.generation.Acquire()
- _, inv, cleanupInvocation, err := snapshot.goCommandInvocation(ctx, source.LoadWorkspace, &gocommand.Invocation{
- WorkingDir: snapshot.view.rootURI.Filename(),
- })
- if err != nil {
- return nil, err
- }
- pe.WorkingDir = inv.WorkingDir
- pe.BuildFlags = inv.BuildFlags
- pe.WorkingDir = inv.WorkingDir
- pe.ModFile = inv.ModFile
- pe.ModFlag = inv.ModFlag
- pe.Env = map[string]string{}
- for _, kv := range inv.Env {
- split := strings.SplitN(kv, "=", 2)
- if len(split) != 2 {
- continue
- }
- pe.Env[split[0]] = split[1]
- }
-
- return func() {
- cleanupInvocation()
- release()
- }, nil
-}
-
-func (s *importsState) refreshProcessEnv() {
- start := time.Now()
-
- s.mu.Lock()
- env := s.processEnv
- if resolver, err := s.processEnv.GetResolver(); err == nil {
- resolver.ClearForNewScan()
- }
- s.mu.Unlock()
-
- event.Log(s.ctx, "background imports cache refresh starting")
- if err := imports.PrimeCache(context.Background(), env); err == nil {
- event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)))
- } else {
- event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)), keys.Err.Of(err))
- }
- s.mu.Lock()
- s.cacheRefreshDuration = time.Since(start)
- s.cacheRefreshTimer = nil
- s.mu.Unlock()
-}
-
-func (s *importsState) destroy() {
- s.mu.Lock()
- if s.cleanupProcessEnv != nil {
- s.cleanupProcessEnv()
- }
- s.mu.Unlock()
-}