X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=cmd%2Fbinapi-generator%2Fmain.go;h=85ef0eb42a417f2f4b096f4af05ef398883f28a8;hb=e9567fa8c853dda16c54afbd2ba99b7263fa37f1;hp=b73a6993e41475e85db81ab57c982a847921afa4;hpb=08ddeac03fd3832d44a3dfb48ee85ecd95d2b388;p=govpp.git diff --git a/cmd/binapi-generator/main.go b/cmd/binapi-generator/main.go index b73a699..85ef0eb 100644 --- a/cmd/binapi-generator/main.go +++ b/cmd/binapi-generator/main.go @@ -15,170 +15,105 @@ package main import ( - "bufio" - "encoding/json" "flag" "fmt" - "io/ioutil" "os" - "os/exec" "path/filepath" "strings" + "unicode" - "github.com/bennyscetbun/jsongo" "github.com/sirupsen/logrus" -) -var ( - inputFile = flag.String("input-file", "", "Input JSON file.") - inputDir = flag.String("input-dir", ".", "Input directory with JSON files.") - outputDir = flag.String("output-dir", ".", "Output directory where package folders will be generated.") - includeAPIVer = flag.Bool("include-apiver", false, "Whether to include VlAPIVersion in generated file.") - debug = flag.Bool("debug", false, "Turn on debug mode.") - continueOnError = flag.Bool("continue-onerror", false, "Wheter to continue with next file on error.") + "git.fd.io/govpp.git/binapigen" + "git.fd.io/govpp.git/binapigen/vppapi" + "git.fd.io/govpp.git/version" ) func init() { - flag.Parse() - if *debug { - logrus.SetLevel(logrus.DebugLevel) - } -} - -func logf(f string, v ...interface{}) { - if *debug { - logrus.Debugf(f, v...) + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "USAGE\n") + fmt.Fprintf(os.Stderr, " Parse API_FILES and generate Go bindings\n") + fmt.Fprintf(os.Stderr, " Provide API_FILES by file name, or with full path including extension.\n") + fmt.Fprintf(os.Stderr, " %s [OPTION] API_FILES\n\n", os.Args[0]) + fmt.Fprintf(os.Stderr, "OPTIONS\n") + flag.PrintDefaults() + fmt.Fprintf(os.Stderr, "\nEXAMPLES:\n") + fmt.Fprintf(os.Stderr, " %s \\\n", os.Args[0]) + fmt.Fprintf(os.Stderr, " --input-dir=$VPP/build-root/install-vpp-native/vpp/share/vpp/api/ \\\n") + fmt.Fprintf(os.Stderr, " --output-dir=~/output \\\n") + fmt.Fprintf(os.Stderr, " interface ip\n") + fmt.Fprintf(os.Stderr, " Assuming --input-dir contains interface.api.json & ip.api.json\n") } } -var log = logrus.Logger{ - Level: logrus.InfoLevel, - Formatter: &logrus.TextFormatter{}, - Out: os.Stdout, +func printErrorAndExit(msg string) { + fmt.Fprintf(os.Stderr, "Error: %s\n\n", msg) + flag.Usage() + os.Exit(1) } func main() { - if *inputFile == "" && *inputDir == "" { - fmt.Fprintln(os.Stderr, "ERROR: input-file or input-dir must be specified") - os.Exit(1) - } - - if *inputFile != "" { - // process one input file - if err := generateFromFile(*inputFile, *outputDir); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: code generation from %s failed: %v\n", *inputFile, err) - os.Exit(1) - } - } else { - // process all files in specified directory - files, err := getInputFiles(*inputDir) - if err != nil { - fmt.Fprintf(os.Stderr, "ERROR: code generation failed: %v\n", err) - os.Exit(1) - } - for _, file := range files { - if err := generateFromFile(file, *outputDir); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: code generation from %s failed: %v\n", file, err) - if *continueOnError { - continue - } - os.Exit(1) - } - } - } -} - -// getInputFiles returns all input files located in specified directory -func getInputFiles(inputDir string) (res []string, err error) { - files, err := ioutil.ReadDir(inputDir) - if err != nil { - return nil, fmt.Errorf("reading directory %s failed: %v", inputDir, err) - } - for _, f := range files { - if strings.HasSuffix(f.Name(), inputFileExt) { - res = append(res, filepath.Join(inputDir, f.Name())) - } - } - return res, nil -} - -// generateFromFile generates Go package from one input JSON file -func generateFromFile(inputFile, outputDir string) error { - logf("generating from file: %q", inputFile) - defer logf("--------------------------------------") - - ctx, err := getContext(inputFile, outputDir) - if err != nil { - return err - } - - // read input file contents - ctx.inputData, err = readFile(inputFile) - if err != nil { - return err - } - // parse JSON data into objects - jsonRoot, err := parseJSON(ctx.inputData) - if err != nil { - return err - } - ctx.packageData, err = parsePackage(ctx, jsonRoot) - if err != nil { - return err - } - - // create output directory - packageDir := filepath.Dir(ctx.outputFile) - if err := os.MkdirAll(packageDir, 0777); err != nil { - return fmt.Errorf("creating output directory %q failed: %v", packageDir, err) - } - // open output file - f, err := os.Create(ctx.outputFile) - if err != nil { - return fmt.Errorf("creating output file %q failed: %v", ctx.outputFile, err) - } - defer f.Close() + var ( + theApiDir = flag.String("input-dir", vppapi.DefaultDir, "Input directory containing API files. (e.g. )") + theOutputDir = flag.String("output-dir", "binapi", "Output directory where code will be generated.") + importPrefix = flag.String("import-prefix", "", "Prefix imports in the generated go code. \nE.g. other API Files (e.g. api_file.ba.go) will be imported with :\nimport (\n api_file \"/api_file\"\n)") + generatorPlugins = flag.String("gen", "rpc", "List of generator plugins to run for files.") + theInputFile = flag.String("input-file", "", "DEPRECATED: Use program arguments to define files to generate.") + + printVersion = flag.Bool("version", false, "Prints version and exits.") + debugLog = flag.Bool("debug", false, "Enable verbose logging.") + noVersionInfo = flag.Bool("no-version-info", false, "Disable version info in generated files.") + noSourcePathInfo = flag.Bool("no-source-path-info", false, "Disable source path info in generated files.") + ) + flag.Parse() - // generate Go package code - w := bufio.NewWriter(f) - if err := generatePackage(ctx, w); err != nil { - return err + if *printVersion { + fmt.Fprintln(os.Stdout, version.Info()) + os.Exit(0) } - // go format the output file (fail probably means the output is not compilable) - cmd := exec.Command("gofmt", "-w", ctx.outputFile) - if output, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("gofmt failed: %v\n%s", err, string(output)) + if *debugLog { + logrus.SetLevel(logrus.DebugLevel) } - // count number of lines in generated output file - cmd = exec.Command("wc", "-l", ctx.outputFile) - if output, err := cmd.CombinedOutput(); err != nil { - log.Warnf("wc command failed: %v\n%s", err, string(output)) + var filesToGenerate []string + if *theInputFile != "" { + if flag.NArg() > 0 { + printErrorAndExit("input-file cannot be combined with files to generate in arguments") + } + filesToGenerate = append(filesToGenerate, *theInputFile) } else { - logf("generated lines: %s", output) + filesToGenerate = append(filesToGenerate, flag.Args()...) } - return nil -} - -// readFile reads content of a file into memory -func readFile(inputFile string) ([]byte, error) { - inputData, err := ioutil.ReadFile(inputFile) - if err != nil { - return nil, fmt.Errorf("reading data from file failed: %v", err) + opts := binapigen.Options{ + ImportPrefix: *importPrefix, + OutputDir: *theOutputDir, + NoVersionInfo: *noVersionInfo, + NoSourcePathInfo: *noSourcePathInfo, } - - return inputData, nil -} - -// parseJSON parses a JSON data into an in-memory tree -func parseJSON(inputData []byte) (*jsongo.JSONNode, error) { - root := jsongo.JSONNode{} - - if err := json.Unmarshal(inputData, &root); err != nil { - return nil, fmt.Errorf("unmarshalling JSON failed: %v", err) + if opts.OutputDir == "binapi" { + if wd, _ := os.Getwd(); filepath.Base(wd) == "binapi" { + opts.OutputDir = "." + } } + apiDir := *theApiDir + genPlugins := strings.FieldsFunc(*generatorPlugins, func(c rune) bool { + return !unicode.IsLetter(c) && !unicode.IsNumber(c) + }) - return &root, nil + binapigen.Run(apiDir, filesToGenerate, opts, func(gen *binapigen.Generator) error { + for _, file := range gen.Files { + if !file.Generate { + continue + } + binapigen.GenerateAPI(gen, file) + for _, p := range genPlugins { + if err := binapigen.RunPlugin(p, gen, file); err != nil { + return err + } + } + } + return nil + }) }