diff --git a/gen/generate-components/main.go b/gen/generate-components/main.go index 77391e3d3..d653d7be8 100644 --- a/gen/generate-components/main.go +++ b/gen/generate-components/main.go @@ -66,13 +66,13 @@ func genGroupDeclarations(name string, fields []datadictionary.MessagePart) (fil return } -func genHeader(header *datadictionary.MessageDef) { +func genHeader(header *datadictionary.MessageDef) error { writer := new(bytes.Buffer) if err := gen.WritePackage(writer, pkg); err != nil { - panic(err) + return err } if err := gen.WriteComponentImports(writer, pkg, header.Parts); err != nil { - panic(err) + return err } fileOut := writer.String() @@ -84,20 +84,20 @@ func genHeader(header *datadictionary.MessageDef) { writer = new(bytes.Buffer) if err := gen.WriteFieldSetters(writer, "Header", header.Parts); err != nil { - panic(err) + return err } fileOut += writer.String() - gen.WriteFile(path.Join(pkg, "header.go"), fileOut) + return gen.WriteFile(path.Join(pkg, "header.go"), fileOut) } -func genTrailer(trailer *datadictionary.MessageDef) { +func genTrailer(trailer *datadictionary.MessageDef) error { writer := new(bytes.Buffer) if err := gen.WritePackage(writer, pkg); err != nil { - panic(err) + return err } if err := gen.WriteComponentImports(writer, pkg, trailer.Parts); err != nil { - panic(err) + return err } fileOut := writer.String() @@ -108,24 +108,24 @@ func genTrailer(trailer *datadictionary.MessageDef) { writer = new(bytes.Buffer) if err := gen.WriteFieldSetters(writer, "Trailer", trailer.Parts); err != nil { - panic(err) + return err } fileOut += writer.String() - gen.WriteFile(path.Join(pkg, "trailer.go"), fileOut) + return gen.WriteFile(path.Join(pkg, "trailer.go"), fileOut) } -func genComponent(name string, component *datadictionary.ComponentType) { +func genComponent(name string, component *datadictionary.ComponentType) error { writer := new(bytes.Buffer) if err := gen.WritePackage(writer, strings.ToLower(name)); err != nil { - panic(err) + return err } if err := gen.WriteComponentImports(writer, pkg, component.Parts()); err != nil { - panic(err) + return err } if err := gen.WriteNewComponent(writer, *component); err != nil { - panic(err) + return err } fileOut := writer.String() @@ -136,7 +136,7 @@ func genComponent(name string, component *datadictionary.ComponentType) { fileOut += "}\n" fileOut += genComponentSetters(component) - gen.WriteFile(path.Join(pkg, strings.ToLower(name), name+".go"), fileOut) + return gen.WriteFile(path.Join(pkg, strings.ToLower(name), name+".go"), fileOut) } func genComponentSetters(component *datadictionary.ComponentType) string { @@ -173,15 +173,18 @@ func main() { panic(pkg + "/ is not a directory") } + var h gen.ErrorHandler switch pkg { //uses fixt11 header/trailer case "fix50", "fix50sp1", "fix50sp2": default: - genHeader(fixSpec.Header) - genTrailer(fixSpec.Trailer) + h.Handle(genHeader(fixSpec.Header)) + h.Handle(genTrailer(fixSpec.Trailer)) } for name, component := range fixSpec.ComponentTypes { - genComponent(name, component) + h.Handle(genComponent(name, component)) } + + os.Exit(h.ReturnCode) } diff --git a/gen/generate-fields/main.go b/gen/generate-fields/main.go index 1bd8924bb..7db39712f 100644 --- a/gen/generate-fields/main.go +++ b/gen/generate-fields/main.go @@ -22,7 +22,7 @@ func usage() { os.Exit(2) } -func genEnums() { +func genEnums() error { fileOut := "package enum\n" for _, fieldName := range sortedTags { @@ -48,10 +48,10 @@ func genEnums() { fileOut += ")\n" } - gen.WriteFile("enum/enums.go", fileOut) + return gen.WriteFile("enum/enums.go", fileOut) } -func genFields() { +func genFields() error { fileOut := "package field\n" fileOut += "import(\n" fileOut += "\"github.com/quickfixgo/quickfix\"\n" @@ -140,7 +140,7 @@ func genFields() { goType = "float64" default: - fmt.Printf("Unknown type '%v' for tag '%v'\n", field.Type, tag) + return fmt.Errorf("Unknown type '%v' for tag '%v'\n", field.Type, tag) } fileOut += fmt.Sprintf("//%vField is a %v field\n", field.Name(), field.Type) @@ -157,10 +157,10 @@ func genFields() { } } - gen.WriteFile("field/fields.go", fileOut) + return gen.WriteFile("field/fields.go", fileOut) } -func genTags() { +func genTags() error { fileOut := "package tag\n" fileOut += "import(\"github.com/quickfixgo/quickfix\")\n" @@ -170,7 +170,7 @@ func genTags() { } fileOut += ")\n" - gen.WriteFile("tag/tag_numbers.go", fileOut) + return gen.WriteFile("tag/tag_numbers.go", fileOut) } func main() { @@ -231,7 +231,9 @@ func main() { } sort.Strings(sortedTags) - genTags() - genFields() - genEnums() + var h gen.ErrorHandler + h.Handle(genTags()) + h.Handle(genFields()) + h.Handle(genEnums()) + os.Exit(h.ReturnCode) } diff --git a/gen/generate-messages/main.go b/gen/generate-messages/main.go index 63cc2b622..dea8dc15c 100644 --- a/gen/generate-messages/main.go +++ b/gen/generate-messages/main.go @@ -34,12 +34,6 @@ func initPackage() { } } -func genMessages() { - for _, m := range fixSpec.Messages { - genMessagePkg(m) - } -} - type group struct { parent string field *datadictionary.FieldDef @@ -138,16 +132,16 @@ func Route(router RouteOut) (string,string,quickfix.MessageRoute) { return fileOut } -func genMessagePkg(msg *datadictionary.MessageDef) { +func genMessagePkg(msg *datadictionary.MessageDef) error { pkgName := strings.ToLower(msg.Name) fileOut := fmt.Sprintf("//Package %v msg type = %v.\n", pkgName, msg.MsgType) writer := new(bytes.Buffer) if err := gen.WritePackage(writer, pkgName); err != nil { - panic(err) + return err } if err := gen.WriteMessageImports(writer, pkg, msg.Parts); err != nil { - panic(err) + return err } fileOut += writer.String() fileOut += genGroupDeclarations(msg) @@ -156,7 +150,7 @@ func genMessagePkg(msg *datadictionary.MessageDef) { fileOut += genMessageSetters(msg) fileOut += genMessageRoute(msg) - gen.WriteFile(path.Join(pkg, strings.ToLower(msg.Name), msg.Name+".go"), fileOut) + return gen.WriteFile(path.Join(pkg, strings.ToLower(msg.Name), msg.Name+".go"), fileOut) } func main() { @@ -193,5 +187,9 @@ func main() { panic(pkg + "/ is not a directory") } - genMessages() + var h gen.ErrorHandler + for _, m := range fixSpec.Messages { + h.Handle(genMessagePkg(m)) + } + os.Exit(h.ReturnCode) } diff --git a/gen/generate.go b/gen/generate.go index d19778d32..0a5f37762 100644 --- a/gen/generate.go +++ b/gen/generate.go @@ -12,38 +12,73 @@ import ( var ( tabWidth = 8 - printerMode printer.Mode + printerMode = printer.UseSpaces | printer.TabIndent ) -func init() { - initPrinterMode() +//ParseError indicates generated go source is invalid +type ParseError struct { + path string + err error } -func initPrinterMode() { - printerMode = printer.UseSpaces | printer.TabIndent +func (e ParseError) Error() string { + return fmt.Sprintf("Error parsing %v: %v", e.path, e.err) } -func WriteFile(filePath, fileOut string) { - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, "", fileOut, parser.ParseComments) - if err != nil { - fmt.Println("Failed to parse:\n", fileOut) +//ErrorHandler is a convenience struct for interpretting generation Errors +type ErrorHandler struct { + ReturnCode int +} + +//Handle interprets the generation error. Proceeds with setting returnCode, or panics depending on error type +func (h *ErrorHandler) Handle(err error) { + switch err := err.(type) { + case nil: + //do nothing + case ParseError: + fmt.Println(err) + h.ReturnCode = 1 + default: panic(err) } +} - ast.SortImports(fset, f) - - //create parentdir if it doesn't exist +func write(filePath string, fset *token.FileSet, f *ast.File) error { if parentdir := path.Dir(filePath); parentdir != "." { if err := os.MkdirAll(parentdir, os.ModePerm); err != nil { - panic(err) + return err } } - if file, err := os.Create(filePath); err == nil { - defer file.Close() - (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(file, fset, f) - } else { - panic(err) + file, err := os.Create(filePath) + if err != nil { + return err } + + ast.SortImports(fset, f) + err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(file, fset, f) + _ = file.Close() + return err +} + +//WriteFile parses the generated code in fileOut and writes the code out to filePath. +//Function performs some import clean up and gofmts the code before writing +//Returns ParseError if the generated source is invalid but is written to filePath +func WriteFile(filePath, fileOut string) error { + fset := token.NewFileSet() + f, pErr := parser.ParseFile(fset, "", fileOut, parser.ParseComments) + if f == nil { + return pErr + } + + //write out the file regardless of parseFile errors + if err := write(filePath, fset, f); err != nil { + return err + } + + if pErr != nil { + return ParseError{path: filePath, err: pErr} + } + + return nil }