我正在寻找一种方法来检索本地安装的软件包,这些软件包包含给定类型的声明和默认软件包名称。
即:
func TestFindPackagesForType(t *testing.T) {
assert.Contains(t, FindPackagesForType("io.Reader"), "io")
assert.Contains(
t,
FindPackagesForType("types.Timestamp"),
"github.com/gogo/protobuf/types",
)
assert.Contains(
t,
FindPackagesForType("types.ContainerCreateConfig"),
"github.com/docker/docker/api/types",
)
}
我可以尝试检索所有已安装的软件包,并在每个AST中进行查找声明,但是如果有解决方案可以更有效地执行此操作,同时还为我想使用的go模块提供支持。 / p>
这样做的原因是为了改进代码生成工具。想法是让用户提供类型的名称,并让该工具识别最有可能的候选者,就像goimports添加缺失的导入一样。
答案 0 :(得分:1)
您可以使用reflect.TypeOf(any).PkgPath()
来获取某种类型的包装路径。但是,我们需要传递具有所需类型的对象(而不是您想要的字符串)。
package main
import (
"bytes"
"fmt"
"reflect"
"gopkg.in/mgo.v2/bson"
)
func main() {
var a bytes.Buffer
fmt.Println(FindPackagesForType(a)) // output: bytes
var b bson.M
fmt.Println(FindPackagesForType(b)) // output: gopkg.in/mgo.v2/bson
}
func FindPackagesForType(any interface{}) string {
return reflect.TypeOf(any).PkgPath()
}
答案 1 :(得分:0)
在程序下方列出了给定查询uses
和给定go包的definitions
和type
。
package main
import (
"flag"
"fmt"
"strings"
"golang.org/x/tools/go/loader"
)
func main() {
var query string
var uses bool
var defs bool
flag.StringVar(&query, "query", "", "the fully qualified type path")
flag.BoolVar(&uses, "uses", true, "capture uses")
flag.BoolVar(&defs, "definitions", true, "capture definitions")
flag.Parse()
if query == "" {
panic("query must not be empty")
}
var queryPkg string
queryType := query
if i := strings.LastIndex(query, "."); i > -1 {
queryPkg = query[:i]
queryType = query[i+1:]
}
var conf loader.Config
_, err := conf.FromArgs(flag.Args(), false)
if err != nil {
panic(err)
}
prog, err := conf.Load()
if err != nil {
panic(err)
}
for pkgType, pkgInfo := range prog.AllPackages {
if queryPkg != "" {
if !strings.HasPrefix(pkgType.Path(), queryPkg) {
continue
}
}
if defs {
for typeInfo, ident := range pkgInfo.Defs {
if !strings.HasPrefix(typeInfo.Name, queryType) {
continue
}
f := prog.Fset.File(ident.Pos())
fpos := f.Position(ident.Pos())
fmt.Printf("def: %v %v.%v\n", fpos, pkgType.Path(), typeInfo.Name)
}
}
if uses {
for ident, oInfo := range pkgInfo.Uses {
if !strings.Contains(oInfo.Type().String(), queryType) {
continue
}
f := prog.Fset.File(ident.Pos())
fpos := f.Position(ident.Pos())
fmt.Printf("use: %v %v\n", fpos, oInfo.Type().String())
}
}
// -
}
}
然后您以这种方式运行
$ go run main.go -query="io.Reader" io
def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:170:6 io.ReaderFrom
def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:77:6 io.Reader
def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:211:6 io.ReaderAt
use: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/multi.go:20:13 []io.Reader
use: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/multi.go:21:16 *io.multiReader
# a ton of output...
[mh-cbon@Host-001 ploader] $ go run main.go -query="Config" io
[mh-cbon@Host-001 ploader] $ go run main.go -query="io.Reader" -uses=false io
def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:170:6 io.ReaderFrom
def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:211:6 io.ReaderAt
def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:77:6 io.Reader
您可能需要改进匹配器引擎以使其更适合。