Skip to content

Commit 8087911

Browse files
committed
gopls: remove the experimentalWorkspaceModule mode
Remove the experimentalWorkspaceModule setting, and all of the roots it has planted. Specifically, this removes: - the gopls.mod and filesystem workspace modes - the command to generate a gopls.mod - the need to track separate workspace modes entirely, as we align with the Go command and don't need any additional logic - the need to maintain a workspace directory - the 'cache.workspace' abstraction entirely; now we can just track workspace modules Along the way, further simplify the treatment of view workspace information. In particular, just use the value of GOWORK returned by the go command, rather than computing it ourselves. This means that we may need to re-run `go env` while processing a change to go.mod or go.work files. If that proves to be problematic, we can improve it in the future. Many workspace tests had to be restricted to just Go 1.18+, because we no longer fake go.work support at earlier Go versions. Fixes golang/go#55331 Change-Id: I15ad58f548295727a51b99f43c7572b066f9df07 Reviewed-on: https://go-review.googlesource.com/c/tools/+/458116 gopls-CI: kokoro <[email protected]> Reviewed-by: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Robert Findley <[email protected]>
1 parent 5b300bd commit 8087911

32 files changed

+320
-1684
lines changed

gopls/doc/commands.md

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,20 +147,6 @@ Args:
147147
}
148148
```
149149

150-
### **Generate gopls.mod**
151-
Identifier: `gopls.generate_gopls_mod`
152-
153-
(Re)generate the gopls.mod file for a workspace.
154-
155-
Args:
156-
157-
```
158-
{
159-
// The file URI.
160-
"URI": string,
161-
}
162-
```
163-
164150
### **go get a package**
165151
Identifier: `gopls.go_get_package`
166152

gopls/doc/settings.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,6 @@ a go.mod file, narrowing the scope to that directory if it exists.
116116

117117
Default: `true`.
118118

119-
#### **experimentalWorkspaceModule** *bool*
120-
121-
**This setting is experimental and may be deleted.**
122-
123-
experimentalWorkspaceModule opts a user into the experimental support
124-
for multi-module workspaces.
125-
126-
Deprecated: this feature is deprecated and will be removed in a future
127-
version of gopls (https://go.dev/issue/55331).
128-
129-
Default: `false`.
130-
131119
#### **experimentalPackageCacheKey** *bool*
132120

133121
**This setting is experimental and may be deleted.**

gopls/internal/lsp/cache/check.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,9 @@ func typeCheckImpl(ctx context.Context, snapshot *snapshot, goFiles, compiledGoF
357357
// If this is a replaced module in the workspace, the version is
358358
// meaningless, and we don't want clients to access it.
359359
if m.Module != nil {
360-
version := m.Module.Version
361-
if source.IsWorkspaceModuleVersion(version) {
362-
version = ""
363-
}
364360
pkg.version = &module.Version{
365361
Path: m.Module.Path,
366-
Version: version,
362+
Version: m.Module.Version,
367363
}
368364
}
369365

gopls/internal/lsp/cache/imports.go

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package cache
77
import (
88
"context"
99
"fmt"
10-
"os"
1110
"reflect"
1211
"strings"
1312
"sync"
@@ -25,12 +24,18 @@ type importsState struct {
2524

2625
mu sync.Mutex
2726
processEnv *imports.ProcessEnv
28-
cleanupProcessEnv func()
2927
cacheRefreshDuration time.Duration
3028
cacheRefreshTimer *time.Timer
3129
cachedModFileHash source.Hash
3230
cachedBuildFlags []string
3331
cachedDirectoryFilters []string
32+
33+
// runOnce records whether runProcessEnvFunc has been called at least once.
34+
// This is necessary to avoid resetting state before the process env is
35+
// populated.
36+
//
37+
// TODO(rfindley): this shouldn't be necessary.
38+
runOnce bool
3439
}
3540

3641
func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot, fn func(*imports.Options) error) error {
@@ -43,7 +48,7 @@ func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot
4348
//
4449
// TODO(rfindley): consider instead hashing on-disk modfiles here.
4550
var modFileHash source.Hash
46-
for m := range snapshot.workspace.ActiveModFiles() {
51+
for m := range snapshot.workspaceModFiles {
4752
fh, err := snapshot.GetFile(ctx, m)
4853
if err != nil {
4954
return err
@@ -70,22 +75,21 @@ func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot
7075
// As a special case, skip cleanup the first time -- we haven't fully
7176
// initialized the environment yet and calling GetResolver will do
7277
// unnecessary work and potentially mess up the go.mod file.
73-
if s.cleanupProcessEnv != nil {
78+
if s.runOnce {
7479
if resolver, err := s.processEnv.GetResolver(); err == nil {
7580
if modResolver, ok := resolver.(*imports.ModuleResolver); ok {
7681
modResolver.ClearForNewMod()
7782
}
7883
}
79-
s.cleanupProcessEnv()
8084
}
85+
8186
s.cachedModFileHash = modFileHash
8287
s.cachedBuildFlags = currentBuildFlags
8388
s.cachedDirectoryFilters = currentDirectoryFilters
84-
var err error
85-
s.cleanupProcessEnv, err = s.populateProcessEnv(ctx, snapshot)
86-
if err != nil {
89+
if err := s.populateProcessEnv(ctx, snapshot); err != nil {
8790
return err
8891
}
92+
s.runOnce = true
8993
}
9094

9195
// Run the user function.
@@ -120,7 +124,7 @@ func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot
120124

121125
// populateProcessEnv sets the dynamically configurable fields for the view's
122126
// process environment. Assumes that the caller is holding the s.view.importsMu.
123-
func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapshot) (cleanup func(), err error) {
127+
func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapshot) error {
124128
pe := s.processEnv
125129

126130
if snapshot.view.Options().VerboseOutput {
@@ -141,7 +145,7 @@ func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapsho
141145
WorkingDir: snapshot.view.workingDir().Filename(),
142146
})
143147
if err != nil {
144-
return nil, err
148+
return err
145149
}
146150

147151
pe.BuildFlags = inv.BuildFlags
@@ -156,29 +160,9 @@ func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapsho
156160
}
157161
// We don't actually use the invocation, so clean it up now.
158162
cleanupInvocation()
159-
160-
// If the snapshot uses a synthetic workspace directory, create a copy for
161-
// the lifecycle of the importsState.
162-
//
163-
// Notably, we cannot use the snapshot invocation working directory, as that
164-
// is tied to the lifecycle of the snapshot.
165-
//
166-
// Otherwise return a no-op cleanup function.
167-
cleanup = func() {}
168-
if snapshot.usesWorkspaceDir() {
169-
tmpDir, err := makeWorkspaceDir(ctx, snapshot.workspace, snapshot)
170-
if err != nil {
171-
return nil, err
172-
}
173-
pe.WorkingDir = tmpDir
174-
cleanup = func() {
175-
os.RemoveAll(tmpDir) // ignore error
176-
}
177-
} else {
178-
pe.WorkingDir = snapshot.view.workingDir().Filename()
179-
}
180-
181-
return cleanup, nil
163+
// TODO(rfindley): should this simply be inv.WorkingDir?
164+
pe.WorkingDir = snapshot.view.workingDir().Filename()
165+
return nil
182166
}
183167

184168
func (s *importsState) refreshProcessEnv() {
@@ -202,11 +186,3 @@ func (s *importsState) refreshProcessEnv() {
202186
s.cacheRefreshTimer = nil
203187
s.mu.Unlock()
204188
}
205-
206-
func (s *importsState) destroy() {
207-
s.mu.Lock()
208-
if s.cleanupProcessEnv != nil {
209-
s.cleanupProcessEnv()
210-
}
211-
s.mu.Unlock()
212-
}

gopls/internal/lsp/cache/load.go

Lines changed: 14 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import (
99
"context"
1010
"errors"
1111
"fmt"
12-
"io/ioutil"
13-
"os"
1412
"path/filepath"
1513
"sort"
1614
"strings"
@@ -287,22 +285,17 @@ func (m *moduleErrorMap) Error() string {
287285
// TODO(rfindley): separate workspace diagnostics from critical workspace
288286
// errors.
289287
func (s *snapshot) workspaceLayoutError(ctx context.Context) (error, []*source.Diagnostic) {
290-
// TODO(rfindley): do we really not want to show a critical error if the user
291-
// has no go.mod files?
292-
if len(s.workspace.getKnownModFiles()) == 0 {
293-
return nil, nil
294-
}
295-
296288
// TODO(rfindley): both of the checks below should be delegated to the workspace.
289+
297290
if s.view.effectiveGO111MODULE() == off {
298291
return nil, nil
299292
}
300-
if s.workspace.moduleSource != legacyWorkspace {
301-
return nil, nil
302-
}
303293

304-
// If the user has one module per view, there is nothing to warn about.
305-
if s.ValidBuildConfiguration() && len(s.workspace.getKnownModFiles()) == 1 {
294+
// If the user is using a go.work file, we assume that they know what they
295+
// are doing.
296+
//
297+
// TODO(golang/go#53880): improve orphaned file diagnostics when using go.work.
298+
if s.view.gowork != "" {
306299
return nil, nil
307300
}
308301

@@ -335,10 +328,10 @@ https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.`
335328
// If the user has one active go.mod file, they may still be editing files
336329
// in nested modules. Check the module of each open file and add warnings
337330
// that the nested module must be opened as a workspace folder.
338-
if len(s.workspace.ActiveModFiles()) == 1 {
331+
if len(s.workspaceModFiles) == 1 {
339332
// Get the active root go.mod file to compare against.
340333
var rootMod string
341-
for uri := range s.workspace.ActiveModFiles() {
334+
for uri := range s.workspaceModFiles {
342335
rootMod = uri.Filename()
343336
}
344337
rootDir := filepath.Dir(rootMod)
@@ -413,55 +406,6 @@ func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, fi
413406
return srcDiags
414407
}
415408

416-
// getWorkspaceDir returns the URI for the workspace directory
417-
// associated with this snapshot. The workspace directory is a
418-
// temporary directory containing the go.mod file computed from all
419-
// active modules.
420-
func (s *snapshot) getWorkspaceDir(ctx context.Context) (span.URI, error) {
421-
s.mu.Lock()
422-
dir, err := s.workspaceDir, s.workspaceDirErr
423-
s.mu.Unlock()
424-
if dir == "" && err == nil { // cache miss
425-
dir, err = makeWorkspaceDir(ctx, s.workspace, s)
426-
s.mu.Lock()
427-
s.workspaceDir, s.workspaceDirErr = dir, err
428-
s.mu.Unlock()
429-
}
430-
return span.URIFromPath(dir), err
431-
}
432-
433-
// makeWorkspaceDir creates a temporary directory containing a go.mod
434-
// and go.sum file for each module in the workspace.
435-
// Note: snapshot's mutex must be unlocked for it to satisfy FileSource.
436-
func makeWorkspaceDir(ctx context.Context, workspace *workspace, fs source.FileSource) (string, error) {
437-
file, err := workspace.modFile(ctx, fs)
438-
if err != nil {
439-
return "", err
440-
}
441-
modContent, err := file.Format()
442-
if err != nil {
443-
return "", err
444-
}
445-
sumContent, err := workspace.sumFile(ctx, fs)
446-
if err != nil {
447-
return "", err
448-
}
449-
tmpdir, err := ioutil.TempDir("", "gopls-workspace-mod")
450-
if err != nil {
451-
return "", err
452-
}
453-
for name, content := range map[string][]byte{
454-
"go.mod": modContent,
455-
"go.sum": sumContent,
456-
} {
457-
if err := ioutil.WriteFile(filepath.Join(tmpdir, name), content, 0644); err != nil {
458-
os.RemoveAll(tmpdir) // ignore error
459-
return "", err
460-
}
461-
}
462-
return tmpdir, nil
463-
}
464-
465409
// buildMetadata populates the updates map with metadata updates to
466410
// apply, based on the given pkg. It recurs through pkg.Imports to ensure that
467411
// metadata exists for all dependencies.
@@ -628,9 +572,13 @@ func containsPackageLocked(s *snapshot, m *source.Metadata) bool {
628572
// Otherwise if the package has a module it must be an active module (as
629573
// defined by the module root or go.work file) and at least one file must not
630574
// be filtered out by directoryFilters.
631-
if m.Module != nil && s.workspace.moduleSource != legacyWorkspace {
575+
//
576+
// TODO(rfindley): revisit this function. We should not need to predicate on
577+
// gowork != "". It should suffice to consider workspace mod files (also, we
578+
// will hopefully eliminate the concept of a workspace package soon).
579+
if m.Module != nil && s.view.gowork != "" {
632580
modURI := span.URIFromPath(m.Module.GoMod)
633-
_, ok := s.workspace.activeModFiles[modURI]
581+
_, ok := s.workspaceModFiles[modURI]
634582
if !ok {
635583
return false
636584
}

gopls/internal/lsp/cache/mod.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,6 @@ func (s *snapshot) matchErrorToModule(ctx context.Context, pm *source.ParsedModu
383383

384384
for i := len(matches) - 1; i >= 0; i-- {
385385
ver := module.Version{Path: matches[i][1], Version: matches[i][2]}
386-
// Any module versions that come from the workspace module should not
387-
// be shown to the user.
388-
if source.IsWorkspaceModuleVersion(ver.Version) {
389-
continue
390-
}
391386
if err := module.Check(ver.Path, ver.Version); err != nil {
392387
continue
393388
}
@@ -424,11 +419,6 @@ func (s *snapshot) goCommandDiagnostic(pm *source.ParsedModule, spn span.Span, g
424419
var innermost *module.Version
425420
for i := len(matches) - 1; i >= 0; i-- {
426421
ver := module.Version{Path: matches[i][1], Version: matches[i][2]}
427-
// Any module versions that come from the workspace module should not
428-
// be shown to the user.
429-
if source.IsWorkspaceModuleVersion(ver.Version) {
430-
continue
431-
}
432422
if err := module.Check(ver.Path, ver.Version); err != nil {
433423
continue
434424
}

0 commit comments

Comments
 (0)