mirror of
https://github.com/golang/go
synced 2024-11-18 15:34:53 -07:00
cb8d9cd245
Some code lenses may be undesirable for certain users or editors -- for example a code lens that runs tests, when VSCode already supports this functionality outside of the LSP. To handle such situations, support configuring code lenses via a new 'codelens' gopls option. Add support for code lens in regtests, and use this to test the new configuration. To achieve this, thread through a new 'EditorConfig' type that configures the fake editor's LSP session. It made sense to move the test Env overlay onto this config object as well. While looking at them, document some types in source.Options. Change-Id: I961077422a273829c5cbd83c3b87fae29f77eeda Reviewed-on: https://go-review.googlesource.com/c/tools/+/232680 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
147 lines
4.1 KiB
Go
147 lines
4.1 KiB
Go
// 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 fake
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"golang.org/x/tools/internal/gocommand"
|
|
"golang.org/x/tools/txtar"
|
|
)
|
|
|
|
// Sandbox holds a collection of temporary resources to use for working with Go
|
|
// code in tests.
|
|
type Sandbox struct {
|
|
name string
|
|
gopath string
|
|
basedir string
|
|
Proxy *Proxy
|
|
Workdir *Workdir
|
|
}
|
|
|
|
// NewSandbox creates a collection of named temporary resources, with a
|
|
// working directory populated by the txtar-encoded content in srctxt, and a
|
|
// file-based module proxy populated with the txtar-encoded content in
|
|
// proxytxt.
|
|
func NewSandbox(name, srctxt, proxytxt string, inGopath bool) (_ *Sandbox, err error) {
|
|
sb := &Sandbox{
|
|
name: name,
|
|
}
|
|
defer func() {
|
|
// Clean up if we fail at any point in this constructor.
|
|
if err != nil {
|
|
sb.Close()
|
|
}
|
|
}()
|
|
basedir, err := ioutil.TempDir("", fmt.Sprintf("goplstest-sandbox-%s-", name))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating temporary workdir: %v", err)
|
|
}
|
|
sb.basedir = basedir
|
|
proxydir := filepath.Join(sb.basedir, "proxy")
|
|
sb.gopath = filepath.Join(sb.basedir, "gopath")
|
|
// Set the working directory as $GOPATH/src if inGopath is true.
|
|
workdir := filepath.Join(sb.gopath, "src")
|
|
dirs := []string{sb.gopath, proxydir}
|
|
if !inGopath {
|
|
workdir = filepath.Join(sb.basedir, "work")
|
|
dirs = append(dirs, workdir)
|
|
}
|
|
for _, subdir := range dirs {
|
|
if err := os.Mkdir(subdir, 0755); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
sb.Proxy, err = NewProxy(proxydir, proxytxt)
|
|
sb.Workdir, err = NewWorkdir(workdir, srctxt)
|
|
|
|
return sb, nil
|
|
}
|
|
|
|
func unpackTxt(txt string) map[string][]byte {
|
|
dataMap := make(map[string][]byte)
|
|
archive := txtar.Parse([]byte(txt))
|
|
for _, f := range archive.Files {
|
|
dataMap[f.Name] = f.Data
|
|
}
|
|
return dataMap
|
|
}
|
|
|
|
// splitModuleVersionPath extracts module information from files stored in the
|
|
// directory structure modulePath@version/suffix.
|
|
// For example:
|
|
// splitModuleVersionPath("mod.com@v1.2.3/package") = ("mod.com", "v1.2.3", "package")
|
|
func splitModuleVersionPath(path string) (modulePath, version, suffix string) {
|
|
parts := strings.Split(path, "/")
|
|
var modulePathParts []string
|
|
for i, p := range parts {
|
|
if strings.Contains(p, "@") {
|
|
mv := strings.SplitN(p, "@", 2)
|
|
modulePathParts = append(modulePathParts, mv[0])
|
|
return strings.Join(modulePathParts, "/"), mv[1], strings.Join(parts[i+1:], "/")
|
|
}
|
|
modulePathParts = append(modulePathParts, p)
|
|
}
|
|
// Default behavior: this is just a module path.
|
|
return path, "", ""
|
|
}
|
|
|
|
// GOPATH returns the value of the Sandbox GOPATH.
|
|
func (sb *Sandbox) GOPATH() string {
|
|
return sb.gopath
|
|
}
|
|
|
|
// GoEnv returns the default environment variables that can be used for
|
|
// invoking Go commands in the sandbox.
|
|
func (sb *Sandbox) GoEnv() []string {
|
|
return []string{
|
|
"GOPATH=" + sb.GOPATH(),
|
|
"GOPROXY=" + sb.Proxy.GOPROXY(),
|
|
"GO111MODULE=",
|
|
"GOSUMDB=off",
|
|
}
|
|
}
|
|
|
|
// RunGoCommand executes a go command in the sandbox.
|
|
func (sb *Sandbox) RunGoCommand(ctx context.Context, verb string, args ...string) error {
|
|
inv := gocommand.Invocation{
|
|
Verb: verb,
|
|
Args: args,
|
|
WorkingDir: sb.Workdir.workdir,
|
|
Env: sb.GoEnv(),
|
|
}
|
|
gocmdRunner := &gocommand.Runner{}
|
|
_, _, _, err := gocmdRunner.RunRaw(ctx, inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Since running a go command may result in changes to workspace files,
|
|
// check if we need to send any any "watched" file events.
|
|
if err := sb.Workdir.CheckForFileChanges(ctx); err != nil {
|
|
return fmt.Errorf("checking for file changes: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Close removes all state associated with the sandbox.
|
|
func (sb *Sandbox) Close() error {
|
|
var goCleanErr error
|
|
if sb.gopath != "" {
|
|
if err := sb.RunGoCommand(context.Background(), "clean", "-modcache"); err != nil {
|
|
goCleanErr = fmt.Errorf("cleaning modcache: %v", err)
|
|
}
|
|
}
|
|
err := os.RemoveAll(sb.basedir)
|
|
if err != nil || goCleanErr != nil {
|
|
return fmt.Errorf("error(s) cleaning sandbox: cleaning modcache: %v; removing files: %v", goCleanErr, err)
|
|
}
|
|
return nil
|
|
}
|