1 // Copyright (c) 2018 Cisco and/or its affiliates.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
28 "github.com/bennyscetbun/jsongo"
29 "github.com/sirupsen/logrus"
33 inputFile = flag.String("input-file", "", "Input file with VPP API in JSON format.")
34 inputDir = flag.String("input-dir", ".", "Input directory with VPP API files in JSON format.")
35 outputDir = flag.String("output-dir", ".", "Output directory where package folders will be generated.")
36 includeAPIVer = flag.Bool("include-apiver", true, "Include APIVersion constant for each module.")
37 includeComments = flag.Bool("include-comments", false, "Include JSON API source in comments for each object.")
38 includeBinapiNames = flag.Bool("include-binapi-names", false, "Include binary API names in struct tag.")
39 includeServices = flag.Bool("include-services", false, "Include service interface with client implementation.")
40 continueOnError = flag.Bool("continue-onerror", false, "Continue with next file on error.")
41 debug = flag.Bool("debug", debugMode, "Enable debug mode.")
44 var debugMode = os.Getenv("DEBUG_BINAPI_GENERATOR") != ""
49 logrus.SetLevel(logrus.DebugLevel)
52 if *inputFile == "" && *inputDir == "" {
53 fmt.Fprintln(os.Stderr, "ERROR: input-file or input-dir must be specified")
58 // process one input file
59 if err := generateFromFile(*inputFile, *outputDir); err != nil {
60 fmt.Fprintf(os.Stderr, "ERROR: code generation from %s failed: %v\n", *inputFile, err)
64 // process all files in specified directory
65 files, err := getInputFiles(*inputDir)
67 fmt.Fprintf(os.Stderr, "ERROR: code generation failed: %v\n", err)
70 for _, file := range files {
71 if err := generateFromFile(file, *outputDir); err != nil {
72 fmt.Fprintf(os.Stderr, "ERROR: code generation from %s failed: %v\n", file, err)
82 // getInputFiles returns all input files located in specified directory
83 func getInputFiles(inputDir string) (res []string, err error) {
84 files, err := ioutil.ReadDir(inputDir)
86 return nil, fmt.Errorf("reading directory %s failed: %v", inputDir, err)
88 for _, f := range files {
89 if strings.HasSuffix(f.Name(), inputFileExt) {
90 res = append(res, filepath.Join(inputDir, f.Name()))
96 // generateFromFile generates Go package from one input JSON file
97 func generateFromFile(inputFile, outputDir string) error {
98 logf("generating from file: %s", inputFile)
99 logf("------------------------------------------------------------")
100 defer logf("------------------------------------------------------------")
102 ctx, err := getContext(inputFile, outputDir)
108 ctx.includeAPIVersion = *includeAPIVer
109 ctx.includeComments = *includeComments
110 ctx.includeBinapiNames = *includeBinapiNames
111 ctx.includeServices = *includeServices
113 // read API definition from input file
114 ctx.inputData, err = ioutil.ReadFile(ctx.inputFile)
116 return fmt.Errorf("reading input file %s failed: %v", ctx.inputFile, err)
119 // parse JSON data into objects
120 jsonRoot := new(jsongo.JSONNode)
121 if err := json.Unmarshal(ctx.inputData, jsonRoot); err != nil {
122 return fmt.Errorf("unmarshalling JSON failed: %v", err)
124 ctx.packageData, err = parsePackage(ctx, jsonRoot)
126 return fmt.Errorf("parsing package %s failed: %v", ctx.packageName, err)
129 // generate Go package code
131 if err := generatePackage(ctx, &buf); err != nil {
132 return fmt.Errorf("generating code for package %s failed: %v", ctx.packageName, err)
135 // create output directory
136 packageDir := filepath.Dir(ctx.outputFile)
137 if err := os.MkdirAll(packageDir, 06); err != nil {
138 return fmt.Errorf("creating output dir %s failed: %v", packageDir, err)
140 // write generated code to output file
141 if err := ioutil.WriteFile(ctx.outputFile, buf.Bytes(), 0666); err != nil {
142 return fmt.Errorf("writing to output file %s failed: %v", ctx.outputFile, err)
145 // go format the output file (fail probably means the output is not compilable)
146 cmd := exec.Command("gofmt", "-w", ctx.outputFile)
147 if output, err := cmd.CombinedOutput(); err != nil {
148 return fmt.Errorf("gofmt failed: %v\n%s", err, string(output))
151 // count number of lines in generated output file
152 cmd = exec.Command("wc", "-l", ctx.outputFile)
153 if output, err := cmd.CombinedOutput(); err != nil {
154 logf("wc command failed: %v\n%s", err, string(output))
156 logf("number of generated lines: %s", output)
162 func logf(f string, v ...interface{}) {
164 logrus.Debugf(f, v...)