diff --git a/cmd/avrogen/main.go b/cmd/avrogen/main.go index e2a70d53..a2adfb4d 100644 --- a/cmd/avrogen/main.go +++ b/cmd/avrogen/main.go @@ -19,6 +19,7 @@ type config struct { TemplateFileName string Pkg string + PkgDoc string Out string Tags string FullName bool @@ -36,6 +37,7 @@ func realMain(args []string, stdout, stderr io.Writer) int { flgs := flag.NewFlagSet("avrogen", flag.ExitOnError) flgs.SetOutput(stderr) flgs.StringVar(&cfg.Pkg, "pkg", "", "The package name of the output file.") + flgs.StringVar(&cfg.PkgDoc, "pkgdoc", "", "The package doc comment to output.") flgs.StringVar(&cfg.Out, "o", "", "The output file path to write to instead of stdout.") flgs.StringVar(&cfg.Tags, "tags", "", "The additional field tags :{snake|camel|upper-camel|kebab}>[,...]") flgs.BoolVar(&cfg.FullName, "fullname", false, "Use the full name of the Record schema to create the struct name.") @@ -77,6 +79,7 @@ func realMain(args []string, stdout, stderr io.Writer) int { opts := []gen.OptsFunc{ gen.WithFullName(cfg.FullName), + gen.WithPackageDoc(cfg.PkgDoc), gen.WithEncoders(cfg.Encoders), gen.WithInitialisms(initialisms), gen.WithTemplate(string(template)), diff --git a/cmd/avrogen/main_test.go b/cmd/avrogen/main_test.go index 31f089fb..4788be0d 100644 --- a/cmd/avrogen/main_test.go +++ b/cmd/avrogen/main_test.go @@ -65,7 +65,7 @@ func TestAvroGen_RequiredFlags(t *testing.T) { func TestAvroGen_GeneratesSchemaStdout(t *testing.T) { var buf bytes.Buffer - args := []string{"avrogen", "-pkg", "testpkg", "testdata/schema.avsc"} + args := []string{"avrogen", "-pkg", "testpkg", "-pkgdoc", "package testpkg is generated from schema.avsc", "testdata/schema.avsc"} gotCode := realMain(args, &buf, io.Discard) require.Equal(t, 0, gotCode) @@ -80,7 +80,7 @@ func TestAvroGen_GeneratesSchema(t *testing.T) { t.Cleanup(func() { _ = os.RemoveAll(path) }) file := filepath.Join(path, "test.go") - args := []string{"avrogen", "-pkg", "testpkg", "-o", file, "testdata/schema.avsc"} + args := []string{"avrogen", "-o", file, "-pkg", "testpkg", "-pkgdoc", "package testpkg is generated from schema.avsc", "testdata/schema.avsc"} gotCode := realMain(args, io.Discard, io.Discard) require.Equal(t, 0, gotCode) diff --git a/cmd/avrogen/testdata/golden.go b/cmd/avrogen/testdata/golden.go index cf6eda1a..e76aef65 100644 --- a/cmd/avrogen/testdata/golden.go +++ b/cmd/avrogen/testdata/golden.go @@ -1,9 +1,11 @@ +// package testpkg is generated from schema.avsc package testpkg -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. -// Test is a generated struct. +// Test is a test struct type Test struct { + // SomeString is a string SomeString string `avro:"someString"` SomeInt int `avro:"someInt"` } diff --git a/cmd/avrogen/testdata/golden_encoders.go b/cmd/avrogen/testdata/golden_encoders.go index 2cd13084..1c5b2fdb 100644 --- a/cmd/avrogen/testdata/golden_encoders.go +++ b/cmd/avrogen/testdata/golden_encoders.go @@ -1,13 +1,14 @@ package testpkg -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. import ( "github.com/hamba/avro/v2" ) -// Test is a generated struct. +// Test is a test struct type Test struct { + // SomeString is a string SomeString string `avro:"someString"` SomeInt int `avro:"someInt"` } diff --git a/cmd/avrogen/testdata/golden_fullname.go b/cmd/avrogen/testdata/golden_fullname.go index 43b51d39..bdec65cd 100644 --- a/cmd/avrogen/testdata/golden_fullname.go +++ b/cmd/avrogen/testdata/golden_fullname.go @@ -1,9 +1,10 @@ package testpkg -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. -// ABTest is a generated struct. +// Test is a test struct type ABTest struct { + // SomeString is a string SomeString string `avro:"someString"` SomeInt int `avro:"someInt"` } diff --git a/cmd/avrogen/testdata/golden_stricttypes.go b/cmd/avrogen/testdata/golden_stricttypes.go index 49f3dcbc..1e721b3e 100644 --- a/cmd/avrogen/testdata/golden_stricttypes.go +++ b/cmd/avrogen/testdata/golden_stricttypes.go @@ -1,9 +1,10 @@ package testpkg -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. -// Test is a generated struct. +// Test is a test struct type Test struct { + // SomeString is a string SomeString string `avro:"someString"` SomeInt int32 `avro:"someInt"` } diff --git a/cmd/avrogen/testdata/schema.avsc b/cmd/avrogen/testdata/schema.avsc index 8196629b..8754f395 100644 --- a/cmd/avrogen/testdata/schema.avsc +++ b/cmd/avrogen/testdata/schema.avsc @@ -2,8 +2,9 @@ "type": "record", "name": "test", "namespace": "a.b", + "doc": "Test is a test struct", "fields": [ - { "name": "someString", "type": "string" }, + { "name": "someString", "type": "string", "doc": "SomeString is a string" }, { "name": "someInt", "type": "int" } ] } \ No newline at end of file diff --git a/gen/gen.go b/gen/gen.go index 720d6201..9a785522 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -147,10 +147,18 @@ func WithStrictTypes(b bool) OptsFunc { } } +// WithPackageDoc configures the generator to use output the given text as a package doc comment. +func WithPackageDoc(text string) OptsFunc { + return func(g *Generator) { + g.pkgdoc = text + } +} + // Generator generates Go structs from schemas. type Generator struct { template string pkg string + pkgdoc string tags map[string]TagStyle fullName bool encoders bool @@ -257,7 +265,7 @@ func (g *Generator) resolveRecordSchema(schema *avro.RecordSchema) string { typeName := g.resolveTypeName(schema) if !g.hasTypeDef(typeName) { - g.typedefs = append(g.typedefs, newType(typeName, fields, schema.String())) + g.typedefs = append(g.typedefs, newType(typeName, schema.Doc(), fields, schema.String())) } return typeName } @@ -319,12 +327,12 @@ func (g *Generator) resolveLogicalSchema(logicalType avro.LogicalType) string { return typ } -func (g *Generator) newField(name, typ, avroFieldDoc, avroFieldName string) field { +func (g *Generator) newField(name, typ, doc, avroFieldName string) field { return field{ Name: name, Type: typ, AvroFieldName: avroFieldName, - AvroFieldDoc: avroFieldDoc, + Doc: doc, Tags: g.tags, } } @@ -364,12 +372,14 @@ func (g *Generator) Write(w io.Writer) error { data := struct { WithEncoders bool PackageName string + PackageDoc string Imports []string ThirdPartyImports []string Typedefs []typedef }{ WithEncoders: g.encoders, PackageName: g.pkg, + PackageDoc: g.pkgdoc, Imports: append(g.imports, g.thirdPartyImports...), Typedefs: g.typedefs, } @@ -378,13 +388,15 @@ func (g *Generator) Write(w io.Writer) error { type typedef struct { Name string + Doc string Fields []field Schema string } -func newType(name string, fields []field, schema string) typedef { +func newType(name string, doc string, fields []field, schema string) typedef { return typedef{ Name: name, + Doc: doc, Fields: fields, Schema: schema, } @@ -393,7 +405,7 @@ func newType(name string, fields []field, schema string) typedef { type field struct { Name string Type string + Doc string AvroFieldName string - AvroFieldDoc string Tags map[string]TagStyle } diff --git a/gen/output_template.tmpl b/gen/output_template.tmpl index 94cbcf67..17a54119 100644 --- a/gen/output_template.tmpl +++ b/gen/output_template.tmpl @@ -1,6 +1,9 @@ +{{- if len .PackageDoc }} +// {{ .PackageDoc }} +{{- end }} package {{ .PackageName }} -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. {{- $encoders := .WithEncoders }} {{ if len .Imports }} @@ -12,10 +15,15 @@ package {{ .PackageName }} {{ end }} {{- range .Typedefs }} - // {{ .Name }} is a generated struct. + {{- if len .Doc }} + // {{ .Doc }} + {{- end}} type {{ .Name }} struct { {{- range .Fields }} {{- $f := . }} + {{- if len $f.Doc }} + // {{ $f.Doc }} + {{- end }} {{ .Name }} {{ .Type }} `avro:"{{ $f.AvroFieldName }}" {{- range $tag, $style := .Tags }} {{- " "}}{{ $tag }}:" diff --git a/gen/testdata/golden.avsc b/gen/testdata/golden.avsc index 5c2300e8..ea7e76d4 100644 --- a/gen/testdata/golden.avsc +++ b/gen/testdata/golden.avsc @@ -1,10 +1,12 @@ { "type": "record", "name": "test", + "doc": "Test represents a golden record", "namespace": "a.b", "fields": [ { "name": "aString", + "doc": "aString is just a string", "type": "string" }, { diff --git a/gen/testdata/golden.go b/gen/testdata/golden.go index 66297736..724b5d3b 100644 --- a/gen/testdata/golden.go +++ b/gen/testdata/golden.go @@ -1,6 +1,6 @@ package something -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. import ( "math/big" @@ -9,49 +9,42 @@ import ( "github.com/hamba/avro/v2" ) -// InnerRecord is a generated struct. type InnerRecord struct { InnerJustBytes []byte `avro:"innerJustBytes"` InnerPrimitiveNullableArrayUnion *[]string `avro:"innerPrimitiveNullableArrayUnion"` } -// RecordInMap is a generated struct. type RecordInMap struct { Name string `avro:"name"` } -// RecordInArray is a generated struct. type RecordInArray struct { AString string `avro:"aString"` } -// RecordInNullableUnion is a generated struct. type RecordInNullableUnion struct { AString string `avro:"aString"` } -// Record1InNonNullableUnion is a generated struct. type Record1InNonNullableUnion struct { AString string `avro:"aString"` } -// Record2InNonNullableUnion is a generated struct. type Record2InNonNullableUnion struct { AString string `avro:"aString"` } -// Record1InNullableUnion is a generated struct. type Record1InNullableUnion struct { AString string `avro:"aString"` } -// Record2InNullableUnion is a generated struct. type Record2InNullableUnion struct { AString string `avro:"aString"` } -// Test is a generated struct. +// Test represents a golden record type Test struct { + // aString is just a string AString string `avro:"aString"` ABoolean bool `avro:"aBoolean"` AnInt int `avro:"anInt"` diff --git a/gen/testdata/golden_encoders.go b/gen/testdata/golden_encoders.go index d3c0fbbb..5c8a8306 100644 --- a/gen/testdata/golden_encoders.go +++ b/gen/testdata/golden_encoders.go @@ -1,6 +1,6 @@ package something -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. import ( "math/big" @@ -9,7 +9,6 @@ import ( "github.com/hamba/avro/v2" ) -// InnerRecord is a generated struct. type InnerRecord struct { InnerJustBytes []byte `avro:"innerJustBytes"` InnerPrimitiveNullableArrayUnion *[]string `avro:"innerPrimitiveNullableArrayUnion"` @@ -32,7 +31,6 @@ func (o *InnerRecord) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// RecordInMap is a generated struct. type RecordInMap struct { Name string `avro:"name"` } @@ -54,7 +52,6 @@ func (o *RecordInMap) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// RecordInArray is a generated struct. type RecordInArray struct { AString string `avro:"aString"` } @@ -76,7 +73,6 @@ func (o *RecordInArray) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// RecordInNullableUnion is a generated struct. type RecordInNullableUnion struct { AString string `avro:"aString"` } @@ -98,7 +94,6 @@ func (o *RecordInNullableUnion) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// Record1InNonNullableUnion is a generated struct. type Record1InNonNullableUnion struct { AString string `avro:"aString"` } @@ -120,7 +115,6 @@ func (o *Record1InNonNullableUnion) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// Record2InNonNullableUnion is a generated struct. type Record2InNonNullableUnion struct { AString string `avro:"aString"` } @@ -142,7 +136,6 @@ func (o *Record2InNonNullableUnion) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// Record1InNullableUnion is a generated struct. type Record1InNullableUnion struct { AString string `avro:"aString"` } @@ -164,7 +157,6 @@ func (o *Record1InNullableUnion) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// Record2InNullableUnion is a generated struct. type Record2InNullableUnion struct { AString string `avro:"aString"` } @@ -186,8 +178,9 @@ func (o *Record2InNullableUnion) Marshal() ([]byte, error) { return avro.Marshal(o.Schema(), o) } -// Test is a generated struct. +// Test represents a golden record type Test struct { + // aString is just a string AString string `avro:"aString"` ABoolean bool `avro:"aBoolean"` AnInt int `avro:"anInt"` diff --git a/gen/testdata/golden_fullname.go b/gen/testdata/golden_fullname.go index cf81a16a..ef207ae6 100644 --- a/gen/testdata/golden_fullname.go +++ b/gen/testdata/golden_fullname.go @@ -1,6 +1,6 @@ package something -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. import ( "math/big" @@ -9,49 +9,42 @@ import ( "github.com/hamba/avro/v2" ) -// ACInnerRecord is a generated struct. type ACInnerRecord struct { InnerJustBytes []byte `avro:"innerJustBytes"` InnerPrimitiveNullableArrayUnion *[]string `avro:"innerPrimitiveNullableArrayUnion"` } -// ABRecordInMap is a generated struct. type ABRecordInMap struct { Name string `avro:"name"` } -// ABRecordInArray is a generated struct. type ABRecordInArray struct { AString string `avro:"aString"` } -// ABRecordInNullableUnion is a generated struct. type ABRecordInNullableUnion struct { AString string `avro:"aString"` } -// ABRecord1InNonNullableUnion is a generated struct. type ABRecord1InNonNullableUnion struct { AString string `avro:"aString"` } -// ABRecord2InNonNullableUnion is a generated struct. type ABRecord2InNonNullableUnion struct { AString string `avro:"aString"` } -// ABRecord1InNullableUnion is a generated struct. type ABRecord1InNullableUnion struct { AString string `avro:"aString"` } -// ABRecord2InNullableUnion is a generated struct. type ABRecord2InNullableUnion struct { AString string `avro:"aString"` } -// ABTest is a generated struct. +// Test represents a golden record type ABTest struct { + // aString is just a string AString string `avro:"aString"` ABoolean bool `avro:"aBoolean"` AnInt int `avro:"anInt"` diff --git a/gen/testdata/golden_multiple.go b/gen/testdata/golden_multiple.go index 34c3f082..dcbfd74c 100644 --- a/gen/testdata/golden_multiple.go +++ b/gen/testdata/golden_multiple.go @@ -1,14 +1,12 @@ package something -// Code generated by avro/gen. DO NOT EDIT. +// Code generated by avro/gen. DO NOT EDIT MANUALLY. -// TestUnionType is a generated struct. type TestUnionType struct { Field1 int64 `avro:"Field1"` Field2 int `avro:"Field2"` } -// TestMain is a generated struct. type TestMain struct { TestUnion *TestUnionType `avro:"TestUnion"` }