Skip to content

Commit

Permalink
gopls/internal/protocol/command: draft Packages/Modules API
Browse files Browse the repository at this point in the history
This new Packages command provides information about
go packages known to gopls. The Modules command reports
modules known to gopls and found in the directory.

For golang/go#59445

Change-Id: Ief0ac4984efb4a0e7f0fee8d8d55dae35eb00375
Reviewed-on: https://go-review.googlesource.com/c/tools/+/579438
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Ethan Reesor <ethan.reesor@gmail.com>
Reviewed-by: Robert Findley <rfindley@google.com>
  • Loading branch information
hyangah authored and gopherbot committed Jul 11, 2024
1 parent d29feb5 commit ef4d083
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 0 deletions.
82 changes: 82 additions & 0 deletions gopls/doc/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,88 @@ Result:
}
```

<a id='gopls.modules'></a>
## `gopls.modules`: **Return information about modules within a directory**

This command returns an empty result if there is no module,
or if module mode is disabled.
The result does not includes the modules that are not
associated with any Views on the server yet.

Args:

```
{
// Dir is the directory in which to search for go.mod files.
"Dir": string,
// MaxDepth is the directory walk limit.
// A value of 0 means inspect only Dir.
// 1 means inspect its child directories too, and so on.
// A negative value removes the limit.
"MaxDepth": int,
}
```

Result:

```
{
"Modules": []{
"Path": string,
"Version": string,
"GoMod": string,
},
}
```

<a id='gopls.packages'></a>
## `gopls.packages`: **Return information about packages**

This command returns an empty result if the specified files
or directories are not associated with any Views on the
server yet.

Args:

```
{
// Files is a list of files and directories whose associated
// packages should be described by the result.
//
// In some cases, a file may belong to more than one package;
// the result may describe any of them.
"Files": []string,
// Enumerate all packages under the directry loadable with
// the ... pattern.
// The search does not cross the module boundaries and
// does not return packages that are not yet loaded.
// (e.g. those excluded by the gopls directory filter setting,
// or the go.work configuration)
"Recursive": bool,
// Mode controls the types of information returned for each package.
"Mode": uint64,
}
```

Result:

```
{
// Packages is an unordered list of package metadata.
"Packages": []{
"Path": string,
"ModulePath": string,
"TestFiles": []{
"URI": string,
"Tests": { ... },
},
},
// Modules maps module path to module metadata for
// all the modules of the returned Packages.
"Module": map[string]golang.org/x/tools/gopls/internal/protocol/command.Module,
}
```

<a id='gopls.regenerate_cgo'></a>
## `gopls.regenerate_cgo`: **Regenerate cgo**

Expand Down
14 changes: 14 additions & 0 deletions gopls/internal/doc/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,20 @@
"ArgDoc": "",
"ResultDoc": "{\n\t\"HeapAlloc\": uint64,\n\t\"HeapInUse\": uint64,\n\t\"TotalAlloc\": uint64,\n}"
},
{
"Command": "gopls.modules",
"Title": "Return information about modules within a directory",
"Doc": "This command returns an empty result if there is no module,\nor if module mode is disabled.\nThe result does not includes the modules that are not\nassociated with any Views on the server yet.",
"ArgDoc": "{\n\t// Dir is the directory in which to search for go.mod files.\n\t\"Dir\": string,\n\t// MaxDepth is the directory walk limit.\n\t// A value of 0 means inspect only Dir.\n\t// 1 means inspect its child directories too, and so on.\n\t// A negative value removes the limit.\n\t\"MaxDepth\": int,\n}",
"ResultDoc": "{\n\t\"Modules\": []{\n\t\t\"Path\": string,\n\t\t\"Version\": string,\n\t\t\"GoMod\": string,\n\t},\n}"
},
{
"Command": "gopls.packages",
"Title": "Return information about packages",
"Doc": "This command returns an empty result if the specified files\nor directories are not associated with any Views on the\nserver yet.",
"ArgDoc": "{\n\t// Files is a list of files and directories whose associated\n\t// packages should be described by the result.\n\t//\n\t// In some cases, a file may belong to more than one package;\n\t// the result may describe any of them.\n\t\"Files\": []string,\n\t// Enumerate all packages under the directry loadable with\n\t// the ... pattern.\n\t// The search does not cross the module boundaries and\n\t// does not return packages that are not yet loaded.\n\t// (e.g. those excluded by the gopls directory filter setting,\n\t// or the go.work configuration)\n\t\"Recursive\": bool,\n\t// Mode controls the types of information returned for each package.\n\t\"Mode\": uint64,\n}",
"ResultDoc": "{\n\t// Packages is an unordered list of package metadata.\n\t\"Packages\": []{\n\t\t\"Path\": string,\n\t\t\"ModulePath\": string,\n\t\t\"TestFiles\": []{\n\t\t\t\"URI\": string,\n\t\t\t\"Tests\": { ... },\n\t\t},\n\t},\n\t// Modules maps module path to module metadata for\n\t// all the modules of the returned Packages.\n\t\"Module\": map[string]golang.org/x/tools/gopls/internal/protocol/command.Module,\n}"
},
{
"Command": "gopls.regenerate_cgo",
"Title": "Regenerate cgo",
Expand Down
40 changes: 40 additions & 0 deletions gopls/internal/protocol/command/command_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

157 changes: 157 additions & 0 deletions gopls/internal/protocol/command/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,21 @@ type Interface interface {
//
// This command is intended for use by gopls tests only.
ScanImports(context.Context) error

// Packages: Return information about packages
//
// This command returns an empty result if the specified files
// or directories are not associated with any Views on the
// server yet.
Packages(context.Context, PackagesArgs) (PackagesResult, error)

// Modules: Return information about modules within a directory
//
// This command returns an empty result if there is no module,
// or if module mode is disabled.
// The result does not includes the modules that are not
// associated with any Views on the server yet.
Modules(context.Context, ModulesArgs) (ModulesResult, error)
}

type RunTestsArgs struct {
Expand Down Expand Up @@ -569,3 +584,145 @@ type View struct {
Folder protocol.DocumentURI // workspace folder associated with the view
EnvOverlay []string // environment variable overrides
}

// PackagesArgs holds arguments for the Packages command.
type PackagesArgs struct {
// Files is a list of files and directories whose associated
// packages should be described by the result.
//
// In some cases, a file may belong to more than one package;
// the result may describe any of them.
Files []protocol.DocumentURI

// Enumerate all packages under the directry loadable with
// the ... pattern.
// The search does not cross the module boundaries and
// does not return packages that are not yet loaded.
// (e.g. those excluded by the gopls directory filter setting,
// or the go.work configuration)
Recursive bool `json:"Recursive,omitempty"`

// Mode controls the types of information returned for each package.
Mode PackagesMode
}

// PackagesMode controls the details to include in PackagesResult.
type PackagesMode uint64

const (
// Populate the [TestFile.Tests] field in [Package] returned by the
// Packages command.
NeedTests PackagesMode = 1 << iota
)

// PackagesResult is the result of the Packages command.
type PackagesResult struct {
// Packages is an unordered list of package metadata.
Packages []Package

// Modules maps module path to module metadata for
// all the modules of the returned Packages.
Module map[string]Module
}

// Package describes a Go package (not an empty parent).
type Package struct {
// Package path.
Path string
// Module path. Empty if the package doesn't
// belong to any module.
ModulePath string

// Note: the result does not include the directory name
// of the package because mapping between a package and
// a folder is not possible in certain build systems.
// If directory info is needed, one can guess it
// from the TestFile's file name.

// TestFiles contains the subset of the files of the package
// whose name ends with "_test.go".
// They are ordered deterministically as determined
// by the underlying build system.
TestFiles []TestFile
}

type Module struct {
Path string // module path
Version string // module version if any.
GoMod protocol.DocumentURI // path to the go.mod file.
}

type TestFile struct {
URI protocol.DocumentURI // a *_test.go file

// Tests is the list of tests in File, including subtests.
//
// The set of subtests is not exhaustive as in general they may be
// dynamically generated, so it is impossible for static heuristics
// to enumerate them.
//
// Tests are lexically ordered.
// Since subtest names are prefixed by their top-level test names
// each top-level test precedes its subtests.
Tests []TestCase
}

// TestCase represents a test case.
// A test case can be a top-level Test/Fuzz/Benchmark/Example function,
// as recognized by 'go list' or 'go test -list', or
// a subtest within a top-level function.
type TestCase struct {
// Name is the complete name of the test (Test, Benchmark, Example, or Fuzz)
// or the subtest as it appears in the output of go test -json.
// The server may attempt to infer names of subtests by static
// analysis; if so, it should aim to simulate the actual computed
// name of the test, including any disambiguating suffix such as "#01".
// To run only this test, clients need to compute the -run, -bench, -fuzz
// flag values by first splitting the Name with “/” and
// quoting each element with "^" + regexp.QuoteMeta(Name) + "$".
// e.g. TestToplevel/Inner.Subtest → -run=^TestToplevel$/^Inner\.Subtest$
Name string

// Loc is the filename and range enclosing this test function
// or the subtest. This is used to place the gutter marker
// and group tests based on location.
// For subtests whose test names can be determined statically,
// this can be either t.Run or the test data table
// for table-driven setup.
// Some testing frameworks allow to declare the actual test
// logic in a different file. For example, one can define
// a testify test suite in suite_test.go and use it from
// main_test.go.
/*
-- main_test.go --
...
func TestFoo(t *testing.T) {
suite.Run(t, new(MyTestSuite))
}
-- suite_test.go --
type MyTestSuite struct {
suite.Suite
}
func (suite *MyTestSuite) TestBar() { ... }
*/
// In this case, the testing framework creates "TestFoo/TestBar"
// and the corresponding test case belongs to "main_test.go"
// TestFile. However, the test case has "suite_test.go" as its
// file location.
Loc protocol.Location
}

type ModulesArgs struct {
// Dir is the directory in which to search for go.mod files.
Dir protocol.DocumentURI

// MaxDepth is the directory walk limit.
// A value of 0 means inspect only Dir.
// 1 means inspect its child directories too, and so on.
// A negative value removes the limit.
MaxDepth int
}

type ModulesResult struct {
Modules []Module
}
8 changes: 8 additions & 0 deletions gopls/internal/server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ type commandHandler struct {
params *protocol.ExecuteCommandParams
}

func (h *commandHandler) Modules(context.Context, command.ModulesArgs) (command.ModulesResult, error) {
panic("unimplemented")
}

func (h *commandHandler) Packages(context.Context, command.PackagesArgs) (command.PackagesResult, error) {
panic("unimplemented")
}

func (h *commandHandler) MaybePromptForTelemetry(ctx context.Context) error {
go h.s.maybePromptForTelemetry(ctx, true)
return nil
Expand Down

0 comments on commit ef4d083

Please sign in to comment.