Skip to content
This repository was archived by the owner on Jan 18, 2026. It is now read-only.

Commit 015449d

Browse files
authored
feat: add stdout output support to avrogen (#302)
1 parent 22b43a9 commit 015449d

3 files changed

Lines changed: 39 additions & 19 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ Example usage assuming there's a valid schema in `in.avsc`:
176176
avrogen -pkg avro -o bla.go -tags json:snake,yaml:upper-camel in.avsc
177177
```
178178

179+
**Tip:** Omit `-o FILE` to dump the generated Go structs to stdout instead of a file.
180+
179181
Check the options and usage with `-h`:
180182

181183
```shell

cmd/avrogen/main.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ type config struct {
2323
}
2424

2525
func main() {
26-
os.Exit(realMain(os.Args, os.Stderr))
26+
os.Exit(realMain(os.Args, os.Stderr, os.Stdout))
2727
}
2828

29-
func realMain(args []string, out io.Writer) int {
29+
func realMain(args []string, out, dumpout io.Writer) int {
3030
var cfg config
3131
flgs := flag.NewFlagSet("avrogen", flag.ExitOnError)
3232
flgs.SetOutput(out)
3333
flgs.StringVar(&cfg.Pkg, "pkg", "", "The package name of the output file.")
34-
flgs.StringVar(&cfg.Out, "o", "", "The output file path.")
34+
flgs.StringVar(&cfg.Out, "o", "", "The output file path to write to instead of stdout.")
3535
flgs.StringVar(&cfg.Tags, "tags", "", "The additional field tags <tag-name>:{snake|camel|upper-camel|kebab}>[,...]")
3636
flgs.BoolVar(&cfg.FullName, "fullname", false, "Use the full name of the Record schema to create the struct name.")
3737
flgs.BoolVar(&cfg.Encoders, "encoders", false, "Generate encoders for the structs.")
@@ -75,13 +75,27 @@ func realMain(args []string, out io.Writer) int {
7575
}
7676
formatted, err := format.Source(buf.Bytes())
7777
if err != nil {
78-
_, _ = fmt.Fprintf(out, "Error: could format code: %v\n", err)
78+
_, _ = fmt.Fprintf(out, "Error: could not format code: %v\n", err)
7979
return 3
8080
}
81-
if err = os.WriteFile(cfg.Out, formatted, 0o600); err != nil {
82-
_, _ = fmt.Fprintf(out, "Error: could write file: %v\n", err)
81+
82+
writer := dumpout
83+
if cfg.Out != "" {
84+
file, err := os.Create(cfg.Out)
85+
if err != nil {
86+
_, _ = fmt.Fprintf(out, "Error: could not create output file: %v\n", err)
87+
return 4
88+
}
89+
defer func() { _ = file.Close() }()
90+
91+
writer = file
92+
}
93+
94+
if _, err := writer.Write(formatted); err != nil {
95+
_, _ = fmt.Fprintf(out, "Error: could not write code: %v\n", err)
8396
return 4
8497
}
98+
8599
return 0
86100
}
87101

@@ -94,10 +108,6 @@ func validateOpts(nargs int, cfg config) error {
94108
return fmt.Errorf("a package is required")
95109
}
96110

97-
if cfg.Out == "" {
98-
return fmt.Errorf("an output file is reqired")
99-
}
100-
101111
return nil
102112
}
103113

cmd/avrogen/main_test.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"bytes"
45
"flag"
56
"io"
67
"os"
@@ -34,11 +35,6 @@ func TestAvroGen_RequiredFlags(t *testing.T) {
3435
args: []string{"avrogen", "-o", "some/file", "schema.avsc"},
3536
wantErr: true,
3637
},
37-
{
38-
name: "validates output file is set",
39-
args: []string{"avrogen", "-pkg", "test", "schema.avsc"},
40-
wantErr: true,
41-
},
4238
{
4339
name: "validates tag format are valid",
4440
args: []string{"avrogen", "-o", "some/file", "-pkg", "test", "-tags", "snake", "schema.avsc"},
@@ -59,7 +55,7 @@ func TestAvroGen_RequiredFlags(t *testing.T) {
5955
for _, test := range tests {
6056
test := test
6157
t.Run(test.name, func(t *testing.T) {
62-
got := realMain(test.args, io.Discard)
58+
got := realMain(test.args, io.Discard, io.Discard)
6359

6460
if !test.wantErr {
6561
assert.Equal(t, 0, got)
@@ -71,14 +67,26 @@ func TestAvroGen_RequiredFlags(t *testing.T) {
7167
}
7268
}
7369

70+
func TestAvroGen_GeneratesSchemaStdout(t *testing.T) {
71+
var buf bytes.Buffer
72+
73+
args := []string{"avrogen", "-pkg", "testpkg", "testdata/schema.avsc"}
74+
gotCode := realMain(args, io.Discard, &buf)
75+
require.Equal(t, 0, gotCode)
76+
77+
want, err := os.ReadFile("testdata/golden.go")
78+
require.NoError(t, err)
79+
assert.Equal(t, want, buf.Bytes())
80+
}
81+
7482
func TestAvroGen_GeneratesSchema(t *testing.T) {
7583
path, err := os.MkdirTemp("./", "avrogen")
7684
require.NoError(t, err)
7785
t.Cleanup(func() { _ = os.RemoveAll(path) })
7886

7987
file := filepath.Join(path, "test.go")
8088
args := []string{"avrogen", "-pkg", "testpkg", "-o", file, "testdata/schema.avsc"}
81-
gotCode := realMain(args, io.Discard)
89+
gotCode := realMain(args, io.Discard, io.Discard)
8290
require.Equal(t, 0, gotCode)
8391

8492
got, err := os.ReadFile(file)
@@ -101,7 +109,7 @@ func TestAvroGen_GeneratesSchemaWithFullname(t *testing.T) {
101109

102110
file := filepath.Join(path, "test.go")
103111
args := []string{"avrogen", "-pkg", "testpkg", "-o", file, "-fullname", "testdata/schema.avsc"}
104-
gotCode := realMain(args, io.Discard)
112+
gotCode := realMain(args, io.Discard, io.Discard)
105113
require.Equal(t, 0, gotCode)
106114

107115
got, err := os.ReadFile(file)
@@ -124,7 +132,7 @@ func TestAvroGen_GeneratesSchemaWithEncoders(t *testing.T) {
124132

125133
file := filepath.Join(path, "test.go")
126134
args := []string{"avrogen", "-pkg", "testpkg", "-o", file, "-encoders", "testdata/schema.avsc"}
127-
gotCode := realMain(args, io.Discard)
135+
gotCode := realMain(args, io.Discard, io.Discard)
128136
require.Equal(t, 0, gotCode)
129137

130138
got, err := os.ReadFile(file)

0 commit comments

Comments
 (0)