Skip to content

Commit f5c7449

Browse files
firelizzard18findleyr
authored andcommitted
gopls/internal: implement Packages command
Implements the `gopls.packages` command. Updates golang/go#59445 Change-Id: Ia72a971b7aac9baa964c8cf5eee8b332b3125fa4 Reviewed-on: https://go-review.googlesource.com/c/tools/+/600355 Reviewed-by: Cherry Mui <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent e5e8aa8 commit f5c7449

File tree

2 files changed

+218
-2
lines changed

2 files changed

+218
-2
lines changed

gopls/internal/server/command.go

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,85 @@ func (h *commandHandler) Modules(ctx context.Context, args command.ModulesArgs)
143143
return result, nil
144144
}
145145

146-
func (h *commandHandler) Packages(context.Context, command.PackagesArgs) (command.PackagesResult, error) {
147-
panic("unimplemented")
146+
func (h *commandHandler) Packages(ctx context.Context, args command.PackagesArgs) (command.PackagesResult, error) {
147+
wantTests := args.Mode&command.NeedTests != 0
148+
result := command.PackagesResult{
149+
Module: make(map[string]command.Module),
150+
}
151+
152+
keepPackage := func(pkg *metadata.Package) bool {
153+
for _, file := range pkg.GoFiles {
154+
for _, arg := range args.Files {
155+
if file == arg || file.Dir() == arg {
156+
return true
157+
}
158+
if args.Recursive && arg.Encloses(file) {
159+
return true
160+
}
161+
}
162+
}
163+
return false
164+
}
165+
166+
buildPackage := func(snapshot *cache.Snapshot, meta *metadata.Package) (command.Package, command.Module) {
167+
if wantTests {
168+
// These will be used in the next CL to query tests
169+
_, _ = ctx, snapshot
170+
panic("unimplemented")
171+
}
172+
173+
pkg := command.Package{
174+
Path: string(meta.PkgPath),
175+
}
176+
if meta.Module == nil {
177+
return pkg, command.Module{}
178+
}
179+
180+
mod := command.Module{
181+
Path: meta.Module.Path,
182+
Version: meta.Module.Version,
183+
GoMod: protocol.URIFromPath(meta.Module.GoMod),
184+
}
185+
pkg.ModulePath = mod.Path
186+
return pkg, mod
187+
}
188+
189+
err := h.run(ctx, commandConfig{
190+
progress: "Packages",
191+
}, func(ctx context.Context, _ commandDeps) error {
192+
for _, view := range h.s.session.Views() {
193+
snapshot, release, err := view.Snapshot()
194+
if err != nil {
195+
return err
196+
}
197+
defer release()
198+
199+
metas, err := snapshot.WorkspaceMetadata(ctx)
200+
if err != nil {
201+
return err
202+
}
203+
204+
for _, meta := range metas {
205+
if meta.IsIntermediateTestVariant() {
206+
continue
207+
}
208+
if !keepPackage(meta) {
209+
continue
210+
}
211+
212+
pkg, mod := buildPackage(snapshot, meta)
213+
result.Packages = append(result.Packages, pkg)
214+
215+
// Overwriting is ok
216+
if mod.Path != "" {
217+
result.Module[mod.Path] = mod
218+
}
219+
}
220+
}
221+
222+
return nil
223+
})
224+
return result, err
148225
}
149226

150227
func (h *commandHandler) MaybePromptForTelemetry(ctx context.Context) error {
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package workspace
6+
7+
import (
8+
"sort"
9+
"strings"
10+
"testing"
11+
12+
"github.com/google/go-cmp/cmp"
13+
"golang.org/x/tools/gopls/internal/protocol"
14+
"golang.org/x/tools/gopls/internal/protocol/command"
15+
. "golang.org/x/tools/gopls/internal/test/integration"
16+
)
17+
18+
func TestPackages(t *testing.T) {
19+
const goModView = `
20+
-- go.mod --
21+
module foo
22+
23+
-- foo.go --
24+
package foo
25+
func Foo()
26+
27+
-- bar/bar.go --
28+
package bar
29+
func Bar()
30+
31+
-- baz/go.mod --
32+
module baz
33+
34+
-- baz/baz.go --
35+
package baz
36+
func Baz()
37+
`
38+
39+
t.Run("file", func(t *testing.T) {
40+
Run(t, goModView, func(t *testing.T, env *Env) {
41+
checkPackages(t, env, []protocol.DocumentURI{env.Editor.DocumentURI("foo.go")}, false, []command.Package{
42+
{
43+
Path: "foo",
44+
ModulePath: "foo",
45+
},
46+
}, map[string]command.Module{
47+
"foo": {
48+
Path: "foo",
49+
GoMod: env.Editor.DocumentURI("go.mod"),
50+
},
51+
})
52+
})
53+
})
54+
55+
t.Run("package", func(t *testing.T) {
56+
Run(t, goModView, func(t *testing.T, env *Env) {
57+
checkPackages(t, env, []protocol.DocumentURI{env.Editor.DocumentURI("bar")}, false, []command.Package{
58+
{
59+
Path: "foo/bar",
60+
ModulePath: "foo",
61+
},
62+
}, map[string]command.Module{
63+
"foo": {
64+
Path: "foo",
65+
GoMod: env.Editor.DocumentURI("go.mod"),
66+
},
67+
})
68+
})
69+
})
70+
71+
t.Run("workspace", func(t *testing.T) {
72+
Run(t, goModView, func(t *testing.T, env *Env) {
73+
checkPackages(t, env, []protocol.DocumentURI{env.Editor.DocumentURI("")}, true, []command.Package{
74+
{
75+
Path: "foo",
76+
ModulePath: "foo",
77+
},
78+
{
79+
Path: "foo/bar",
80+
ModulePath: "foo",
81+
},
82+
}, map[string]command.Module{
83+
"foo": {
84+
Path: "foo",
85+
GoMod: env.Editor.DocumentURI("go.mod"),
86+
},
87+
})
88+
})
89+
})
90+
91+
t.Run("nested module", func(t *testing.T) {
92+
Run(t, goModView, func(t *testing.T, env *Env) {
93+
// Load the nested module
94+
env.OpenFile("baz/baz.go")
95+
96+
// Request packages using the URI of the nested module _directory_
97+
checkPackages(t, env, []protocol.DocumentURI{env.Editor.DocumentURI("baz")}, true, []command.Package{
98+
{
99+
Path: "baz",
100+
ModulePath: "baz",
101+
},
102+
}, map[string]command.Module{
103+
"baz": {
104+
Path: "baz",
105+
GoMod: env.Editor.DocumentURI("baz/go.mod"),
106+
},
107+
})
108+
})
109+
})
110+
}
111+
112+
func checkPackages(t testing.TB, env *Env, files []protocol.DocumentURI, recursive bool, wantPkg []command.Package, wantModule map[string]command.Module) {
113+
t.Helper()
114+
115+
cmd, err := command.NewPackagesCommand("Packages", command.PackagesArgs{Files: files, Recursive: recursive})
116+
if err != nil {
117+
t.Fatal(err)
118+
}
119+
var result command.PackagesResult
120+
env.ExecuteCommand(&protocol.ExecuteCommandParams{
121+
Command: command.Packages.String(),
122+
Arguments: cmd.Arguments,
123+
}, &result)
124+
125+
// The ordering of packages is undefined so sort the results to ensure
126+
// consistency
127+
sort.Slice(result.Packages, func(i, j int) bool {
128+
a, b := result.Packages[i], result.Packages[j]
129+
return strings.Compare(a.Path, b.Path) < 0
130+
})
131+
132+
if diff := cmp.Diff(wantPkg, result.Packages); diff != "" {
133+
t.Errorf("Packages(%v) returned unexpected packages (-want +got):\n%s", files, diff)
134+
}
135+
136+
if diff := cmp.Diff(wantModule, result.Module); diff != "" {
137+
t.Errorf("Packages(%v) returned unexpected modules (-want +got):\n%s", files, diff)
138+
}
139+
}

0 commit comments

Comments
 (0)