mirror of https://github.com/golang/go.git
internal/lsp/cache: keep a cached workspace module dir
Keep a workspace module dir around for running the go command against a snapshot, bound to the contents of the workspace modfile. This uses the cache's resource model to share the workspace module dir across snapshots if it is not invalidated, and to delete it when it is no longer in-use by a snapshot. Of course, the go command will still only see files on the filesystem, but using this immutable model was most consistent with the immutable workspace. For golang/go#41836 Change-Id: Iaec544283b2f545071e5cab1d0ff2a66e6d24dff Reviewed-on: https://go-review.googlesource.com/c/tools/+/263938 Run-TryBot: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com> Reviewed-by: Rebecca Stambler <rstambler@golang.org> Trust: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
3734b81991
commit
4fc0492b8e
|
|
@ -19,6 +19,7 @@ import (
|
|||
"golang.org/x/tools/internal/gocommand"
|
||||
"golang.org/x/tools/internal/lsp/debug/tag"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/memoize"
|
||||
"golang.org/x/tools/internal/packagesinternal"
|
||||
"golang.org/x/tools/internal/span"
|
||||
errors "golang.org/x/xerrors"
|
||||
|
|
@ -184,37 +185,62 @@ func (s *snapshot) parseLoadError(ctx context.Context, loadErr error) *source.Er
|
|||
return srcErrs
|
||||
}
|
||||
|
||||
// tempWorkspaceModule creates a temporary directory for use with
|
||||
// packages.Loads that occur from within the workspace module.
|
||||
func (s *snapshot) tempWorkspaceModule(ctx context.Context) (_ span.URI, cleanup func(), err error) {
|
||||
cleanup = func() {}
|
||||
if s.workspaceMode()&usesWorkspaceModule == 0 {
|
||||
return "", cleanup, nil
|
||||
type workspaceDirKey string
|
||||
|
||||
type workspaceDirData struct {
|
||||
dir string
|
||||
err error
|
||||
}
|
||||
|
||||
// getWorkspaceDir gets the URI for the workspace directory associated with
|
||||
// this snapshot. The workspace directory is a temp directory containing the
|
||||
// go.mod file computed from all active modules.
|
||||
func (s *snapshot) getWorkspaceDir(ctx context.Context) (span.URI, error) {
|
||||
s.mu.Lock()
|
||||
h := s.workspaceDirHandle
|
||||
s.mu.Unlock()
|
||||
if h != nil {
|
||||
return getWorkspaceDir(ctx, h, s.generation)
|
||||
}
|
||||
file, err := s.workspace.modFile(ctx, s)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
content, err := file.Format()
|
||||
if err != nil {
|
||||
return "", cleanup, err
|
||||
return "", err
|
||||
}
|
||||
// Create a temporary working directory for the go command that contains
|
||||
// the workspace module file.
|
||||
name, err := ioutil.TempDir("", "gopls-mod")
|
||||
key := workspaceDirKey(hashContents(content))
|
||||
s.mu.Lock()
|
||||
s.workspaceDirHandle = s.generation.Bind(key, func(context.Context, memoize.Arg) interface{} {
|
||||
tmpdir, err := ioutil.TempDir("", "gopls-workspace-mod")
|
||||
if err != nil {
|
||||
return &workspaceDirData{err: err}
|
||||
}
|
||||
filename := filepath.Join(tmpdir, "go.mod")
|
||||
if err := ioutil.WriteFile(filename, content, 0644); err != nil {
|
||||
os.RemoveAll(tmpdir)
|
||||
return &workspaceDirData{err: err}
|
||||
}
|
||||
return &workspaceDirData{dir: tmpdir}
|
||||
}, func(v interface{}) {
|
||||
d := v.(*workspaceDirData)
|
||||
if d.dir != "" {
|
||||
if err := os.RemoveAll(d.dir); err != nil {
|
||||
event.Error(context.Background(), "cleaning workspace dir", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
s.mu.Unlock()
|
||||
return getWorkspaceDir(ctx, s.workspaceDirHandle, s.generation)
|
||||
}
|
||||
|
||||
func getWorkspaceDir(ctx context.Context, h *memoize.Handle, g *memoize.Generation) (span.URI, error) {
|
||||
v, err := h.Get(ctx, g, nil)
|
||||
if err != nil {
|
||||
return "", cleanup, err
|
||||
return "", err
|
||||
}
|
||||
cleanup = func() {
|
||||
os.RemoveAll(name)
|
||||
}
|
||||
filename := filepath.Join(name, "go.mod")
|
||||
if err := ioutil.WriteFile(filename, content, 0644); err != nil {
|
||||
cleanup()
|
||||
return "", cleanup, err
|
||||
}
|
||||
return span.URIFromPath(filepath.Dir(filename)), cleanup, nil
|
||||
return span.URIFromPath(v.(*workspaceDirData).dir), nil
|
||||
}
|
||||
|
||||
// setMetadata extracts metadata from pkg and records it in s. It
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ type snapshot struct {
|
|||
modUpgradeHandles map[span.URI]*modUpgradeHandle
|
||||
modWhyHandles map[span.URI]*modWhyHandle
|
||||
|
||||
workspace *workspace
|
||||
workspace *workspace
|
||||
workspaceDirHandle *memoize.Handle
|
||||
}
|
||||
|
||||
type packageKey struct {
|
||||
|
|
@ -252,7 +253,7 @@ func (s *snapshot) goCommandInvocation(ctx context.Context, mode source.Invocati
|
|||
} else {
|
||||
var tmpDir span.URI
|
||||
var err error
|
||||
tmpDir, cleanup, err = s.tempWorkspaceModule(ctx)
|
||||
tmpDir, err = s.getWorkspaceDir(ctx)
|
||||
if err != nil {
|
||||
return "", nil, cleanup, err
|
||||
}
|
||||
|
|
@ -1001,6 +1002,11 @@ func (s *snapshot) clone(ctx context.Context, changes map[span.URI]*fileChange,
|
|||
workspace: newWorkspace,
|
||||
}
|
||||
|
||||
if !workspaceChanged && s.workspaceDirHandle != nil {
|
||||
result.workspaceDirHandle = s.workspaceDirHandle
|
||||
newGen.Inherit(s.workspaceDirHandle)
|
||||
}
|
||||
|
||||
if s.builtin != nil {
|
||||
newGen.Inherit(s.builtin.handle)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue