Skip to content

Commit

Permalink
Move plugins to own module & improve apigen CLI
Browse files Browse the repository at this point in the history
This patch moves the binapigenerator plugins to their own package.
- It capitalizes the methods they leverage.
- It changes the way plugins are called, passing the whole generator
at once and letting the plugin themselves loop on the files.
This allow for more variety in filtering, aggregation, etc...

This patch also proposes an evolution to the binapigen CLI
in order to make it more user-friendly for newcomers as well
as build pipelines based on go:generate

For now two usecases are in the picture:
- Building from a directory containing .json files
e.g. 'binapigen --api /usr/share/vpp/api --output ./myapp/bindings --filter interface,ip'
- Building from a cloned local VPP
e.g. 'binapigen --vpp ~/vpp --output ./myapp/binding'

Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
Change-Id: I5b0b2ade40ab80c9e91c2a422f8c193b232d9830
  • Loading branch information
sknat committed Sep 28, 2022
1 parent 491e018 commit 62f5161
Show file tree
Hide file tree
Showing 21 changed files with 483 additions and 385 deletions.
2 changes: 1 addition & 1 deletion binapigen/binapigen.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ func getMsgType(m vppapi.Message) (msgType, error) {
return typ, nil
}

func getRetvalField(m *Message) *Field {
func GetRetvalField(m *Message) *Field {
for _, field := range m.Fields {
if field.Name == fieldRetval {
return field
Expand Down
67 changes: 40 additions & 27 deletions binapigen/binapigen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,56 @@
package binapigen

import (
"os"
"path/filepath"
"testing"

. "github.com/onsi/gomega"

"go.fd.io/govpp/binapigen/vppapi"
)

var sampleJson = `{
"types": [],
"messages": [],
"unions": [],
"enums": [],
"enumflags": [],
"services": {},
"options": {
"version": "1.7.0"
},
"aliases": {},
"vl_api_version": "0x12345678",
"imports": [],
"counters": [],
"paths": []
}`

func TestGenerator(t *testing.T) {
tests := []struct {
name string
file *vppapi.File
expectPackage string
}{
{name: "vpe", file: &vppapi.File{
Name: "vpe",
Path: "/usr/share/vpp/api/core/vpe.api.json",
CRC: "0x12345678",
},
expectPackage: "vpe",
},
RegisterTestingT(t)

dir, err := os.MkdirTemp("", "govpp-test")
if err != nil {
t.Fatal(err)
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
RegisterTestingT(t)
defer os.RemoveAll(dir)

apiFiles := []*vppapi.File{test.file}
file := filepath.Join(dir, "vpe.api.json")
if err := os.WriteFile(file, []byte(sampleJson), 0666); err != nil {
t.Fatal(err)
}

gen, err := New(Options{
ImportPrefix: "test",
}, apiFiles, nil)
Expect(err).ToNot(HaveOccurred(), "unexpected generator error: %v", err)
os.Setenv(VPPVersionEnvVar, "test-version")
gen, err := New(Options{
ApiDir: dir,
FileFilter: []string{file},
ImportPrefix: "test",
})
Expect(err).ToNot(HaveOccurred(), "unexpected generator error: %v", err)

Expect(gen.Files).To(HaveLen(1))
Expect(gen.Files[0].PackageName).To(BeEquivalentTo(test.expectPackage))
Expect(gen.Files[0].GoImportPath).To(BeEquivalentTo("test/" + test.expectPackage))
})
}
Expect(gen.Files).To(HaveLen(1))
Expect(gen.Files[0].PackageName).To(BeEquivalentTo("vpe"))
Expect(gen.Files[0].GoImportPath).To(BeEquivalentTo("test/vpe"))
Expect(gen.Files[0].Desc.CRC).To(BeEquivalentTo("0x12345678"))
}

func TestSanitize(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion binapigen/gen_encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ func decodeField(g *GenFile, field *Field, name string, getFieldName func(string
if field.Length > 0 {
g.P("for ", index, " := 0; ", index, " < ", field.Length, ";", index, "++ {")
} else if field.SizeFrom != "" {
g.P(name, " = make(", getFieldType(g, field), ", ", sizeFromName, ")")
g.P(name, " = make(", GetFieldType(g, field), ", ", sizeFromName, ")")
g.P("for ", index, " := 0; ", index, " < len(", name, ");", index, "++ {")
}
name = fmt.Sprintf("%s[%s]", name, index)
Expand Down
9 changes: 4 additions & 5 deletions binapigen/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ func GenerateAPI(gen *Generator, file *File) *GenFile {
logf("----------------------------")

filename := path.Join(file.FilenamePrefix, file.Desc.Name+".ba.go")
g := gen.NewGenFile(filename, file.GoImportPath)
g.file = file
g := gen.NewGenFile(filename, file)

g.P("// Code generated by GoVPP's binapi-generator. DO NOT EDIT.")
if !gen.opts.NoVersionInfo {
Expand Down Expand Up @@ -317,7 +316,7 @@ func genUnion(g *GenFile, union *Union) {
// generate field comments
g.P("// ", union.GoName, " can be one of:")
for _, field := range union.Fields {
g.P("// - ", field.GoName, " *", getFieldType(g, field))
g.P("// - ", field.GoName, " *", GetFieldType(g, field))
}

// generate data field
Expand Down Expand Up @@ -377,7 +376,7 @@ func genField(g *GenFile, fields []*Field, i int) {

logf(" gen FIELD[%d] %s (%s) - type: %q (array: %v/%v)", i, field.GoName, field.Name, field.Type, field.Array, field.Length)

gotype := getFieldType(g, field)
gotype := GetFieldType(g, field)
tags := structTags{
"binapi": fieldTagBinapi(field),
"json": fieldTagJson(field),
Expand Down Expand Up @@ -520,7 +519,7 @@ func genMessageMethods(g *GenFile, msg *Message) {
if msg.msgType == msgTypeReply || msg.msgType == msgTypeEvent {
// GetRetVal method
g.P("func (m *", msg.GoIdent.GoName, ") GetRetVal() error {")
if getRetvalField(msg) != nil {
if GetRetvalField(msg) != nil {
g.P(" return api.RetvalToVPPApiError(int32(m.Retval))")
} else {
g.P(" return nil")
Expand Down
36 changes: 12 additions & 24 deletions binapigen/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,19 @@ import (
. "github.com/onsi/gomega"

"go.fd.io/govpp/binapi/ip_types"
"go.fd.io/govpp/binapigen/vppapi"
)

const testOutputDir = "test_output_dir"

func GenerateFromFile(file string, opts Options) error {
apifile, err := vppapi.ParseFile(file)
func GenerateFromFile(filename string) error {
os.Setenv(VPPVersionEnvVar, "test-version")
gen, err := New(Options{
OutputDir: testOutputDir,
ApiDir: filename,
})
if err != nil {
return err
}
gen, err := New(opts, []*vppapi.File{apifile}, nil)
if err != nil {
return err
}
for _, file := range gen.Files {
if !file.Generate {
continue
}
GenerateAPI(gen, file)
}
if err = gen.Generate(); err != nil {
return err
}
Expand All @@ -53,8 +46,7 @@ func TestGenerateFromFileACL(t *testing.T) {
// remove directory created during test
defer os.RemoveAll(testOutputDir)

opts := Options{OutputDir: testOutputDir}
err := GenerateFromFile("vppapi/testdata/acl.api.json", opts)
err := GenerateFromFile("vppapi/testdata/acl.api.json")
Expect(err).ShouldNot(HaveOccurred())
fileInfo, err := os.Stat(testOutputDir + "/acl/acl.ba.go")
Expect(err).ShouldNot(HaveOccurred())
Expand All @@ -68,8 +60,7 @@ func TestGenerateFromFileIP(t *testing.T) {
// remove directory created during test
defer os.RemoveAll(testOutputDir)

opts := Options{OutputDir: testOutputDir}
err := GenerateFromFile("vppapi/testdata/ip.api.json", opts)
err := GenerateFromFile("vppapi/testdata/ip.api.json")
Expect(err).ShouldNot(HaveOccurred())
fileInfo, err := os.Stat(testOutputDir + "/ip/ip.ba.go")
Expect(err).ShouldNot(HaveOccurred())
Expand All @@ -80,17 +71,15 @@ func TestGenerateFromFileIP(t *testing.T) {
func TestGenerateFromFileInputError(t *testing.T) {
RegisterTestingT(t)

opts := Options{OutputDir: testOutputDir}
err := GenerateFromFile("vppapi/testdata/nonexisting.json", opts)
err := GenerateFromFile("vppapi/testdata/nonexisting.json")
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("unsupported"))
Expect(err.Error()).To(ContainSubstring("vppapi/testdata/nonexisting.json does not exist"))
}

func TestGenerateFromFileReadJsonError(t *testing.T) {
RegisterTestingT(t)

opts := Options{OutputDir: testOutputDir}
err := GenerateFromFile("vppapi/testdata/input-read-json-error.json", opts)
err := GenerateFromFile("vppapi/testdata/input-read-json-error.json")
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("unsupported"))
}
Expand All @@ -106,8 +95,7 @@ func TestGenerateFromFileGeneratePackageError(t *testing.T) {
os.RemoveAll(testOutputDir)
}()

opts := Options{OutputDir: testOutputDir}
err := GenerateFromFile("vppapi/testdata/input-generate-error.json", opts)
err := GenerateFromFile("vppapi/testdata/input-generate-error.json")
Expect(err).Should(HaveOccurred())
}

Expand Down
Loading

0 comments on commit 62f5161

Please sign in to comment.