Skip to content

Commit 0b60bb2

Browse files
author
Mateusz Gajewski
committed
Export as interface, hide variables
1 parent d75ced4 commit 0b60bb2

File tree

11 files changed

+165
-457
lines changed

11 files changed

+165
-457
lines changed

cli/cli.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ type Config struct {
3636
FormatCode bool
3737
ForcePluginRebuild bool
3838
OutputPackage string
39+
HideVariables bool
40+
AsInterface bool
3941
}
4042

4143
// Cli is responsible for generating plugin wrapper, can be initialized with New()
@@ -96,10 +98,7 @@ func (c *Cli) GenerateFile() error {
9698
return fmt.Errorf("Could not create output file: %s", err)
9799
}
98100

99-
tpl, err := template.New("generate").
100-
Funcs(template.FuncMap{"isStandardImport": func(pkg string, importName string) bool {
101-
return pkg[strings.LastIndex(pkg, "/")+1:] == importName
102-
}}).Parse(generateFileTemplate)
101+
tpl, err := template.New("generate").Parse(generateFileTemplate)
103102

104103
if err != nil {
105104
return err
@@ -219,6 +218,14 @@ func (c *Cli) buildCommandArgs() string {
219218
commandLine = append(commandLine, "-rebuild")
220219
}
221220

221+
if c.config.AsInterface {
222+
commandLine = append(commandLine, "-interface")
223+
}
224+
225+
if c.config.HideVariables {
226+
commandLine = append(commandLine, "-hide-vars")
227+
}
228+
222229
return strings.Join(commandLine, " ")
223230
}
224231

@@ -243,5 +250,9 @@ func validateConfig(config *Config) error {
243250
config.PluginPath = "plugin.so"
244251
}
245252

253+
if config.AsInterface {
254+
config.HideVariables = true
255+
}
256+
246257
return nil
247258
}

cli/cli_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type testCase struct {
1818
Plugin string
1919
ExpectedOutput string
2020
ExecutedCode string
21+
AsInterface bool
2122
}
2223

2324
func TestWillGenerateComplexPluginWithoutErrors(t *testing.T) {
@@ -33,6 +34,12 @@ func TestWillGenerateComplexPluginWithoutErrors(t *testing.T) {
3334
ExecutedCode: "fmt.Println(pl.ReturningIntArray())",
3435
ExpectedOutput: "[1 0 1]",
3536
},
37+
{
38+
Plugin: "plugin_as_interface",
39+
ExecutedCode: "fmt.Println(pl.ReturningStringSlice())",
40+
ExpectedOutput: "hello world",
41+
AsInterface: true,
42+
},
3643
}
3744

