pkg/terminal: add 'packages' command (#3499)
This command lists the packages included in the debugee. The implementation utilizes "ListPackagesBuildInfo" RPC. In order to support server-side filtering like `sources` and other commands, expanded the ListPackagesBuildInfo RPC to take an optional filter field.
This commit is contained in:
parent
382bb0fde6
commit
e072a64903
@ -89,6 +89,7 @@ Command | Description
|
||||
[help](#help) | Prints the help message.
|
||||
[libraries](#libraries) | List loaded dynamic libraries
|
||||
[list](#list) | Show source code.
|
||||
[packages](#packages) | Print list of packages.
|
||||
[source](#source) | Executes a file containing a list of delve commands
|
||||
[sources](#sources) | Print list of source files.
|
||||
[target](#target) | Manages child process debugging.
|
||||
@ -539,6 +540,14 @@ The command 'on <bp> cond <cond-arguments>' is equivalent to 'cond <bp> <cond-ar
|
||||
The command 'on x -edit' can be used to edit the list of commands executed when the breakpoint is hit.
|
||||
|
||||
|
||||
## packages
|
||||
Print list of packages.
|
||||
|
||||
packages [<regex>]
|
||||
|
||||
If regex is specified only the packages matching it will be returned.
|
||||
|
||||
|
||||
## print
|
||||
Evaluate an expression.
|
||||
|
||||
|
@ -54,7 +54,7 @@ functions(Filter) | Equivalent to API call [ListFunctions](https://godoc.org/git
|
||||
goroutines(Start, Count, Filters, GoroutineGroupingOptions, EvalScope) | Equivalent to API call [ListGoroutines](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListGoroutines)
|
||||
local_vars(Scope, Cfg) | Equivalent to API call [ListLocalVars](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListLocalVars)
|
||||
package_vars(Filter, Cfg) | Equivalent to API call [ListPackageVars](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListPackageVars)
|
||||
packages_build_info(IncludeFiles) | Equivalent to API call [ListPackagesBuildInfo](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListPackagesBuildInfo)
|
||||
packages_build_info(IncludeFiles, Filter) | Equivalent to API call [ListPackagesBuildInfo](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListPackagesBuildInfo)
|
||||
registers(ThreadID, IncludeFp, Scope) | Equivalent to API call [ListRegisters](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListRegisters)
|
||||
sources(Filter) | Equivalent to API call [ListSources](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListSources)
|
||||
targets() | Equivalent to API call [ListTargets](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ListTargets)
|
||||
|
@ -356,6 +356,11 @@ If regex is specified only the functions matching it will be returned.`},
|
||||
types [<regex>]
|
||||
|
||||
If regex is specified only the types matching it will be returned.`},
|
||||
{aliases: []string{"packages"}, cmdFn: packages, helpMsg: `Print list of packages.
|
||||
|
||||
packages [<regex>]
|
||||
|
||||
If regex is specified only the packages matching it will be returned.`},
|
||||
{aliases: []string{"args"}, allowedPrefixes: onPrefix | deferredPrefix, group: dataCmds, cmdFn: args, helpMsg: `Print function arguments.
|
||||
|
||||
[goroutine <n>] [frame <m>] args [-v] [<regex>]
|
||||
@ -2224,6 +2229,18 @@ func sources(t *Term, ctx callContext, args string) error {
|
||||
return t.printSortedStrings(t.client.ListSources(args))
|
||||
}
|
||||
|
||||
func packages(t *Term, ctx callContext, args string) error {
|
||||
info, err := t.client.ListPackagesBuildInfo(args, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkgs := make([]string, 0, len(info))
|
||||
for _, i := range info {
|
||||
pkgs = append(pkgs, i.ImportPath)
|
||||
}
|
||||
return t.printSortedStrings(pkgs, nil)
|
||||
}
|
||||
|
||||
func funcs(t *Term, ctx callContext, args string) error {
|
||||
return t.printSortedStrings(t.client.ListFunctions(args))
|
||||
}
|
||||
|
@ -1445,3 +1445,31 @@ func TestRestartBreakpoints(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestListPackages(t *testing.T) {
|
||||
test.AllowRecording(t)
|
||||
withTestTerminal("goroutinestackprog", t, func(term *FakeTerminal) {
|
||||
out := term.MustExec("packages")
|
||||
t.Logf("> packages\n%s", out)
|
||||
seen := map[string]bool{}
|
||||
for _, p := range strings.Split(strings.TrimSpace(out), "\n") {
|
||||
seen[p] = true
|
||||
}
|
||||
if !seen["main"] || !seen["runtime"] {
|
||||
t.Error("output omits 'main' and 'runtime'")
|
||||
}
|
||||
|
||||
out = term.MustExec("packages runtime")
|
||||
t.Logf("> packages runtime\n%s", out)
|
||||
|
||||
for _, p := range strings.Split(strings.TrimSpace(out), "\n") {
|
||||
if !strings.Contains(p, "runtime") {
|
||||
t.Errorf("output includes unexpected %q", p)
|
||||
}
|
||||
seen[p] = true
|
||||
}
|
||||
if !seen["runtime"] {
|
||||
t.Error("output omits 'runtime'")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1275,11 +1275,19 @@ func (env *Env) starlarkPredeclare() (starlark.StringDict, map[string]string) {
|
||||
return starlark.None, decorateError(thread, err)
|
||||
}
|
||||
}
|
||||
if len(args) > 1 && args[1] != starlark.None {
|
||||
err := unmarshalStarlarkValue(args[1], &rpcArgs.Filter, "Filter")
|
||||
if err != nil {
|
||||
return starlark.None, decorateError(thread, err)
|
||||
}
|
||||
}
|
||||
for _, kv := range kwargs {
|
||||
var err error
|
||||
switch kv[0].(starlark.String) {
|
||||
case "IncludeFiles":
|
||||
err = unmarshalStarlarkValue(kv[1], &rpcArgs.IncludeFiles, "IncludeFiles")
|
||||
case "Filter":
|
||||
err = unmarshalStarlarkValue(kv[1], &rpcArgs.Filter, "Filter")
|
||||
default:
|
||||
err = fmt.Errorf("unknown argument %q", kv[0])
|
||||
}
|
||||
@ -1293,7 +1301,7 @@ func (env *Env) starlarkPredeclare() (starlark.StringDict, map[string]string) {
|
||||
}
|
||||
return env.interfaceToStarlarkValue(rpcRet), nil
|
||||
})
|
||||
doc["packages_build_info"] = "builtin packages_build_info(IncludeFiles)\n\npackages_build_info returns the list of packages used by the program along with\nthe directory where each package was compiled and optionally the list of\nfiles constituting the package.\nNote that the directory path is a best guess and may be wrong is a tool\nother than cmd/go is used to perform the build."
|
||||
doc["packages_build_info"] = "builtin packages_build_info(IncludeFiles, Filter)\n\npackages_build_info returns the list of packages used by the program along with\nthe directory where each package was compiled and optionally the list of\nfiles constituting the package.\nNote that the directory path is a best guess and may be wrong is a tool\nother than cmd/go is used to perform the build."
|
||||
r["registers"] = starlark.NewBuiltin("registers", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
|
||||
if err := isCancelled(thread); err != nil {
|
||||
return starlark.None, decorateError(thread, err)
|
||||
|
@ -108,6 +108,8 @@ type Client interface {
|
||||
ListFunctions(filter string) ([]string, error)
|
||||
// ListTypes lists all types in the process matching filter.
|
||||
ListTypes(filter string) ([]string, error)
|
||||
// ListPackagesBuildInfo lists all packages in the process matching filter.
|
||||
ListPackagesBuildInfo(filter string, includeFiles bool) ([]api.PackageBuildInfo, error)
|
||||
// ListLocalVariables lists all local variables in scope.
|
||||
ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error)
|
||||
// ListFunctionArgs lists all arguments to the current function.
|
||||
|
@ -357,6 +357,12 @@ func (c *RPCClient) ListPackageVariables(filter string, cfg api.LoadConfig) ([]a
|
||||
return out.Variables, err
|
||||
}
|
||||
|
||||
func (c *RPCClient) ListPackagesBuildInfo(filter string, includeFiles bool) ([]api.PackageBuildInfo, error) {
|
||||
var out ListPackagesBuildInfoOut
|
||||
err := c.call("ListPackagesBuildInfo", ListPackagesBuildInfoIn{Filter: filter, IncludeFiles: includeFiles}, &out)
|
||||
return out.List, err
|
||||
}
|
||||
|
||||
func (c *RPCClient) ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) {
|
||||
var out ListLocalVarsOut
|
||||
err := c.call("ListLocalVars", ListLocalVarsIn{scope, cfg}, &out)
|
||||
|
@ -3,6 +3,7 @@ package rpc2
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
@ -912,12 +913,13 @@ func (s *RPCServer) ListDynamicLibraries(in ListDynamicLibrariesIn, out *ListDyn
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListPackagesBuildInfoIn holds the arguments of ListPackages.
|
||||
// ListPackagesBuildInfoIn holds the arguments of ListPackagesBuildInfo.
|
||||
type ListPackagesBuildInfoIn struct {
|
||||
IncludeFiles bool
|
||||
Filter string // if not empty, returns only packages matching the regexp.
|
||||
}
|
||||
|
||||
// ListPackagesBuildInfoOut holds the return values of ListPackages.
|
||||
// ListPackagesBuildInfoOut holds the return values of ListPackagesBuildInfo.
|
||||
type ListPackagesBuildInfoOut struct {
|
||||
List []api.PackageBuildInfo
|
||||
}
|
||||
@ -928,9 +930,20 @@ type ListPackagesBuildInfoOut struct {
|
||||
// Note that the directory path is a best guess and may be wrong is a tool
|
||||
// other than cmd/go is used to perform the build.
|
||||
func (s *RPCServer) ListPackagesBuildInfo(in ListPackagesBuildInfoIn, out *ListPackagesBuildInfoOut) error {
|
||||
var pattern *regexp.Regexp
|
||||
if in.Filter != "" {
|
||||
p, err := regexp.Compile(in.Filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid Filter pattern: %v", err)
|
||||
}
|
||||
pattern = p
|
||||
}
|
||||
pkgs := s.debugger.ListPackagesBuildInfo(in.IncludeFiles)
|
||||
out.List = make([]api.PackageBuildInfo, 0, len(pkgs))
|
||||
for _, pkg := range pkgs {
|
||||
if pattern != nil && !pattern.MatchString(pkg.ImportPath) {
|
||||
continue
|
||||
}
|
||||
var files []string
|
||||
|
||||
if len(pkg.Files) > 0 {
|
||||
|
Loading…
Reference in New Issue
Block a user