import (
"fmt"
+ "io/ioutil"
"os"
+ "path"
"path/filepath"
+ "regexp"
+ "strings"
"github.com/sirupsen/logrus"
"git.fd.io/govpp.git/binapigen/vppapi"
)
-var debugMode = true
+type Options struct {
+ OutputDir string // output directory for generated files
+ ImportPrefix string // prefix for import paths
+ NoVersionInfo bool // disables generating version info
+}
-func logf(f string, v ...interface{}) {
- if debugMode {
- logrus.Debugf(f, v...)
+func Run(apiDir string, filesToGenerate []string, opts Options, f func(*Generator) error) {
+ if err := run(apiDir, filesToGenerate, opts, f); err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), err)
+ os.Exit(1)
}
}
-func GenerateBinapiFile(gen *Generator, file *File, outputDir string) *GenFile {
- packageDir := filepath.Join(outputDir, file.PackageName)
- filename := filepath.Join(packageDir, file.PackageName+outputFileExt)
+func run(apiDir string, filesToGenerate []string, opts Options, fn func(*Generator) error) error {
+ apifiles, err := vppapi.ParseDir(apiDir)
+ if err != nil {
+ return err
+ }
- g := gen.NewGenFile(filename)
- g.file = file
- g.packageDir = filepath.Join(outputDir, file.PackageName)
+ if opts.ImportPrefix == "" {
+ opts.ImportPrefix, err = resolveImportPath(opts.OutputDir)
+ if err != nil {
+ return fmt.Errorf("cannot resolve import path for output dir %s: %w", opts.OutputDir, err)
+ }
+ logrus.Infof("resolved import path prefix: %s", opts.ImportPrefix)
+ }
- generatePackage(g, &g.buf)
+ gen, err := New(opts, apifiles, filesToGenerate)
+ if err != nil {
+ return err
+ }
- return g
-}
+ gen.vppVersion = vppapi.ResolveVPPVersion(apiDir)
+ if gen.vppVersion == "" {
+ gen.vppVersion = "unknown"
+ }
-func GenerateRPC(gen *Generator, file *File, outputDir string) *GenFile {
- packageDir := filepath.Join(outputDir, file.PackageName)
- filename := filepath.Join(packageDir, file.PackageName+rpcFileSuffix+outputFileExt)
+ if fn == nil {
+ GenerateDefault(gen)
+ } else {
+ if err := fn(gen); err != nil {
+ return err
+ }
+ }
- g := gen.NewGenFile(filename)
- g.file = file
- g.packageDir = filepath.Join(outputDir, file.PackageName)
+ if err = gen.Generate(); err != nil {
+ return err
+ }
- generatePackageRPC(g, &g.buf)
+ return nil
+}
- return g
+func GenerateDefault(gen *Generator) {
+ for _, file := range gen.Files {
+ if !file.Generate {
+ continue
+ }
+ GenerateAPI(gen, file)
+ GenerateRPC(gen, file)
+ }
}
-func Run(apiDir string, opts Options, f func(*Generator) error) {
- if err := run(apiDir, opts, f); err != nil {
- fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), err)
- os.Exit(1)
+var Logger = logrus.New()
+
+func init() {
+ if debug := os.Getenv("DEBUG_GOVPP"); strings.Contains(debug, "binapigen") {
+ Logger.SetLevel(logrus.DebugLevel)
+ logrus.SetLevel(logrus.DebugLevel)
}
}
-func run(apiDir string, opts Options, f func(*Generator) error) error {
- // parse API files
- apifiles, err := vppapi.ParseDir(apiDir)
+func logf(f string, v ...interface{}) {
+ Logger.Debugf(f, v...)
+}
+
+// resolveImportPath tries to resolve import path for a directory.
+func resolveImportPath(dir string) (string, error) {
+ absPath, err := filepath.Abs(dir)
if err != nil {
- return err
+ return "", err
}
-
- g, err := New(opts, apifiles)
+ modRoot := findGoModuleRoot(absPath)
+ if modRoot == "" {
+ return "", err
+ }
+ modPath, err := readModulePath(path.Join(modRoot, "go.mod"))
if err != nil {
- return err
+ return "", err
}
-
- if err := f(g); err != nil {
- return err
+ relDir, err := filepath.Rel(modRoot, absPath)
+ if err != nil {
+ return "", err
}
+ return filepath.Join(modPath, relDir), nil
+}
- if err = g.Generate(); err != nil {
- return err
+// findGoModuleRoot looks for enclosing Go module.
+func findGoModuleRoot(dir string) (root string) {
+ dir = filepath.Clean(dir)
+ for {
+ if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
+ return dir
+ }
+ d := filepath.Dir(dir)
+ if d == dir {
+ break
+ }
+ dir = d
}
+ return ""
+}
- return nil
+var modulePathRE = regexp.MustCompile(`module[ \t]+([^ \t\r\n]+)`)
+
+// readModulePath reads module path from go.mod file.
+func readModulePath(gomod string) (string, error) {
+ data, err := ioutil.ReadFile(gomod)
+ if err != nil {
+ return "", err
+ }
+ m := modulePathRE.FindSubmatch(data)
+ if m == nil {
+ return "", err
+ }
+ return string(m[1]), nil
}