3845
for i, testCase := range testCases {
@@ -47,14 +54,15 @@ func TestWillGenerateComplexPluginWithoutErrors(t *testing.T) {
4754
ForcePluginRebuild: true,
4855
OutputPackage: "main",
4956
OutputName: "TestWrapper",
57+
AsInterface: testCase.AsInterface,
5058
}
5159

5260
client, err := New(config, log.New(ioutil.Discard, "", 0))
5361
if err != nil {
5462
t.Fatalf("[Test %d] Expected err to be nil, actual: %s", i, err)
5563
}
5664

57-
if generateErr := client.GenerateFile(); err != nil {
65+
if generateErr := client.GenerateFile(); generateErr != nil {
5866
t.Fatalf("[Test %d] Expected err to be nil, actual: %s", i, generateErr)
5967
}
6068

cli/plugin.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"plugin"
7+
"strings"
78
"unsafe"
89
)
910

@@ -23,7 +24,10 @@ type pluginStructure struct {
2324

2425
Functions []*function
2526
Variables []*variable
26-
ImportsNames map[string]string
27+
Imports []string
28+
NamedImports map[string]string
29+
30+
importsNames map[string]string
2731
}
2832

2933
func loadPlugin(path string, imports []string) (*pluginStructure, error) {
@@ -47,9 +51,9 @@ func loadPlugin(path string, imports []string) (*pluginStructure, error) {
4751
ps := &pluginStructure{
4852
Symbols: plug.symbols,
4953
Package: plug.path,
50-
ImportsNames: make(map[string]string),
5154
Size: stat.Size(),
5255
Sha256: shaSum,
56+
importsNames: make(map[string]string),
5357
}
5458

5559
for _, pkg := range imports {
@@ -62,6 +66,9 @@ func loadPlugin(path string, imports []string) (*pluginStructure, error) {
6266
return nil, err2
6367
}
6468

69+
ps.Imports = ps.imports()
70+
ps.NamedImports = ps.namedImports()
71+
6572
return ps, nil
6673
}
6774

@@ -80,3 +87,33 @@ func (p *pluginStructure) analyze() error {
8087

8188
return nil
8289
}
90+
91+
func (p *pluginStructure) namedImports() map[string]string {
92+
var ret = make(map[string]string)
93+
94+
for name, imp := range p.importsNames {
95+
if p.isNamedImport(imp, name) {
96+
ret[name] = imp
97+
}
98+
}
99+
100+
return ret
101+
}
102+
103+
func (p *pluginStructure) imports() []string {
104+
var ret []string
105+
106+
for name, imp := range p.importsNames {
107+
if p.isNamedImport(imp, name) {
108+
ret = append(ret, fmt.Sprintf("%s %q", name, imp))
109+
} else {
110+
ret = append(ret, fmt.Sprintf("%q", imp))
111+
}
112+
}
113+
114+
return ret
115+
}
116+
117+
func (p *pluginStructure) isNamedImport(pkg string, importName string) bool {
118+
return pkg[strings.LastIndex(pkg, "/")+1:] != importName
119+
}

cli/reflect.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (p *pluginStructure) getNamedPkgImport(pkg string) string {
5757
nextImportName = fmt.Sprintf("%s_%d", importName, nextIndex)
5858
}
5959

60-
if current, ok := p.ImportsNames[nextImportName]; ok {
60+
if current, ok := p.importsNames[nextImportName]; ok {
6161
// We already have this package
6262
if current == pkg {
6363
return nextImportName + "."
@@ -66,7 +66,7 @@ func (p *pluginStructure) getNamedPkgImport(pkg string) string {
6666
nextIndex++
6767
continue
6868
} else {
69-
p.ImportsNames[nextImportName] = pkg
69+
p.importsNames[nextImportName] = pkg
7070
return nextImportName + "."
7171
}
7272
}

cli/template.go

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,51 @@ var generateFileTemplate = `package {{.OutputPackage}}
99
// - size: {{.Plugin.Size}} bytes
1010
// - sha256: {{.Plugin.Sha256}}
1111
12-
import ({{ range $key, $val := .Plugin.ImportsNames }}
13-
{{if isStandardImport $val $key }}"{{ $val }}"{{else}}{{ $key }} "{{ $val }}"{{end }}{{end}}
12+
{{ $imports := .Plugin.Imports }}
13+
import ({{ range $imports }}
14+
{{.}}
15+
{{end}}
1416
)
15-
{{$useVarReference := .Config.DereferenceVariables|not}}{{$pluginPackage := .Plugin.Package}}{{$receiver := .Config.OutputName}}
17+
{{$useVarReference := .Config.DereferenceVariables|not}}{{$pluginPackage := .Plugin.Package}}{{$receiver := .Config.OutputName}}{{$interface := .Config.AsInterface}}
1618
// {{.Config.OutputName}} wraps symbols (functions and variables) exported by plugin {{.Plugin.Package}}
1719
//
1820
// See docs at https://godoc.org/{{$pluginPackage}}
19-
type {{.Config.OutputName}} struct {
21+
type {{if $interface}}_{{end}}{{.Config.OutputName}} struct {
2022
// Exported functions
2123
{{range .Plugin.Functions}}_{{ .Name }} {{ .Signature }}
2224
{{end}}
25+
{{if .Config.HideVariables | not }}
2326
// Exported variables (public references)
2427
{{range .Plugin.Variables}}
2528
// See docs at https://godoc.org/{{$pluginPackage}}#{{ .Name }}
2629
{{ .Name }} {{if $useVarReference}}*{{end}}{{ .Signature }}{{end}}
30+
{{end}}
2731
}
32+
33+
{{if $interface}}
34+
// {{.Config.OutputName}} wraps functions exported by plugin {{.Plugin.Package}}
35+
//
36+
// See docs at https://godoc.org/{{$pluginPackage}}
37+
type {{.Config.OutputName}} interface {
38+
// Exported functions
39+
{{range .Plugin.Functions}}{{ .Name }} {{ .TrimmedSignature }}
40+
{{end}}
41+
}
42+
{{end}}
43+
2844
{{range .Plugin.Functions}}
2945
// {{.Name}} function was exported from plugin {{$pluginPackage}} symbol '{{.Name}}'
3046
//
3147
// See docs at https://godoc.org/{{$pluginPackage}}#{{.Name}}
32-
func (p *{{$receiver}}) {{.Name}}{{.TrimmedSignature}} {
48+
func (p *{{if $interface}}_{{end}}{{$receiver}}) {{.Name}}{{.TrimmedSignature}} {
3349
{{ if .ReturnsVoid | not }}return {{ end }}p._{{ .Name }}({{ .ArgumentsCall }})
3450
}
3551
{{end}}
3652
3753
// String returnes textual representation of the wrapper. It provides info on exported symbols and variables.
38-
func (p *{{$receiver}}) String() string {
54+
func (p *{{if $interface}}_{{end}}{{$receiver}}) String() string {
3955
var lines []string
40-
lines = append(lines, "Wrapper info:")
56+
lines = append(lines, "{{if $interface}}Interface{{else}}Struct{{end}} {{.Config.OutputName}}:")
4157
lines = append(lines, "\t- Generated on: {{.Build.Date}}")
4258
lines = append(lines, "\t- Command: {{.Build.Command}}")
4359
lines = append(lines, "\nPlugin info:")
@@ -47,19 +63,26 @@ func (p *{{$receiver}}) String() string {
4763
lines = append(lines, "\nExported functions ({{.Plugin.Functions|len}}):")
4864
{{ range .Plugin.Functions }}lines = append(lines, "\t- {{.Name}} {{ .Signature }}")
4965
{{ end }}
66+
{{ if .Config.HideVariables | not }}
67+
{{ if .Plugin.Variables }}
5068
lines = append(lines, "\nExported variables ({{.Plugin.Variables|len}}):")
5169
{{ range .Plugin.Variables }}lines = append(lines, "\t- {{.Name}} {{ .Signature }}")
5270
{{ end }}
53-
lines = append(lines, "\nPlugin imports:"){{ range $key, $val := .Plugin.ImportsNames }}{{if isStandardImport $val $key | not }}
71+
{{end}}
72+
{{end}}
73+
{{$imports := .Plugin.NamedImports}}
74+
{{if $imports}}
75+
lines = append(lines, "\nPlugin imports:"){{ range $key, $val := $imports }}
5476
lines = append(lines, "\t- {{ $val }} as {{ $key }}")
55-
{{end}}{{ end }}
77+
{{end}}
78+
{{end}}
5679
return strings.Join(lines, "\n")
5780
}
5881
59-
// Load{{.Config.OutputName}} loads plugin from the given path and binds symbols (variables and functions)
60-
// to the {{.Config.OutputName}} struct. {{if .Config.DereferenceVariables}}All variables are derefenences. {{end}}
61-
{{ if .Config.CheckSha256 }}// When plugin is loaded sha256 checksum is computed and checked against precomputed once. On mismatch error is returned. {{end}}
62-
func Bind{{.Config.OutputName}}(path string) (*{{.Config.OutputName}}, error) {
82+
// Bind{{.Config.OutputName}} loads plugin from the given path and binds {{if .Config.AsInterface}}functions{{else}}symbols (variables and functions){{end}}
83+
// to the {{if .Config.AsInterface}}struct implementing {{.Config.OutputName}} interface{{else}}{{.Config.OutputName}} struct{{end}}. {{if .Config.HideVariables | not}}{{if .Config.DereferenceVariables}}All variables are derefenences. {{end}}{{end}}
84+
{{ if .Config.CheckSha256 }}// When plugin is loaded sha256 checksum is computed and checked against precomputed once. On mismatch error is returned.
85+
{{end}}func Bind{{.Config.OutputName}}(path string) ({{if.Config.AsInterface|not}}*{{end}}{{.Config.OutputName}}, error) {
6386
p, err := plugin.Open(path)
6487
6588
if err != nil {
@@ -92,7 +115,7 @@ func Bind{{.Config.OutputName}}(path string) (*{{.Config.OutputName}}, error) {
92115
return nil, fmt.Errorf("Sha256 checksum mismatch (expected: {{.Plugin.Sha256}}, actual: %s)", checksum)
93116
}{{ end }}
94117
95-
ret := new({{.Config.OutputName}})
118+
ret := new({{if .Config.AsInterface}}_{{end}}{{.Config.OutputName}})
96119
{{range .Plugin.Functions}}
97120
func{{ .Name }}, err := p.Lookup("{{ .Name }}")
98121
if err != nil {
@@ -104,7 +127,9 @@ func Bind{{.Config.OutputName}}(path string) (*{{.Config.OutputName}}, error) {
104127
} else {
105128
return nil, fmt.Errorf("Could not import function '{{ .Name }}', incompatible types '{{ .Signature }}' and '%s'", reflect.TypeOf(func{{ .Name }}))
106129
}
107-
{{end}}{{range .Plugin.Variables}}
130+
{{end}}
131+
{{if .Config.HideVariables|not}}
132+
{{range .Plugin.Variables}}
108133
var{{ .Name }}, err := p.Lookup("{{ .Name }}")
109134
if err != nil {
110135
return nil, fmt.Errorf("Could not import variable '{{ .Name }}', symbol not found: %s", err)
@@ -116,6 +141,8 @@ func Bind{{.Config.OutputName}}(path string) (*{{.Config.OutputName}}, error) {
116141
return nil, fmt.Errorf("Could not import variable '{{ .Name }}', incompatible types '{{ .Signature }}' and '%s'", reflect.TypeOf(var{{ .Name }}))
117142
}
118143
{{end}}
144+
{{end}}
145+
119146
return ret, nil
120147
}
121148
`

internal/test_fixtures/basic_plugin/plugin.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,22 @@ package main
22

33
import "fmt"
44

5+
// ReturningInt32 is only exported for testing purposes
56
func ReturningInt32() int32 {
67
return 32
78
}
89

10+
// ReturningStringSlice is only exported for testing purposes
911
func ReturningStringSlice() []string {
1012
return make([]string, 0)
1113
}
1214

15+
// ReturningIntArray is only exported for testing purposes
1316
func ReturningIntArray() [3]int32 {
1417
return [...]int32{1, 0, 1}
1518
}
1619

20+
// NonReturningFunction is only exported for testing purposes
1721
func NonReturningFunction() {
1822
fmt.Println("I'm not returning anything")
1923
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package http
22

3+
// Work is only exported for testing purposes
34
type Work struct {
45
Work string
56
}
67

8+
// DoWork2 is only exported for testing purposes
79
func DoWork2(w Work) string {
810
return "I'm doing my work: " + w.Work
911
}

0 commit comments

Comments
 (0)