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 JSON file.")
34 inputDir = flag.String("input-dir", ".", "Input directory with JSON files.")
35 outputDir = flag.String("output-dir", ".", "Output directory where package folders will be generated.")
36 includeAPIVer = flag.Bool("include-apiver", false, "Whether to include VlAPIVersion in generated file.")
37 debug = flag.Bool("debug", false, "Turn on debug mode.")
38 continueOnError = flag.Bool("continue-onerror", false, "Wheter to continue with next file on error.")
44 logrus.SetLevel(logrus.DebugLevel)
48 func logf(f string, v ...interface{}) {
50 logrus.Debugf(f, v...)
54 var log = logrus.Logger{
55 Level: logrus.InfoLevel,
56 Formatter: &logrus.TextFormatter{},
61 if *inputFile == "" && *inputDir == "" {
62 fmt.Fprintln(os.Stderr, "ERROR: input-file or input-dir must be specified")
67 // process one input file
68 if err := generateFromFile(*inputFile, *outputDir); err != nil {
69 fmt.Fprintf(os.Stderr, "ERROR: code generation from %s failed: %v\n", *inputFile, err)
73 // process all files in specified directory
74 files, err := getInputFiles(*inputDir)
76 fmt.Fprintf(os.Stderr, "ERROR: code generation failed: %v\n", err)
79 for _, file := range files {
80 if err := generateFromFile(file, *outputDir); err != nil {
81 fmt.Fprintf(os.Stderr, "ERROR: code generation from %s failed: %v\n", file, err)
91 // getInputFiles returns all input files located in specified directory
92 func getInputFiles(inputDir string) (res []string, err error) {
93 files, err := ioutil.ReadDir(inputDir)
95 return nil, fmt.Errorf("reading directory %s failed: %v", inputDir, err)
97 for _, f := range files {
98 if strings.HasSuffix(f.Name(), inputFileExt) {
99 res = append(res, filepath.Join(inputDir, f.Name()))
105 // generateFromFile generates Go package from one input JSON file
106 func generateFromFile(inputFile, outputDir string) error {
107 logf("generating from file: %q", inputFile)
108 defer logf("--------------------------------------")
110 ctx, err := getContext(inputFile, outputDir)
115 // read input file contents
116 ctx.inputData, err = readFile(inputFile)
120 // parse JSON data into objects
121 jsonRoot, err := parseJSON(ctx.inputData)
125 ctx.packageData, err = parsePackage(ctx, jsonRoot)
130 // create output directory
131 packageDir := filepath.Dir(ctx.outputFile)
132 if err := os.MkdirAll(packageDir, 0777); err != nil {
133 return fmt.Errorf("creating output directory %q failed: %v", packageDir, err)
136 f, err := os.Create(ctx.outputFile)
138 return fmt.Errorf("creating output file %q failed: %v", ctx.outputFile, err)
142 // generate Go package code
143 w := bufio.NewWriter(f)
144 if err := generatePackage(ctx, w); err != nil {
148 // go format the output file (fail probably means the output is not compilable)
149 cmd := exec.Command("gofmt", "-w", ctx.outputFile)
150 if output, err := cmd.CombinedOutput(); err != nil {
151 return fmt.Errorf("gofmt failed: %v\n%s", err, string(output))
154 // count number of lines in generated output file
155 cmd = exec.Command("wc", "-l", ctx.outputFile)
156 if output, err := cmd.CombinedOutput(); err != nil {
157 log.Warnf("wc command failed: %v\n%s", err, string(output))
159 logf("generated lines: %s", output)
165 // readFile reads content of a file into memory
166 func readFile(inputFile string) ([]byte, error) {
167 inputData, err := ioutil.ReadFile(inputFile)
169 return nil, fmt.Errorf("reading data from file failed: %v", err)
172 return inputData, nil
175 // parseJSON parses a JSON data into an in-memory tree
176 func parseJSON(inputData []byte) (*jsongo.JSONNode, error) {
177 root := jsongo.JSONNode{}
179 if err := json.Unmarshal(inputData, &root); err != nil {
180 return nil, fmt.Errorf("unmarshalling JSON failed: %v", err)