mirror of https://github.com/golang/go.git
internal/lsp/cache: consider gopls.mod when finding workspace root
gopls.mod files should take precedence over go.mod files when finding a workspace root. To allow this, implement our own algorithm for expanding the workspace, rather than using the go command. For golang/go#41837 Change-Id: I943c08bdbdbdd164f108e44bae95d2c659a6e21e Reviewed-on: https://go-review.googlesource.com/c/tools/+/263897 Run-TryBot: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org> Trust: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
d463eb0e41
commit
f239dba448
|
|
@ -126,7 +126,7 @@ type workspaceInformation struct {
|
|||
}
|
||||
|
||||
type environmentVariables struct {
|
||||
gocache, gopath, goprivate, gomodcache, gomod string
|
||||
gocache, gopath, goprivate, gomodcache string
|
||||
}
|
||||
|
||||
type workspaceMode int
|
||||
|
|
@ -651,13 +651,15 @@ func (s *Session) getWorkspaceInformation(ctx context.Context, folder span.URI,
|
|||
tool, _ := exec.LookPath("gopackagesdriver")
|
||||
hasGopackagesDriver := gopackagesdriver != "off" && (gopackagesdriver != "" || tool != "")
|
||||
|
||||
var modURI span.URI
|
||||
if envVars.gomod != os.DevNull && envVars.gomod != "" {
|
||||
modURI = span.URIFromPath(envVars.gomod)
|
||||
}
|
||||
root := folder
|
||||
if options.ExpandWorkspaceToModule && modURI != "" {
|
||||
root = span.URIFromPath(filepath.Dir(modURI.Filename()))
|
||||
if options.ExpandWorkspaceToModule {
|
||||
wsRoot, err := findWorkspaceRoot(ctx, root, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if wsRoot != "" {
|
||||
root = wsRoot
|
||||
}
|
||||
}
|
||||
return &workspaceInformation{
|
||||
hasGopackagesDriver: hasGopackagesDriver,
|
||||
|
|
@ -669,6 +671,39 @@ func (s *Session) getWorkspaceInformation(ctx context.Context, folder span.URI,
|
|||
}, nil
|
||||
}
|
||||
|
||||
func findWorkspaceRoot(ctx context.Context, folder span.URI, fs source.FileSource) (span.URI, error) {
|
||||
for _, basename := range []string{"gopls.mod", "go.mod"} {
|
||||
dir, err := findRootPattern(ctx, folder, basename, fs)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("finding %s: %w", basename, err)
|
||||
}
|
||||
if dir != "" {
|
||||
return dir, nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func findRootPattern(ctx context.Context, folder span.URI, basename string, fs source.FileSource) (span.URI, error) {
|
||||
dir := folder.Filename()
|
||||
for dir != "" {
|
||||
target := filepath.Join(dir, basename)
|
||||
exists, err := fileExists(ctx, span.URIFromPath(target), fs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if exists {
|
||||
return span.URIFromPath(dir), nil
|
||||
}
|
||||
next, _ := filepath.Split(dir)
|
||||
if next == dir {
|
||||
break
|
||||
}
|
||||
dir = next
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// OS-specific path case check, for case-insensitive filesystems.
|
||||
var checkPathCase = defaultCheckPathCase
|
||||
|
||||
|
|
@ -710,7 +745,6 @@ func (s *Session) getGoEnv(ctx context.Context, folder string, configEnv []strin
|
|||
"GOPATH": &envVars.gopath,
|
||||
"GOPRIVATE": &envVars.goprivate,
|
||||
"GOMODCACHE": &envVars.gomodcache,
|
||||
"GOMOD": &envVars.gomod,
|
||||
}
|
||||
// We can save ~200 ms by requesting only the variables we care about.
|
||||
args := append([]string{"-json"}, imports.RequiredGoEnvVars...)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,14 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/fake"
|
||||
"golang.org/x/tools/internal/span"
|
||||
)
|
||||
|
||||
func TestCaseInsensitiveFilesystem(t *testing.T) {
|
||||
|
|
@ -43,3 +47,50 @@ func TestCaseInsensitiveFilesystem(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindWorkspaceRoot(t *testing.T) {
|
||||
workspace := `
|
||||
-- a/go.mod --
|
||||
module a
|
||||
-- a/x/x.go
|
||||
package x
|
||||
-- b/go.mod --
|
||||
module b
|
||||
-- b/c/go.mod --
|
||||
module bc
|
||||
-- d/gopls.mod --
|
||||
module d-goplsworkspace
|
||||
-- d/e/go.mod
|
||||
module de
|
||||
`
|
||||
dir, err := fake.Tempdir(workspace)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
tests := []struct {
|
||||
folder, want string
|
||||
}{
|
||||
// no module at root.
|
||||
{"", ""},
|
||||
{"a", "a"},
|
||||
{"a/x", "a"},
|
||||
{"b/c", "b/c"},
|
||||
{"d", "d"},
|
||||
{"d/e", "d"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
ctx := context.Background()
|
||||
rel := fake.RelativeTo(dir)
|
||||
folderURI := span.URIFromPath(rel.AbsPath(test.folder))
|
||||
got, err := findWorkspaceRoot(ctx, folderURI, osFileSource{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rel.RelPath(got.Filename()) != test.want {
|
||||
t.Errorf("fileWorkspaceRoot(%q) = %q, want %q", test.folder, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue