thrawn01.org

Grammar on my terms

How to Inspect Variables in a Golang Package

Jan 11, 2018 - 2 minute read - Comments

Google doesn’t have much on this topic, so here is what I found.

  1. You can’t use reflect to inspect a package at runtime.
  2. You can use go/parser to inspect the package if you have access to the source code

I needed to inspect a package to facilitate generating code at compile time. So the go/parser route worked fine for me.

The following code prints out the types and consts and functions found in the files of the ./events_pb package.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path"
	"strings"
)

func checkErr(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "-- %s\n", err)
		os.Exit(1)
	}
}

// Specify what files to parser
func onlyProtoBufFiles(info os.FileInfo) bool {
	if strings.HasSuffix(info.Name(), ".pb.go") {
		return true
	}
	return false
}

func main() {
	pwd, err := os.Getwd()
	checkErr(err)

	dir := path.Join(pwd, "events_pb")
	pkgs, err := parser.ParseDir(token.NewFileSet(), dir, onlyProtoBufFiles, 0)
	if err != nil {
		return
	}
	for _, pkg := range pkgs {
		for source, f := range pkg.Files {
			source = path.Base(source)
			for name, object := range f.Scope.Objects {
				if object.Kind == ast.Typ {
					fmt.Printf("%s: Type: %s\n", source, name)
				}
				if object.Kind == ast.Con {
					fmt.Printf("%s: Const: %s\n", source, name)
				}
				if object.Kind == ast.Fun {
					fmt.Printf("%s: Functions: %s\n", source, name)
				}
			}
		}
	}
}

Output looks like this


 fixtures.pb.go: Type: Bar
 fixtures.pb.go: Type: Blah
 fixtures.pb.go: Type: Bazz
 fixtures.pb.go: Type: Foo
 meta.pb.go: Const: Meta_FOO
 meta.pb.go: Const: Meta_BAR
 ...