diff --git a/.github/workflows/avro.yaml b/.github/workflows/avro.yaml new file mode 100644 index 0000000..08b8cd8 --- /dev/null +++ b/.github/workflows/avro.yaml @@ -0,0 +1,87 @@ +name: avro + +on: + push: + branches: + - master + - main + paths: + - '**.go' + - 'go.*' + - Makefile + pull_request: + paths: + - '**.go' + - 'go.*' + - Makefile + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +env: + directory: "." + allow_lint_failure: "true" + +jobs: + test: + runs-on: ubuntu-22.04 +# container: +# image: ghcr.io/heetch/containers/heetch-base-testenv:1 + services: + registry: + image: lensesio/fast-data-dev:2.6.2-L0 + ports: + - 8081:8081 + steps: +# - name: Purge initial context +# run: | +# rm -rf $HOME/* $HOME/.* || true +# - name: Get BIN dir +# id: get-bin-dir +# shell: bash +# run: | +# echo bin_dir=.go-test-env >> $GITHUB_OUTPUT + - name: Checkout + uses: actions/checkout@v3 + - name: Set up env + uses: actions/setup-go@v3 + with: + cache: true + check-latest: true + cache-dependency-path: ${{ env.directory }}/go.sum + go-version-file: ${{ env.directory }}/go.mod + - name: Install Tools + shell: bash + run: | + go install github.com/mfridman/tparse@v0.12.1 + tgz=$(mktemp) + ARCH="$(uname -s)_$(uname -m)" + curl "https://github.com/cuelang/cue/releases/download/v0.0.15/cue_0.0.15_$ARCH.tar.gz" -L -o $tgz + (cd /usr/local/bin/ && tar xzf $tgz cue) + - name: "Lint: static" + id: lint-static + continue-on-error: true + uses: golangci/golangci-lint-action@v3 + with: + version: v1.52.2 + working-directory: ${{ env.directory }} + args: --timeout=5m + skip-cache: true + - name: "Lint: security" + id: lint-security + continue-on-error: true + working-directory: ${{ env.directory }} + run: | + go install golang.org/x/vuln/cmd/govulncheck@latest + govulncheck ./... + - name: Build + run: | + make build + - name: Unit tests + working-directory: ${{ env.directory }} + env: + CGO_ENABLED: "1" + KAFKA_REGISTRY_ADDR: 127.0.0.1:8081 + run: | + make test diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml deleted file mode 100644 index 37f4dde..0000000 --- a/.github/workflows/test.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# Code generated by github.com/heetch/cue-schema/github/workflow/generate. DO NOT EDIT. -jobs: - test: - runs-on: ${{ matrix.platform }} - # container: ubuntu:latest - services: - registry: - image: lensesio/fast-data-dev:2.6.2-L0 - ports: - - 8081:8081 - - # zookeeper: - # image: confluentinc/cp-zookeeper:5.4.1 - # ports: - # - 32181:32181 - # env: - # ZOOKEEPER_CLIENT_PORT: "32181" - # ZOOKEEPER_SERVER_ID: 1 - # ZOOKEEPER_TICK_TIME: "2000" - - # kafka: - # image: confluentinc/cp-kafka:5.4.1 - # env: - # KAFKA_BROKER_ID: "1" - # KAFKA_ZOOKEEPER_CONNECT: localhost:32181 - # KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://0.0.0.0:29092,PLAINTEXT_HOST://0.0.0.0:9092 - # KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - # KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT - # KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" - # KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 - # KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 - # ports: - # - 9092:9092 - # - 29092:29092 - - # schemaregistry: - # image: confluentinc/cp-schema-registry:5.4.1 - # ports: - # - 8081:8081 - # env: - # SCHEMA_REGISTRY_HOST_NAME: schemaregistry - # SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: localhost:32181 - # SCHEMA_REGISTRY_LISTENERS: http://0.0.0.0:8081 - # SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: PLAINTEXT://localhost:29092 - - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go }} - - name: Checkout code - uses: actions/checkout@v2 - # - name: Install curl gcc - # run: |- - # apt update - # apt install --yes curl gcc - - name: Test - env: - KAFKA_REGISTRY_ADDR: localhost:${{ job.services.registry.ports['8081'] }} - run: |- - set -ex - tgz=$(mktemp) - ARCH="$(uname -s)_$(uname -m)" - mkdir -p ~/go/bin - export PATH=$PATH:~/go/bin - curl "https://github.com/cuelang/cue/releases/download/v0.0.15/cue_0.0.15_$ARCH.tar.gz" -L -o $tgz - (cd ~/go/bin && tar xzf $tgz cue) - go install ./cmd/... && - go generate . ./cmd/... && - go test ./... || - docker logs -f $(docker ps -f 'name=lenses' -q) - strategy: - matrix: - go: - - 1.16 - - 1.17 - - 1.18 - - 1.19 - platform: - - ubuntu-latest -name: Test -"on": -- push -- pull_request diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..401a609 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ + +.PHONY: test build + +build: + go build ./... + +test: + go install ./cmd/... + go generate . ./cmd/... + go test ./... -cover -race -timeout=2m -json ./... | tparse diff --git a/analyze.go b/analyze.go index cf1c776..cf28236 100644 --- a/analyze.go +++ b/analyze.go @@ -2,6 +2,7 @@ package avro import ( "fmt" + "gopkg.in/errgo.v2/fmt/errors" "log" "reflect" "strings" @@ -104,18 +105,18 @@ func compileDecoder(names *Names, t reflect.Type, writerType *Type) (*decodeProg // First determine the schema for the type. readerType, err := avroTypeOf(names, t) if err != nil { - return nil, fmt.Errorf("cannot determine schema for %s: %v", t, err) + return nil, errors.Newf("cannot determine schema for %s: %v", t, err) } if debugging { debugf("compiling:\nwriter type: %s\nreader type: %s\n", writerType, readerType) } prog, err := compiler.Compile(writerType.avroType, readerType.avroType, compiler.AllowLaxNames()) if err != nil { - return nil, fmt.Errorf("cannot create decoder: %v", err) + return nil, errors.Newf("cannot create decoder: %v", err) } prog1, err := analyzeProgramTypes(prog, t, readerType.avroType) if err != nil { - return nil, fmt.Errorf("analysis failed: %v", err) + return nil, errors.Newf("analysis failed: %v", err) } prog1.readerType = readerType return prog1, nil @@ -145,7 +146,7 @@ func analyzeProgramTypes(prog *vm.Program, t reflect.Type, readerType schema.Avr info: info, avroType: readerType, }}); err != nil { - return nil, fmt.Errorf("eval: %v", err) + return nil, errors.Newf("eval: %v", err) } prog1 := &decodeProgram{ Program: *prog, @@ -158,11 +159,11 @@ func analyzeProgramTypes(prog *vm.Program, t reflect.Type, readerType schema.Avr switch inst.Op { case vm.Enter: if prog1.enter[i] == nil { - return nil, fmt.Errorf("enter not set; pc %d; instruction %v", i, inst) + return nil, errors.Newf("enter not set; pc %d; instruction %v", i, inst) } case vm.SetDefault: if prog1.makeDefault[i] == nil { - return nil, fmt.Errorf("makeDefault not set; pc %d; instruction %v", i, inst) + return nil, errors.Newf("makeDefault not set; pc %d; instruction %v", i, inst) } } } @@ -203,7 +204,7 @@ func (a *analyzer) eval(stack []int, calls []int, path []pathElem) (retErr error // we should always be inside the same path if // we're at the same PC. if !equalPathRef(path, a.pcInfo[pc].path) { - return fmt.Errorf("type mismatch (\n\tprevious %s\n\tnew %s\n)", pathStr(a.pcInfo[pc].path), pathStr(path)) + return errors.Newf("type mismatch (\n\tprevious %s\n\tnew %s\n)", pathStr(a.pcInfo[pc].path), pathStr(path)) } if !a.pcInfo[pc].addTrace(stack) { // We've been exactly here before, @@ -235,7 +236,7 @@ func (a *analyzer) eval(stack []int, calls []int, path []pathElem) (retErr error // TODO: sanity-check that if it's Set(Bytes), the previous // instruction was Read(Bytes) (i.e. frame.Bytes hasn't been invalidated). if !canAssignVMType(inst.Operand, elem.ftype) { - return fmt.Errorf("cannot assign %v to %s", operandString(inst.Operand), elem.ftype) + return errors.Newf("cannot assign %v to %s", operandString(inst.Operand), elem.ftype) } case vm.Enter: index := inst.Operand @@ -244,17 +245,17 @@ func (a *analyzer) eval(stack []int, calls []int, path []pathElem) (retErr error } enterf, newElem, err := enter(elem, index) if err != nil { - return fmt.Errorf("cannot enter: %v", err) + return errors.Newf("cannot enter: %v", err) } path = append(path, newElem) a.enter[pc] = enterf case vm.AppendArray: if elem.ftype.Kind() != reflect.Slice { - return fmt.Errorf("cannot append to %T", elem.ftype) + return errors.Newf("cannot append to %T", elem.ftype) } newElem, err := enterContainer(elem) if err != nil { - return fmt.Errorf("cannot enter array: %v", err) + return errors.Newf("cannot enter array: %v", err) } path = append(path, newElem) if debugging { @@ -262,19 +263,19 @@ func (a *analyzer) eval(stack []int, calls []int, path []pathElem) (retErr error } case vm.AppendMap: if elem.ftype.Kind() != reflect.Map { - return fmt.Errorf("cannot append to %T", elem.ftype) + return errors.Newf("cannot append to %T", elem.ftype) } if elem.ftype.Key().Kind() != reflect.String { - return fmt.Errorf("invalid key type for map %s", elem.ftype) + return errors.Newf("invalid key type for map %s", elem.ftype) } newElem, err := enterContainer(elem) if err != nil { - return fmt.Errorf("cannot enter map: %v", err) + return errors.Newf("cannot enter map: %v", err) } path = append(path, newElem) case vm.Exit: if len(path) == 0 { - return fmt.Errorf("unbalanced exit") + return errors.Newf("unbalanced exit") } path = path[:len(path)-1] case vm.SetExitNull: @@ -283,11 +284,11 @@ func (a *analyzer) eval(stack []int, calls []int, path []pathElem) (retErr error case vm.SetDefault: index := inst.Operand if index >= len(elem.info.Entries) { - return fmt.Errorf("set-default index out of bounds; pc %d; type %s", pc, elem.ftype) + return errors.Newf("set-default index out of bounds; pc %d; type %s", pc, elem.ftype) } info := elem.info.Entries[index] if info.MakeDefault == nil { - return fmt.Errorf("no default info found at index %d at %v", index, pathStr(path)) + return errors.Newf("no default info found at index %d at %v", index, pathStr(path)) } a.makeDefault[pc] = info.MakeDefault case vm.Call: @@ -306,7 +307,7 @@ func (a *analyzer) eval(stack []int, calls []int, path []pathElem) (retErr error } case vm.Return: if len(stack) == 0 { - return fmt.Errorf("empty stack") + return errors.Newf("empty stack") } stack = stack[:len(stack)-1] calls = calls[:len(calls)-1] @@ -347,7 +348,7 @@ func (a *analyzer) eval(stack []int, calls []int, path []pathElem) (retErr error case vm.Halt: return nil default: - return fmt.Errorf("unknown instruction %v", inst.Op) + return errors.Newf("unknown instruction %v", inst.Op) } stack[len(stack)-1]++ } @@ -370,10 +371,10 @@ func enter(elem pathElem, index int) (enterFunc, pathElem, error) { case *schema.UnionField: itemTypes := at.ItemTypes() if len(elem.info.Entries) != len(itemTypes) { - return nil, pathElem{}, fmt.Errorf("union type mismatch") + return nil, pathElem{}, errors.Newf("union type mismatch") } if index >= len(elem.info.Entries) { - return nil, pathElem{}, fmt.Errorf("union index out of bounds") + return nil, pathElem{}, errors.Newf("union index out of bounds") } entryType = itemTypes[index] @@ -383,7 +384,7 @@ func enter(elem pathElem, index int) (enterFunc, pathElem, error) { case *schema.RecordDefinition: fields := def.Fields() if index >= len(fields) { - return nil, pathElem{}, fmt.Errorf("field index out of bounds (%d/%d)", index, len(fields)) + return nil, pathElem{}, errors.Newf("field index out of bounds (%d/%d)", index, len(fields)) } field := fields[index] // The reader type might not exactly match the @@ -394,15 +395,15 @@ func enter(elem pathElem, index int) (enterFunc, pathElem, error) { // for a field that matches the Avro field. info1, ok := entryByName(elem.info.Entries, field.Name()) if !ok { - return nil, pathElem{}, fmt.Errorf("could not find entry for field %q in %v", field.Name(), elem.ftype) + return nil, pathElem{}, errors.Newf("could not find entry for field %q in %v", field.Name(), elem.ftype) } info = info1 entryType = field.Type() default: - return nil, pathElem{}, fmt.Errorf("unexpected Enter on Avro definition %T", def) + return nil, pathElem{}, errors.Newf("unexpected Enter on Avro definition %T", def) } default: - return nil, pathElem{}, fmt.Errorf("unexpected Enter on Avro type %T", at) + return nil, pathElem{}, errors.Newf("unexpected Enter on Avro type %T", at) } if info.Type == nil { // Special case for the nil type. Return @@ -415,7 +416,7 @@ func enter(elem pathElem, index int) (enterFunc, pathElem, error) { // The type itself might contribute information. info1, err := typeinfo.ForType(info.Type) if err != nil { - return nil, pathElem{}, fmt.Errorf("cannot get info for %s: %v", info.Type, err) + return nil, pathElem{}, errors.Newf("cannot get info for %s: %v", info.Type, err) } info1.FieldIndex = info.FieldIndex info = info1 @@ -439,7 +440,7 @@ func enter(elem pathElem, index int) (enterFunc, pathElem, error) { } case reflect.Ptr: if len(elem.info.Entries) != 2 { - return nil, pathElem{}, fmt.Errorf("pointer type without a two-member union") + return nil, pathElem{}, errors.Newf("pointer type without a two-member union") } enter = func(v reflect.Value) (reflect.Value, bool) { inner := reflect.New(info.Type) @@ -447,7 +448,7 @@ func enter(elem pathElem, index int) (enterFunc, pathElem, error) { return inner.Elem(), true } default: - return nil, pathElem{}, fmt.Errorf("unexpected type %v for Enter", elem.ftype) + return nil, pathElem{}, errors.Newf("unexpected type %v for Enter", elem.ftype) } return enter, newElem, nil } @@ -468,7 +469,7 @@ func enterContainer(elem pathElem) (pathElem, error) { // The type itself might contribute information. info, err := typeinfo.ForType(elem1.ftype) if err != nil { - return pathElem{}, fmt.Errorf("cannot get info for %s: %v", info.Type, err) + return pathElem{}, errors.Newf("cannot get info for %s: %v", info.Type, err) } elem1.info = info } diff --git a/avroregistry/message.go b/avroregistry/message.go index 30eca8f..883d011 100644 --- a/avroregistry/message.go +++ b/avroregistry/message.go @@ -6,6 +6,7 @@ import ( "encoding/binary" "encoding/json" "fmt" + "gopkg.in/errgo.v2/fmt/errors" "github.com/heetch/avro" ) @@ -83,7 +84,7 @@ func (r decodingRegistry) SchemaForID(ctx context.Context, id int64) (*avro.Type } t, err := avro.ParseType(resp.Schema) if err != nil { - return nil, fmt.Errorf("invalid schema (%q) in response: %v", resp.Schema, err) + return nil, errors.Newf("invalid schema (%q) in response: %v", resp.Schema, err) } return t, nil } diff --git a/avroregistry/registry.go b/avroregistry/registry.go index 6ef714c..52bba12 100644 --- a/avroregistry/registry.go +++ b/avroregistry/registry.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "fmt" + "gopkg.in/errgo.v2/fmt/errors" "io" "net/http" "net/url" @@ -61,10 +62,10 @@ func New(p Params) (*Registry, error) { p.RetryStrategy = defaultRetryStrategy } if p.ServerURL == "" { - return nil, fmt.Errorf("no server address found for Avro registry") + return nil, errors.Newf("no server address found for Avro registry") } if u, err := url.Parse(p.ServerURL); err != nil || u.Scheme == "" { - return nil, fmt.Errorf("invalid server address %q", p.ServerURL) + return nil, errors.Newf("invalid server address %q", p.ServerURL) } return &Registry{ params: p, @@ -157,9 +158,9 @@ func validateVersion(version string) error { if version == "latest" { return nil } - return fmt.Errorf("%s: %w", msg, err) + return errors.Newf("%s: %w", msg, err) } else if i < 1 || i > 1<<31-1 { - return fmt.Errorf("%s: %d provided", msg, i) + return errors.Newf("%s: %d provided", msg, i) } return nil @@ -228,13 +229,13 @@ func unmarshalResponse(req *http.Request, resp *http.Response, result interface{ defer resp.Body.Close() if resp.StatusCode == http.StatusOK { if err := httprequest.UnmarshalJSONResponse(resp, result); err != nil { - return fmt.Errorf("cannot unmarshal JSON response from %v: %v", req.URL, err) + return errors.Newf("cannot unmarshal JSON response from %v: %v", req.URL, err) } return nil } var apiErr apiError if err := httprequest.UnmarshalJSONResponse(resp, &apiErr); err != nil { - return fmt.Errorf("cannot unmarshal JSON error response from %v: %v", req.URL, err) + return errors.Newf("cannot unmarshal JSON error response from %v: %v", req.URL, err) } apiErr.StatusCode = resp.StatusCode return &apiErr diff --git a/avroregistrytest/avroregistrytest.go b/avroregistrytest/avroregistrytest.go index 6d90527..bf8d973 100644 --- a/avroregistrytest/avroregistrytest.go +++ b/avroregistrytest/avroregistrytest.go @@ -2,7 +2,7 @@ package avroregistrytest import ( "context" - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "os" "github.com/heetch/avro" @@ -14,9 +14,9 @@ import ( // The following environment variables can be used to // configure the connection parameters: // -// - $KAFKA_REGISTRY_ADDR -// The Kafka registry address in host:port -// form. If this is empty, localhost:8084 will be used. +// - $KAFKA_REGISTRY_ADDR +// The Kafka registry address in host:port +// form. If this is empty, localhost:8084 will be used. // // This requires go1.14 or higher func Register(ctx context.Context, t T, x interface{}, topic string) error { @@ -29,17 +29,17 @@ func Register(ctx context.Context, t T, x interface{}, topic string) error { ServerURL: "http://" + registryAddr, }) if err != nil { - return fmt.Errorf("cannot connect to registry: %w", err) + return errors.Newf("cannot connect to registry: %w", err) } avroType, err := avro.TypeOf(x) if err != nil { - return fmt.Errorf("cannot generate Avro schema for %T: %w", x, err) + return errors.Newf("cannot generate Avro schema for %T: %w", x, err) } _, err = registry.Register(ctx, topic, avroType) if err != nil { - return fmt.Errorf("cannot register %T in %v: %w", x, topic, err) + return errors.Newf("cannot register %T in %v: %w", x, topic, err) } t.Cleanup(func() { diff --git a/avrotypegen/typeinfo.go b/avrotypegen/typeinfo.go index 7c466e5..833cf96 100644 --- a/avrotypegen/typeinfo.go +++ b/avrotypegen/typeinfo.go @@ -2,7 +2,7 @@ // This is an implementation detail and this might change over time. package avrotypegen -import "fmt" +import "gopkg.in/errgo.v2/fmt/errors" // AvroRecord is implemented by Go types generated // by the avrogo command. @@ -58,7 +58,7 @@ type Null struct{} // the JSON value to be null. func (Null) UnmarshalJSON(data []byte) error { if string(data) != "null" { - return fmt.Errorf("cannot unmarshal %q into avro.Null", data) + return errors.Newf("cannot unmarshal %q into avro.Null", data) } return nil } diff --git a/cmd/avrogo/avrotypemap/typemap.go b/cmd/avrogo/avrotypemap/typemap.go index b4ddb27..276597f 100644 --- a/cmd/avrogo/avrotypemap/typemap.go +++ b/cmd/avrogo/avrotypemap/typemap.go @@ -4,6 +4,7 @@ package avrotypemap import ( "fmt" + "gopkg.in/errgo.v2/fmt/errors" "reflect" "github.com/actgardner/gogen-avro/v10/schema" @@ -80,7 +81,7 @@ func (w *walker) walk(at schema.AvroType, t reflect.Type, info typeinfo.Info) er // We've found this name before. Check that it // maps to the same Go type here. if oldt != t { - return fmt.Errorf("type clash on %s: %v vs %v", at.TypeName, t, oldt) + return errors.Newf("type clash on %s: %v vs %v", at.TypeName, t, oldt) } return nil } else { @@ -89,18 +90,18 @@ func (w *walker) walk(at schema.AvroType, t reflect.Type, info typeinfo.Info) er switch def := at.Def.(type) { case *schema.RecordDefinition: if t.Kind() != reflect.Struct { - return fmt.Errorf("expected struct") + return errors.Newf("expected struct") } if len(info.Entries) == 0 { // The type itself might contribute information. info1, err := typeinfo.ForType(t) if err != nil { - return fmt.Errorf("cannot get info for %s: %v", info.Type, err) + return errors.Newf("cannot get info for %s: %v", info.Type, err) } info = info1 } if len(info.Entries) != len(def.Fields()) { - return fmt.Errorf("field count mismatch") + return errors.Newf("field count mismatch") } for i, f := range def.Fields() { ft := t.Field(info.Entries[i].FieldIndex) @@ -112,17 +113,17 @@ func (w *walker) walk(at schema.AvroType, t reflect.Type, info typeinfo.Info) er } case *schema.ArrayField: if t.Kind() != reflect.Slice { - return fmt.Errorf("expected slice, got %s", t) + return errors.Newf("expected slice, got %s", t) } return w.walk(at.ItemType(), t.Elem(), info) case *schema.MapField: if t.Kind() != reflect.Map { - return fmt.Errorf("expected map, got %s", t) + return errors.Newf("expected map, got %s", t) } return w.walk(at.ItemType(), t.Elem(), info) case *schema.UnionField: if len(info.Entries) != len(at.ItemTypes()) { - return fmt.Errorf("union entry count mismatch") + return errors.Newf("union entry count mismatch") } for i, at := range at.ItemTypes() { err := w.walk(at, info.Entries[i].Type, info.Entries[i]) diff --git a/cmd/avrogo/externaltype.go b/cmd/avrogo/externaltype.go index a9d0075..636f039 100644 --- a/cmd/avrogo/externaltype.go +++ b/cmd/avrogo/externaltype.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "go/format" + "gopkg.in/errgo.v2/fmt/errors" "io/ioutil" "os" "os/exec" @@ -60,17 +61,17 @@ func externalTypeMap(ns *parser.Namespace) (map[schema.QualifiedName]goType, err if !ok { // We should have acquired the necessary info // with externalTypeInfoForGoTypes above. - panic(fmt.Errorf("type info for %s not found", gt)) + panic(errors.Newf("type info for %s not found", gt)) } extType, err := typeinfo.ParseSchema(info.Schema, nil) if err != nil { - return nil, fmt.Errorf("cannot parse schema from external type: %v", err) + return nil, errors.Newf("cannot parse schema from external type: %v", err) } if err := checkGoCompatible(name.String(), &schema.Reference{ TypeName: name, Def: def, }, extType, make(map[schema.AvroType]bool)); err != nil { - return nil, fmt.Errorf("external type is not compatible; external schema %s; name %s: %v", info.Schema, name, err) + return nil, errors.Newf("external type is not compatible; external schema %s; name %s: %v", info.Schema, name, err) } for qname, extType := range info.Map { name := parser.ParseAvroName("", qname) @@ -79,7 +80,7 @@ func externalTypeMap(ns *parser.Namespace) (map[schema.QualifiedName]goType, err } else if extType != extType0 { // We've found another mention of the same Avro type that's // associated with a different Go type. - return nil, fmt.Errorf("different external names for Avro name %s (%s vs %s)", name, extType, extType0) + return nil, errors.Newf("different external names for Avro name %s (%s vs %s)", name, extType, extType0) } } } @@ -126,12 +127,12 @@ func externalTypeInfoForGoTypes(gts map[goType]bool) (map[goType]avrotypemap.Ext } var buf bytes.Buffer if err := typeInfoMainTemplate.Execute(&buf, mp); err != nil { - return nil, fmt.Errorf("cannot execute type info main template: %v", err) + return nil, errors.Newf("cannot execute type info main template: %v", err) } resultData, err := format.Source(buf.Bytes()) if err != nil { fmt.Printf("%s\n", buf.Bytes()) - return nil, fmt.Errorf("cannot format typeinfo source: %v", err) + return nil, errors.Newf("cannot format typeinfo source: %v", err) } f, err := ioutil.TempFile(*dirFlag, "avro-introspect*.go") if err != nil { @@ -141,7 +142,7 @@ func externalTypeInfoForGoTypes(gts map[goType]bool) (map[goType]avrotypemap.Ext defer os.Remove(prog) defer f.Close() if _, err := f.Write(resultData); err != nil { - return nil, fmt.Errorf("cannot write %q: %v", f.Name(), err) + return nil, errors.Newf("cannot write %q: %v", f.Name(), err) } f.Close() var runStdout bytes.Buffer @@ -150,14 +151,14 @@ func externalTypeInfoForGoTypes(gts map[goType]bool) (map[goType]avrotypemap.Ext cmd.Stdout = &runStdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - return nil, fmt.Errorf("failed to run introspect program: %v", err) + return nil, errors.Newf("failed to run introspect program: %v", err) } var resultSlice []avrotypemap.ExternalTypeResult if err := json.Unmarshal(runStdout.Bytes(), &resultSlice); err != nil { - return nil, fmt.Errorf("cannot unmarshal introspect output %q: %v", runStdout.Bytes(), err) + return nil, errors.Newf("cannot unmarshal introspect output %q: %v", runStdout.Bytes(), err) } if len(resultSlice) != len(gts) { - return nil, fmt.Errorf("unexpected result count, got %d want %d", len(resultSlice), len(gts)) + return nil, errors.Newf("unexpected result count, got %d want %d", len(resultSlice), len(gts)) } results := make(map[goType]avrotypemap.ExternalTypeResult) for i, result := range resultSlice { @@ -222,11 +223,11 @@ func main() { func infoForType(t reflect.Type) (*avro.Type, map[string]avrotypemap.GoType, error) { at, err := avro.TypeOf(reflect.Zero(t).Interface()) if err != nil { - return nil, nil, fmt.Errorf("cannot get Avro type for %s: %v", t, err) + return nil, nil, errors.Newf("cannot get Avro type for %s: %v", t, err) } m, err := avrotypemap.AvroTypeMap(t) if err != nil { - return nil, nil, fmt.Errorf("cannot get type map for %s: %v", t, err) + return nil, nil, errors.Newf("cannot get type map for %s: %v", t, err) } return at, m, nil } @@ -303,7 +304,7 @@ func checkGoCompatible(path string, t1, t2 schema.AvroType, checked map[schema.A return compatErrorf(path, "fixed size changed value") } default: - panic(fmt.Errorf("unknown definition type %T", t1def)) + panic(errors.Newf("unknown definition type %T", t1def)) } case *schema.UnionField: // All members of the union must be compatible. @@ -313,7 +314,7 @@ func checkGoCompatible(path string, t1, t2 schema.AvroType, checked map[schema.A if len(itemTypes1) != len(itemTypes2) { // TODO we could potentially let the external type add new // union members. - return fmt.Errorf("union type mismatch") + return errors.Newf("union type mismatch") } for i := range itemTypes1 { if err := checkGoCompatible(path+fmt.Sprintf("[u%d]", i), itemTypes1[i], itemTypes2[i], checked); err != nil { @@ -327,7 +328,7 @@ func checkGoCompatible(path string, t1, t2 schema.AvroType, checked map[schema.A case *schema.LongField: if logicalType(t1) != logicalType(t2) { // TODO check for timestamp-micros only? - return fmt.Errorf("logical type mismatch") + return errors.Newf("logical type mismatch") } } // We already know the type matches and there's nothing diff --git a/cmd/avrogo/generate.go b/cmd/avrogo/generate.go index 17b79df..6c8114d 100644 --- a/cmd/avrogo/generate.go +++ b/cmd/avrogo/generate.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "gopkg.in/errgo.v2/fmt/errors" "io" "regexp" "sort" @@ -91,7 +92,7 @@ func generate(w io.Writer, pkg string, ns *parser.Namespace, definitions []schem Imports: importList, ImportIds: gc.imports, }); err != nil { - return fmt.Errorf("cannot execute header template: %v", err) + return errors.Newf("cannot execute header template: %v", err) } if _, err := w.Write(body.Bytes()); err != nil { return err @@ -154,7 +155,7 @@ func (gc *generateContext) RecordInfoLiteral(t *schema.RecordDefinition) (string fprintf(w, "%d: ", i) lit, err := gc.defaultFuncLiteral(f.Default(), f.Type()) if err != nil { - return "", fmt.Errorf("cannot generate code for field %s of record %v: %v", f.Name(), t.AvroName(), err) + return "", errors.Newf("cannot generate code for field %s of record %v: %v", f.Name(), t.AvroName(), err) } else { fprintf(w, "func() interface{} {\nreturn %s\n},\n", lit) } @@ -282,13 +283,13 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) return gc.defaultFuncLiteral(v, t.AvroTypes()[0]) case *schema.NullField: if v != nil { - return "", fmt.Errorf("must be null but got %s", jsonMarshal(v)) + return "", errors.Newf("must be null but got %s", jsonMarshal(v)) } return nullType + "{}", nil case *schema.BoolField: v, ok := v.(bool) if !ok { - return "", fmt.Errorf("must be boolean but got %s", jsonMarshal(v)) + return "", errors.Newf("must be boolean but got %s", jsonMarshal(v)) } return fmt.Sprintf("%v", v), nil case *schema.IntField: @@ -302,30 +303,30 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) case *schema.BytesField: s, ok := v.(string) if !ok { - return "", fmt.Errorf("must be string but got %v", jsonMarshal(v)) + return "", errors.Newf("must be string but got %v", jsonMarshal(v)) } bytes, err := decodeBytes(s) if err != nil { - return "", fmt.Errorf("cannot decode bytes literal %v: %v", jsonMarshal(v), err) + return "", errors.Newf("cannot decode bytes literal %v: %v", jsonMarshal(v), err) } return fmt.Sprintf("[]byte(%q)", bytes), nil case *schema.StringField: s, ok := v.(string) if !ok { - return "", fmt.Errorf("must be string but got %v", jsonMarshal(v)) + return "", errors.Newf("must be string but got %v", jsonMarshal(v)) } return fmt.Sprintf("%q", s), nil case *schema.ArrayField: a, ok := v.([]interface{}) if !ok { - return "", fmt.Errorf("must be array but got %v", jsonMarshal(v)) + return "", errors.Newf("must be array but got %v", jsonMarshal(v)) } var buf bytes.Buffer fmt.Fprintf(&buf, "[]%s{", gc.GoTypeOf(t.ItemType()).GoType) for i, item := range a { val, err := gc.defaultFuncLiteral(item, t.ItemType()) if err != nil { - return "", fmt.Errorf("at index %d: %v", i, err) + return "", errors.Newf("at index %d: %v", i, err) } buf.WriteString(val) buf.WriteString(",") @@ -335,7 +336,7 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) case *schema.MapField: m, ok := v.(map[string]interface{}) if !ok { - return "", fmt.Errorf("must be map but got %v", jsonMarshal(v)) + return "", errors.Newf("must be map but got %v", jsonMarshal(v)) } var buf bytes.Buffer fmt.Fprintf(&buf, "map[string]%s{\n", gc.GoTypeOf(t.ItemType()).GoType) @@ -347,7 +348,7 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) for _, key := range keys { val, err := gc.defaultFuncLiteral(m[key], t.ItemType()) if err != nil { - return "", fmt.Errorf("at key %q: %v", key, err) + return "", errors.Newf("at key %q: %v", key, err) } fmt.Fprintf(&buf, "%q: %s,\n", key, val) } @@ -358,25 +359,25 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) case *schema.EnumDefinition: s, ok := v.(string) if !ok { - return "", fmt.Errorf("enum default value must be string, not %s", jsonMarshal(v)) + return "", errors.Newf("enum default value must be string, not %s", jsonMarshal(v)) } for _, sym := range def.Symbols() { if sym == s { return def.SymbolName(s), nil } } - return "", fmt.Errorf("unknown value %q for enum %s", s, def.Name()) + return "", errors.Newf("unknown value %q for enum %s", s, def.Name()) case *schema.FixedDefinition: s, ok := v.(string) if !ok { - return "", fmt.Errorf("fixed default value must be string, not %s", jsonMarshal(v)) + return "", errors.Newf("fixed default value must be string, not %s", jsonMarshal(v)) } b, err := decodeBytes(s) if err != nil { - return "", fmt.Errorf("invalid fixed default value %q: %v", b, err) + return "", errors.Newf("invalid fixed default value %q: %v", b, err) } if len(b) != def.SizeBytes() { - return "", fmt.Errorf("fixed value %s is wrong length (got %d; want %d)", jsonMarshal(v), len(b), def.SizeBytes()) + return "", errors.Newf("fixed value %s is wrong length (got %d; want %d)", jsonMarshal(v), len(b), def.SizeBytes()) } var buf bytes.Buffer fmt.Fprintf(&buf, "%s{", def.Name()) @@ -388,7 +389,7 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) case *schema.RecordDefinition: m, ok := v.(map[string]interface{}) if !ok { - return "", fmt.Errorf("invalid record default value %s", jsonMarshal(v)) + return "", errors.Newf("invalid record default value %s", jsonMarshal(v)) } var buf bytes.Buffer fmt.Fprintf(&buf, "%s{\n", def.Name()) @@ -396,11 +397,11 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) fieldVal, ok := m[field.Name()] var lit string if !ok { - return "", fmt.Errorf("field %q of record %s must be present in default value but is missing", field.Name(), t.TypeName) + return "", errors.Newf("field %q of record %s must be present in default value but is missing", field.Name(), t.TypeName) } lit, err := gc.defaultFuncLiteral(fieldVal, field.Type()) if err != nil { - return "", fmt.Errorf("at field %s: %v", field.Name(), err) + return "", errors.Newf("at field %s: %v", field.Name(), err) } ident, err := goName(field.Name()) if err != nil { @@ -411,11 +412,11 @@ func (gc *generateContext) defaultFuncLiteral(v interface{}, t schema.AvroType) buf.WriteString("}") return buf.String(), nil default: - return "", fmt.Errorf("unknown definition type %T", def) + return "", errors.Newf("unknown definition type %T", def) } default: - return "", fmt.Errorf("literal of type %T not yet implemented", t) + return "", errors.Newf("literal of type %T not yet implemented", t) } } @@ -425,7 +426,7 @@ func goName(s string) (string, error) { name := s[lastIndex+1:] name = strings.Title(strings.Trim(name, "_")) if !isExportedGoIdentifier(name) { - return "", fmt.Errorf("cannot form an exported Go identifier from %q", s) + return "", errors.Newf("cannot form an exported Go identifier from %q", s) } return name, nil } @@ -434,7 +435,7 @@ func decodeBytes(s string) ([]byte, error) { b := make([]byte, 0, len(s)) for _, r := range s { if r > 0xff { - return nil, fmt.Errorf("rune out of range (%d) in byte literal %q", r, s) + return nil, errors.Newf("rune out of range (%d) in byte literal %q", r, s) } b = append(b, byte(r)) } @@ -454,7 +455,7 @@ func numberDefault(v interface{}, goType string) (string, error) { // TODO omit type conversion when it's not needed? return fmt.Sprintf("%s(%v)", goType, v), nil default: - return "", fmt.Errorf("must be number but got %T", v) + return "", errors.Newf("must be number but got %T", v) } } diff --git a/cmd/avrogo/generatetestcode.go b/cmd/avrogo/generatetestcode.go index 38e779e..1e7c52d 100644 --- a/cmd/avrogo/generatetestcode.go +++ b/cmd/avrogo/generatetestcode.go @@ -1,3 +1,4 @@ +//go:build ignore // +build ignore // This program generates all the test code in internal/generated_tests from @@ -190,7 +191,7 @@ func quote(b interface{}) string { case string: s = b default: - panic(fmt.Errorf("cannot quote %T", b)) + panic(errors.Newf("cannot quote %T", b)) } if !strings.Contains(s, "`") { return "`" + s + "`" diff --git a/cmd/avrogo/internal/avrotestdata/testdata.go b/cmd/avrogo/internal/avrotestdata/testdata.go index 7d8365d..0e86dcf 100644 --- a/cmd/avrogo/internal/avrotestdata/testdata.go +++ b/cmd/avrogo/internal/avrotestdata/testdata.go @@ -3,7 +3,7 @@ package avrotestdata import ( "bytes" "encoding/json" - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "os" "os/exec" ) @@ -35,14 +35,14 @@ func Load(dir string) (map[string]Test, error) { cmd.Stdout = &buf err := cmd.Run() if err != nil { - return nil, fmt.Errorf("cue export failed: %v", err) + return nil, errors.Newf("cue export failed: %v", err) } var exported struct { Tests map[string]Test `json:"tests"` } err = json.Unmarshal(buf.Bytes(), &exported) if err != nil { - return nil, fmt.Errorf("cannot unmarshal test data: %v", err) + return nil, errors.Newf("cannot unmarshal test data: %v", err) } return exported.Tests, nil } diff --git a/cmd/avrogo/internal/generated_tests/enumDefault/schema_gen.go b/cmd/avrogo/internal/generated_tests/enumDefault/schema_gen.go index ccf7f07..4248326 100644 --- a/cmd/avrogo/internal/generated_tests/enumDefault/schema_gen.go +++ b/cmd/avrogo/internal/generated_tests/enumDefault/schema_gen.go @@ -34,7 +34,7 @@ func (e Foo) String() string { // by returning the textual representation of Foo. func (e Foo) MarshalText() ([]byte, error) { if e < 0 || int(e) >= len(_Foo_strings) { - return nil, fmt.Errorf("Foo value %d is out of bounds", e) + return nil, errors.Newf("Foo value %d is out of bounds", e) } return []byte(_Foo_strings[e]), nil } @@ -49,7 +49,7 @@ func (e *Foo) UnmarshalText(data []byte) error { return nil } } - return fmt.Errorf("unknown value %q for Foo", data) + return errors.Newf("unknown value %q for Foo", data) } type R struct { diff --git a/cmd/avrogo/internal/generated_tests/goTypeCustomName/schema_gen.go b/cmd/avrogo/internal/generated_tests/goTypeCustomName/schema_gen.go index 04e6bce..bec5e7d 100644 --- a/cmd/avrogo/internal/generated_tests/goTypeCustomName/schema_gen.go +++ b/cmd/avrogo/internal/generated_tests/goTypeCustomName/schema_gen.go @@ -48,7 +48,7 @@ func (e customEnum) String() string { // by returning the textual representation of customEnum. func (e customEnum) MarshalText() ([]byte, error) { if e < 0 || int(e) >= len(_customEnum_strings) { - return nil, fmt.Errorf("customEnum value %d is out of bounds", e) + return nil, errors.Newf("customEnum value %d is out of bounds", e) } return []byte(_customEnum_strings[e]), nil } @@ -63,7 +63,7 @@ func (e *customEnum) UnmarshalText(data []byte) error { return nil } } - return fmt.Errorf("unknown value %q for customEnum", data) + return errors.Newf("unknown value %q for customEnum", data) } type customFixed [2]byte diff --git a/cmd/avrogo/internal/generated_tests/justEnum/schema_gen.go b/cmd/avrogo/internal/generated_tests/justEnum/schema_gen.go index 4189c1a..cfcfd7f 100644 --- a/cmd/avrogo/internal/generated_tests/justEnum/schema_gen.go +++ b/cmd/avrogo/internal/generated_tests/justEnum/schema_gen.go @@ -33,7 +33,7 @@ func (e MyEnum) String() string { // by returning the textual representation of MyEnum. func (e MyEnum) MarshalText() ([]byte, error) { if e < 0 || int(e) >= len(_MyEnum_strings) { - return nil, fmt.Errorf("MyEnum value %d is out of bounds", e) + return nil, errors.Newf("MyEnum value %d is out of bounds", e) } return []byte(_MyEnum_strings[e]), nil } @@ -48,5 +48,5 @@ func (e *MyEnum) UnmarshalText(data []byte) error { return nil } } - return fmt.Errorf("unknown value %q for MyEnum", data) + return errors.Newf("unknown value %q for MyEnum", data) } diff --git a/cmd/avrogo/internal/generated_tests/simpleEnum/schema_gen.go b/cmd/avrogo/internal/generated_tests/simpleEnum/schema_gen.go index f2b7a00..ca5ca8b 100644 --- a/cmd/avrogo/internal/generated_tests/simpleEnum/schema_gen.go +++ b/cmd/avrogo/internal/generated_tests/simpleEnum/schema_gen.go @@ -3,8 +3,8 @@ package simpleEnum import ( - "fmt" "github.com/heetch/avro/avrotypegen" + "gopkg.in/errgo.v2/fmt/errors" "strconv" ) @@ -34,7 +34,7 @@ func (e MyEnum) String() string { // by returning the textual representation of MyEnum. func (e MyEnum) MarshalText() ([]byte, error) { if e < 0 || int(e) >= len(_MyEnum_strings) { - return nil, fmt.Errorf("MyEnum value %d is out of bounds", e) + return nil, errors.Newf("MyEnum value %d is out of bounds", e) } return []byte(_MyEnum_strings[e]), nil } @@ -49,7 +49,7 @@ func (e *MyEnum) UnmarshalText(data []byte) error { return nil } } - return fmt.Errorf("unknown value %q for MyEnum", data) + return errors.Newf("unknown value %q for MyEnum", data) } type R struct { diff --git a/cmd/avrogo/main.go b/cmd/avrogo/main.go index 17b956e..4e8a348 100644 --- a/cmd/avrogo/main.go +++ b/cmd/avrogo/main.go @@ -9,16 +9,16 @@ // // Usage: // -// usage: avrogo [flags] schema-file... -// -d string -// directory to write Go files to (default ".") -// -p string -// package name (defaults to $GOPACKAGE) -// -t generated files will have _test.go suffix -// -s string -// suffix for generated files (default "_gen") -// -tokenize -// if true, generate one dedicated file per qualified name found in the schema files +// usage: avrogo [flags] schema-file... +// -d string +// directory to write Go files to (default ".") +// -p string +// package name (defaults to $GOPACKAGE) +// -t generated files will have _test.go suffix +// -s string +// suffix for generated files (default "_gen") +// -tokenize +// if true, generate one dedicated file per qualified name found in the schema files // // By default, a type is generated for each Avro definition // in the schema. Some additional metadata fields are @@ -33,6 +33,7 @@ import ( stdflag "flag" "fmt" "go/format" + "gopkg.in/errgo.v2/fmt/errors" "io/ioutil" "os" "path" @@ -105,14 +106,14 @@ func generateFiles(files []string) error { singleFileList := []schema.QualifiedName{qualifiedName} if err := generateFile(outputPath, ns, singleFileList); err != nil { - return fmt.Errorf("cannot generate code for %s.%s: %v", qualifiedName.Namespace, qualifiedName.Name, err) + return errors.Newf("cannot generate code for %s.%s: %v", qualifiedName.Namespace, qualifiedName.Name, err) } } } } else { for i, f := range files { if err := generateFile(outfiles[f], ns, fileDefinitions[i]); err != nil { - return fmt.Errorf("cannot generate code for %s: %v", f, err) + return errors.Newf("cannot generate code for %s: %v", f, err) } } } @@ -156,7 +157,7 @@ func outputPaths(files []string, testFile bool) (map[string]string, error) { if !allOK && len(fileset) > 0 { // We've got to the end of some paths and failed to resolve all the files // unambigously, so avoid the potential infinite loop by returning an error. - return nil, fmt.Errorf("could not make unambiguous output files from input files") + return nil, errors.Newf("could not make unambiguous output files from input files") } } return result, nil @@ -210,10 +211,10 @@ func generateFile(outFile string, ns *parser.Namespace, definitions []schema.Qua resultData, err := format.Source(buf.Bytes()) if err != nil { fmt.Printf("%s\n", buf.Bytes()) - return fmt.Errorf("cannot format source: %v", err) + return errors.Newf("cannot format source: %v", err) } if err := os.MkdirAll(*dirFlag, 0777); err != nil { - return fmt.Errorf("cannot create output directory: %v", err) + return errors.Newf("cannot create output directory: %v", err) } outFile = filepath.Join(*dirFlag, outFile) if err := ioutil.WriteFile(outFile, resultData, 0666); err != nil { @@ -241,7 +242,7 @@ func parseFiles(files []string) (*parser.Namespace, [][]schema.QualifiedName, er singleNS := parser.NewNamespace(false) avroType, err := singleNS.TypeForSchema(data) if err != nil { - return nil, nil, fmt.Errorf("invalid schema in %s: %v", f, err) + return nil, nil, errors.Newf("invalid schema in %s: %v", f, err) } if _, ok := avroType.(*schema.Reference); !ok { // The schema doesn't have a top-level name. @@ -251,7 +252,7 @@ func parseFiles(files []string) (*parser.Namespace, [][]schema.QualifiedName, er // methods on it because it might be a union type which // is represented by an interface type in Go. // See https://github.com/heetch/avro/issues/13 - return nil, nil, fmt.Errorf("cannot generate code for schema %q which hasn't got a name (%T)", f, avroType) + return nil, nil, errors.Newf("cannot generate code for schema %q which hasn't got a name (%T)", f, avroType) } for name, def := range singleNS.Definitions { if name != def.AvroName() { @@ -270,7 +271,7 @@ func parseFiles(files []string) (*parser.Namespace, [][]schema.QualifiedName, er // Parse the schema again but use the global namespace // this time so all the schemas can share the same definitions. if _, err := ns.TypeForSchema(data); err != nil { - return nil, nil, fmt.Errorf("cannot parse schema in %s: %v", f, err) + return nil, nil, errors.Newf("cannot parse schema in %s: %v", f, err) } } // Now we've accumulated all the available types, @@ -280,7 +281,7 @@ func parseFiles(files []string) (*parser.Namespace, [][]schema.QualifiedName, er if err := resolver.ResolveDefinition(def, ns.Definitions); err != nil { // TODO find out which file(s) the definition came from // and include that file name in the error. - return nil, nil, fmt.Errorf("cannot resolve reference %q: %v", name, err) + return nil, nil, errors.Newf("cannot resolve reference %q: %v", name, err) } } return ns, fileDefinitions, nil diff --git a/cmd/avrogo/template.go b/cmd/avrogo/template.go index 8e21276..a91675b 100644 --- a/cmd/avrogo/template.go +++ b/cmd/avrogo/template.go @@ -108,7 +108,7 @@ var bodyTemplate = newTemplate(` // by returning the textual representation of «defName .». func (e «defName .») MarshalText() ([]byte, error) { if e < 0 || int(e) >= len(_«defName .»_strings) { - return nil, fmt.Errorf("«defName .» value %d is out of bounds", e) + return nil, errors.Newf("«defName .» value %d is out of bounds", e) } return []byte(_«defName .»_strings[e]), nil } @@ -123,7 +123,7 @@ var bodyTemplate = newTemplate(` return nil } } - return fmt.Errorf("unknown value %q for «defName .»", data) + return errors.Newf("unknown value %q for «defName .»", data) } «else if eq (typeof .) "FixedDefinition"» «- doc "// " . -» diff --git a/cmd/avsc2avdl/main.go b/cmd/avsc2avdl/main.go index e753c5a..2535b5e 100644 --- a/cmd/avsc2avdl/main.go +++ b/cmd/avsc2avdl/main.go @@ -5,6 +5,7 @@ import ( "encoding/json" stdflag "flag" "fmt" + "gopkg.in/errgo.v2/fmt/errors" "io/ioutil" "os" "reflect" @@ -54,11 +55,11 @@ func avsc2avdl(avscFile, outFile string) error { } at, err := typeinfo.ParseSchema(string(data), nil) if err != nil { - return fmt.Errorf("cannot parse schema from %q: %v", avscFile, err) + return errors.Newf("cannot parse schema from %q: %v", avscFile, err) } ref, ok := at.(*schema.Reference) if !ok { - return fmt.Errorf("top level of schema is not a reference") + return errors.Newf("top level of schema is not a reference") } g := &generator{ filename: outFile, @@ -90,7 +91,7 @@ func avsc2avdl(avscFile, outFile string) error { } else { err := ioutil.WriteFile(outFile, g.buf.Bytes(), 0666) if err != nil { - return fmt.Errorf("cannot create output file: %v", err) + return errors.Newf("cannot create output file: %v", err) } } return nil @@ -163,7 +164,7 @@ func (g *generator) writeDefinition(def schema.Definition) { writeNamespace() g.printf("\tfixed %s(%d);\n", name.Name, def.SizeBytes()) default: - panic(fmt.Errorf("unknown definition type %T", def)) + panic(errors.Newf("unknown definition type %T", def)) } } @@ -224,7 +225,7 @@ func (g *generator) typeString(at schema.AvroType) string { s += " }" return s default: - panic(fmt.Errorf("unknown Avro type %T", at)) + panic(errors.Newf("unknown Avro type %T", at)) } } @@ -302,7 +303,7 @@ func getMetadata(d interface{}) metadata { def, _ := d.Definition(make(map[schema.QualifiedName]interface{})) m.attrs, _ = def.(map[string]interface{}) default: - panic(fmt.Errorf("invalid type %T for definitionOf", d)) + panic(errors.Newf("invalid type %T for definitionOf", d)) } m.doc, _ = m.attrs["doc"].(string) delete(m.attrs, "doc") @@ -381,7 +382,7 @@ func (g *generator) namespace() string { func jsonMarshal(v interface{}, indent string) []byte { data, err := json.MarshalIndent(v, indent, "\t") if err != nil { - panic(fmt.Errorf("cannot json marshal default value: %v", err)) + panic(errors.Newf("cannot json marshal default value: %v", err)) } return data } diff --git a/cmd/go2avro/main.go b/cmd/go2avro/main.go index 1afb2e7..8b892f3 100644 --- a/cmd/go2avro/main.go +++ b/cmd/go2avro/main.go @@ -7,6 +7,7 @@ import ( stdflag "flag" "fmt" "go/format" + "gopkg.in/errgo.v2/fmt/errors" "io/ioutil" "os" "os/exec" @@ -58,7 +59,7 @@ func main2() error { var err error p.Package, err = currentPkg() if err != nil { - return fmt.Errorf("cannot get current package: %v", err) + return errors.Newf("cannot get current package: %v", err) } p.Type = pkgType } else { @@ -67,12 +68,12 @@ func main2() error { } var codeBuf bytes.Buffer if err := tmpl.Execute(&codeBuf, p); err != nil { - return fmt.Errorf("cannot execute template: %v", err) + return errors.Newf("cannot execute template: %v", err) } code, err := format.Source(codeBuf.Bytes()) if err != nil { fmt.Fprintf(os.Stderr, "invalid temporary Go code:\n-------\n%s-----\n", codeBuf.String()) - return fmt.Errorf("invalid template code: %v", err) + return errors.Newf("invalid template code: %v", err) } // Build the binary before executing the code so we can // distinguish between build errors and Avro errors. @@ -89,13 +90,13 @@ func main2() error { cmd.Stderr = &errBuf if err := cmd.Run(); err != nil { if errBuf.Len() > 0 { - return fmt.Errorf("cannot get Avro type: %s", strings.TrimSpace(errBuf.String())) + return errors.Newf("cannot get Avro type: %s", strings.TrimSpace(errBuf.String())) } return err } var indentJSON bytes.Buffer if err := json.Indent(&indentJSON, outBuf.Bytes(), "", " "); err != nil { - return fmt.Errorf("cannot indent JSON: %v", err) + return errors.Newf("cannot indent JSON: %v", err) } fmt.Printf("%s", indentJSON.String()) return nil @@ -107,17 +108,17 @@ func buildGo(code []byte) (string, error) { // TODO avoid the side-effect of adding the avro import, somehow. tmpFile, err := ioutil.TempFile(".", "go2avro_temp_*.go") if err != nil { - return "", fmt.Errorf("cannot generate temp file: %v", err) + return "", errors.Newf("cannot generate temp file: %v", err) } defer os.Remove(tmpFile.Name()) _, err = tmpFile.Write(code) tmpFile.Close() if err != nil { - return "", fmt.Errorf("cannot write %q: %v", tmpFile.Name(), err) + return "", errors.Newf("cannot write %q: %v", tmpFile.Name(), err) } tmpBinary, err := ioutil.TempFile(".", "go2avro_temp_bin") if err != nil { - return "", fmt.Errorf("cannot generate temp binary file: %v", err) + return "", errors.Newf("cannot generate temp binary file: %v", err) } tmpBinary.Close() @@ -126,7 +127,7 @@ func buildGo(code []byte) (string, error) { cmd.Stderr = &errBuf if err := cmd.Run(); err != nil { defer os.Remove(tmpBinary.Name()) - return "", fmt.Errorf("cannot build: %v", errBuf.String()) + return "", errors.Newf("cannot build: %v", errBuf.String()) } // Use explicit "./" prefix because . isn't always in $PATH. return "." + string(filepath.Separator) + tmpBinary.Name(), nil diff --git a/decode.go b/decode.go index 2776f3a..860e168 100644 --- a/decode.go +++ b/decode.go @@ -1,7 +1,7 @@ package avro import ( - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "io" "reflect" "time" @@ -30,7 +30,7 @@ func (names *Names) Unmarshal(data []byte, x interface{}, wType *Type) (*Type, e v := reflect.ValueOf(x) t := v.Type() if t.Kind() != reflect.Ptr { - return nil, fmt.Errorf("destination is not a pointer %s", t) + return nil, errors.Newf("destination is not a pointer %s", t) } prog, err := compileDecoder(names, t.Elem(), wType) if err != nil { @@ -167,7 +167,7 @@ func (d *decoder) eval(target reflect.Value) { if target.Kind() == reflect.Array { n := reflect.Copy(target, reflect.ValueOf(frame.Bytes)) if n != len(frame.Bytes) { - d.error(fmt.Errorf("copied too little")) + d.error(errors.Newf("copied too little")) } } else { data := make([]byte, len(frame.Bytes)) @@ -184,7 +184,7 @@ func (d *decoder) eval(target reflect.Value) { } val, err := gouuid.Parse(frame.String) if err != nil { - d.error(fmt.Errorf("invalid UUID in Avro encoding: %w", err)) + d.error(errors.Newf("invalid UUID in Avro encoding: %w", err)) } else { target.Set(reflect.ValueOf(val)) } @@ -194,7 +194,7 @@ func (d *decoder) eval(target reflect.Value) { } case vm.SetDefault: if d.program.makeDefault[d.pc] == nil { - panic(fmt.Errorf("no makeDefault at PC %d; prog %p", d.pc, &d.program.makeDefault[0])) + panic(errors.Newf("no makeDefault at PC %d; prog %p", d.pc, &d.program.makeDefault[0])) } v := d.program.makeDefault[d.pc]() target.Field(inst.Operand).Set(v) @@ -279,9 +279,9 @@ func (d *decoder) eval(target reflect.Value) { // This doesn't actually halt, but it doesn't seem to matter. return } - d.error(fmt.Errorf("runtime error: %v, frame: %v, pc: %v", d.program.Errors[inst.Operand-1], frame, d.pc)) + d.error(errors.Newf("runtime error: %v, frame: %v, pc: %v", d.program.Errors[inst.Operand-1], frame, d.pc)) default: - d.error(fmt.Errorf("unknown instruction %v", d.program.Instructions[d.pc])) + d.error(errors.Newf("unknown instruction %v", d.program.Instructions[d.pc])) } } } diff --git a/encode.go b/encode.go index a5aafc3..b14c49e 100644 --- a/encode.go +++ b/encode.go @@ -3,7 +3,7 @@ package avro import ( "bytes" "encoding/binary" - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "math" "reflect" "sort" @@ -114,13 +114,13 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty switch def := at.Def.(type) { case *schema.RecordDefinition: if t.Kind() != reflect.Struct { - return errorEncoder(fmt.Errorf("expected struct")) + return errorEncoder(errors.Newf("expected struct")) } if len(info.Entries) == 0 { // The type itself might contribute information. info1, err := typeinfo.ForType(t) if err != nil { - return errorEncoder(fmt.Errorf("cannot get info for %s: %v", info.Type, err)) + return errorEncoder(errors.Newf("cannot get info for %s: %v", info.Type, err)) } info = info1 } @@ -143,7 +143,7 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty for i, f := range def.Fields() { fieldInfo, ok := entryByName(info.Entries, f.Name()) if !ok { - return errorEncoder(fmt.Errorf("field %q not found in %s", f.Name(), t)) + return errorEncoder(errors.Newf("field %q not found in %s", f.Name(), t)) } fieldIndex := fieldInfo.FieldIndex fieldEncoders[i] = b.typeEncoder(f.Type(), t.Field(fieldIndex).Type, info.Entries[i]) @@ -159,7 +159,7 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty case *schema.FixedDefinition: return fixedEncoder{def.SizeBytes()}.encode default: - return errorEncoder(fmt.Errorf("unknown definition type %T", def)) + return errorEncoder(errors.Newf("unknown definition type %T", def)) } case *schema.UnionField: atypes := at.ItemTypes() @@ -167,7 +167,7 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty case reflect.Ptr: // It's a union of null and one other type, represented by a Go pointer. if len(atypes) != 2 { - return errorEncoder(fmt.Errorf("unexpected item type count in union")) + return errorEncoder(errors.Newf("unexpected item type count in union")) } switch { case info.Entries[0].Type == nil: @@ -181,7 +181,7 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty encodeElem: b.typeEncoder(atypes[0], info.Entries[0].Type, info.Entries[0]), }.encode default: - return errorEncoder(fmt.Errorf("unexpected types in union")) + return errorEncoder(errors.Newf("unexpected types in union")) } case reflect.Interface: enc := unionEncoder{ @@ -200,7 +200,7 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty } return enc.encode default: - return errorEncoder(fmt.Errorf("union type is not pointer or interface")) + return errorEncoder(errors.Newf("union type is not pointer or interface")) } case *schema.MapField: return mapEncoder{b.typeEncoder(at.ItemType(), t.Elem(), info)}.encode @@ -225,13 +225,13 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty return timestampMicrosEncoder } else { // TODO timestamp-millis support. - return errorEncoder(fmt.Errorf("cannot encode time.Time as long with logical type %q", lt)) + return errorEncoder(errors.Newf("cannot encode time.Time as long with logical type %q", lt)) } case durationType: if lt := logicalType(at); lt == durationNanos { return durationNanosEncoder } else { - return errorEncoder(fmt.Errorf("cannot encode %t as long with logical type %q", t, lt)) + return errorEncoder(errors.Newf("cannot encode %t as long with logical type %q", t, lt)) } default: return longEncoder @@ -241,12 +241,12 @@ func (b *encoderBuilder) typeEncoder(at schema.AvroType, t reflect.Type, info ty if lt := logicalType(at); lt == uuid { return uuidEncoder } else { - return errorEncoder(fmt.Errorf("cannot encode %v as string with logical type %q", t, lt)) + return errorEncoder(errors.Newf("cannot encode %v as string with logical type %q", t, lt)) } } return stringEncoder default: - return errorEncoder(fmt.Errorf("unknown avro schema type %T", at)) + return errorEncoder(errors.Newf("unknown avro schema type %T", at)) } } @@ -424,7 +424,7 @@ func (ue unionEncoder) encode(e *encodeState, v reflect.Value) { e.writeLong(int64(ue.nullIndex)) return } - e.error(fmt.Errorf("nil value not allowed")) + e.error(errors.Newf("nil value not allowed")) } v = v.Elem() vt := v.Type() @@ -435,7 +435,7 @@ func (ue unionEncoder) encode(e *encodeState, v reflect.Value) { return } } - e.error(fmt.Errorf("unknown type for union %s", vt)) + e.error(errors.Newf("unknown type for union %s", vt)) } type ptrUnionEncoder struct { diff --git a/go.mod b/go.mod index 6a36223..49078bb 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/heetch/avro -go 1.16 +go 1.19 require ( github.com/actgardner/gogen-avro/v10 v10.2.1 @@ -12,3 +12,14 @@ require ( gopkg.in/httprequest.v1 v1.2.1 gopkg.in/retry.v1 v1.0.3 ) + +require ( + github.com/golang/snappy v0.0.4 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/julienschmidt/httprouter v1.3.0 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e // indirect + golang.org/x/net v0.0.0-20200505041828-1ed23360d12c // indirect + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect + gopkg.in/errgo.v1 v1.0.0 // indirect +) diff --git a/go.sum b/go.sum index d522c08..d367adc 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ github.com/actgardner/gogen-avro/v10 v10.2.1 h1:z3pOGblRjAJCYpkIJ8CmbMJdksi4rAhaygw0dyXZ930= github.com/actgardner/gogen-avro/v10 v10.2.1/go.mod h1:QUhjeHPchheYmMDni/Nx7VB0RsT/ee8YIgGY/xpEQgQ= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= @@ -36,15 +34,12 @@ github.com/linkedin/goavro/v2 v2.11.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a h1:3QH7VyOaaiUHNrA9Se4YQIRkDTCw1EJls9xTUCaCeRM= github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a/go.mod h1:4r5QyqhjIWCcK8DO4KMclc5Iknq5qVBAlbYYzAbUScQ= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -80,6 +75,4 @@ gopkg.in/retry.v1 v1.0.3 h1:a9CArYczAVv6Qs6VGoLMio99GEs7kY9UzSF9+LD+iGs= gopkg.in/retry.v1 v1.0.3/go.mod h1:FJkXmWiMaAo7xB+xhvDF59zhfjDWyzmyAxiT4dB688g= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gotype.go b/gotype.go index d5e4f10..2272518 100644 --- a/gotype.go +++ b/gotype.go @@ -3,6 +3,7 @@ package avro import ( "encoding/json" "fmt" + "gopkg.in/errgo.v2/fmt/errors" "reflect" "strings" @@ -40,30 +41,30 @@ type errorSchema struct { // Otherwise TypeOf(T) is derived according to // the following rules: // -// - int, int64 and uint32 encode as "long" -// - int32, int16, uint16, int8 and uint8 encode as "int" -// - float32 encodes as "float" -// - float64 encodes as "double" -// - string encodes as "string" -// - Null{} encodes as "null" -// - time.Duration encodes as {"type": "long", "logicalType": "duration-nanos"} -// - time.Time encodes as {"type": "long", "logicalType": "timestamp-micros"} -// - github.com/google/uuid.UUID encodes as {"type": "string", "logicalType": "string"} -// - [N]byte encodes as {"type": "fixed", "name": "go.FixedN", "size": N} -// - a named type with underlying type [N]byte encodes as [N]byte but typeName(T) for the name. -// - []T encodes as {"type": "array", "items": TypeOf(T)} -// - map[string]T encodes as {"type": "map", "values": TypeOf(T)} -// - *T encodes as ["null", TypeOf(T)] -// - a named struct type encodes as {"type": "record", "name": typeName(T), "fields": ...} -// where the fields are encoded as described below. -// - interface types are disallowed. +// - int, int64 and uint32 encode as "long" +// - int32, int16, uint16, int8 and uint8 encode as "int" +// - float32 encodes as "float" +// - float64 encodes as "double" +// - string encodes as "string" +// - Null{} encodes as "null" +// - time.Duration encodes as {"type": "long", "logicalType": "duration-nanos"} +// - time.Time encodes as {"type": "long", "logicalType": "timestamp-micros"} +// - github.com/google/uuid.UUID encodes as {"type": "string", "logicalType": "string"} +// - [N]byte encodes as {"type": "fixed", "name": "go.FixedN", "size": N} +// - a named type with underlying type [N]byte encodes as [N]byte but typeName(T) for the name. +// - []T encodes as {"type": "array", "items": TypeOf(T)} +// - map[string]T encodes as {"type": "map", "values": TypeOf(T)} +// - *T encodes as ["null", TypeOf(T)] +// - a named struct type encodes as {"type": "record", "name": typeName(T), "fields": ...} +// where the fields are encoded as described below. +// - interface types are disallowed. // // Struct fields are encoded as follows: // -// - unexported struct fields are ignored -// - the field name is taken from the Go field name, or from a "json" tag for the field if present. -// - the default value for the field is the zero value for the type. -// - anonymous struct fields are disallowed (this restriction may be lifted in the future). +// - unexported struct fields are ignored +// - the field name is taken from the Go field name, or from a "json" tag for the field if present. +// - the default value for the field is the zero value for the type. +// - anonymous struct fields are disallowed (this restriction may be lifted in the future). func TypeOf(x interface{}) (*Type, error) { return globalNames.TypeOf(x) } @@ -102,7 +103,7 @@ func avroTypeOfUncached(names *Names, t reflect.Type) (*Type, error) { } data, err := json.Marshal(schemaVal) if err != nil { - return nil, fmt.Errorf("cannot marshal generated schema: %v", err) + return nil, errors.Newf("cannot marshal generated schema: %v", err) } at, err := ParseType(string(data)) if err != nil { @@ -114,11 +115,11 @@ func avroTypeOfUncached(names *Names, t reflect.Type) (*Type, error) { } data1, err := json.Marshal(names.renameSchema(at.avroType)) if err != nil { - return nil, fmt.Errorf("cannot marshal generated renamed schema: %v", err) + return nil, errors.Newf("cannot marshal generated renamed schema: %v", err) } at, err = ParseType(string(data1)) if err != nil { - return nil, fmt.Errorf("cannot parse generated renamed type: %v", err) + return nil, errors.Newf("cannot parse generated renamed type: %v", err) } return at, nil } @@ -194,7 +195,7 @@ func (gts *goTypeSchema) schemaForGoType(t reflect.Type) (interface{}, error) { case reflect.Map: // TODO support the same map keys types that JSON does. if t.Key().Kind() != reflect.String { - return nil, fmt.Errorf("map must have string key") + return nil, errors.Newf("map must have string key") } values, err := gts.schemaForGoType(t.Elem()) if err != nil { @@ -231,7 +232,7 @@ func (gts *goTypeSchema) schemaForGoType(t reflect.Type) (interface{}, error) { for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.Anonymous { - return nil, fmt.Errorf("anonymous fields not yet supported (in %s)", t) + return nil, errors.Newf("anonymous fields not yet supported (in %s)", t) } // Technically in Go, every field is optional because // that's the way that the encoding/json package works, @@ -267,7 +268,7 @@ func (gts *goTypeSchema) schemaForGoType(t reflect.Type) (interface{}, error) { } if t.Elem() != reflect.TypeOf(byte(0)) { - return nil, fmt.Errorf("the only array type supported is [...]byte, not %s", t) + return nil, errors.Newf("the only array type supported is [...]byte, not %s", t) } return gts.define(t, map[string]interface{}{ "type": "fixed", @@ -275,7 +276,7 @@ func (gts *goTypeSchema) schemaForGoType(t reflect.Type) (interface{}, error) { }, fmt.Sprintf("go.Fixed%d", t.Len())) case reflect.Ptr: if t.Elem().Kind() == reflect.Ptr { - return nil, fmt.Errorf("can only cope with a single level of pointer indirection") + return nil, errors.Newf("can only cope with a single level of pointer indirection") } elem, err := gts.schemaForGoType(t.Elem()) if err != nil { @@ -287,9 +288,9 @@ func (gts *goTypeSchema) schemaForGoType(t reflect.Type) (interface{}, error) { }, nil case reflect.Interface: // TODO fill in from the writer schema. - return nil, fmt.Errorf("interface types (%s) not yet supported (use avrogo instead)", t) + return nil, errors.Newf("interface types (%s) not yet supported (use avrogo instead)", t) default: - return nil, fmt.Errorf("cannot make Avro schema for Go type %s", t) + return nil, errors.Newf("cannot make Avro schema for Go type %s", t) } } @@ -306,7 +307,7 @@ func (gts *goTypeSchema) define(t reflect.Type, def0 interface{}, defaultName st // as well as the type name. See https://github.com/heetch/avro/issues/35 if name = t.Name(); name == "" { if name = defaultName; name == "" { - return nil, fmt.Errorf("cannot use unnamed type %s as Avro type", t) + return nil, errors.Newf("cannot use unnamed type %s as Avro type", t) } } def["name"] = name @@ -314,7 +315,7 @@ func (gts *goTypeSchema) define(t reflect.Type, def0 interface{}, defaultName st for _, def := range gts.defs { if def.name == name { // TODO use package path to disambiguate. See https://github.com/heetch/avro/issues/35 - return nil, fmt.Errorf("duplicate struct type name %q", name) + return nil, errors.Newf("duplicate struct type name %q", name) } } gts.defs[t] = goTypeDef{ @@ -472,13 +473,13 @@ func (gts *goTypeSchema) defaultForType(t reflect.Type) (interface{}, error) { // It's a generated type - producing a correctly formed default value // for it needs a bit more work so we punt on doing it for now. // TODO make default values for struct-typed fields work in all cases. - return nil, fmt.Errorf("value fields of struct types generated by avrogo are not yet supported (type %s)", t) + return nil, errors.Newf("value fields of struct types generated by avrogo are not yet supported (type %s)", t) } fields := make(map[string]interface{}) for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.Anonymous { - return nil, fmt.Errorf("anonymous fields not yet supported (in %s)", t) + return nil, errors.Newf("anonymous fields not yet supported (in %s)", t) } name, _ := typeinfo.JSONFieldName(f) if name == "" { diff --git a/internal/testtypes/prototest1.pb.go b/internal/testtypes/prototest1.pb.go index 344d4ce..ed232f7 100644 --- a/internal/testtypes/prototest1.pb.go +++ b/internal/testtypes/prototest1.pb.go @@ -7,13 +7,13 @@ package testtypes import ( - fmt "fmt" + "gopkg.in/errgo.v2/fmt/errors" math "math" ) // Reference imports to suppress errors if they are not otherwise used. -//var _ = proto.Marshal -var _ = fmt.Errorf +// var _ = proto.Marshal +var _ = errors.Newf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file @@ -69,9 +69,10 @@ func (m *MessageA) Reset() { *m = MessageA{} } // This is commented out because otherwise the logging in tests // calls it, which we don't want. -//func (m *MessageA) String() string { -// return proto.CompactTextString(m) -// } +// +// func (m *MessageA) String() string { +// return proto.CompactTextString(m) +// } func (*MessageA) ProtoMessage() {} func (*MessageA) Descriptor() ([]byte, []int) { return fileDescriptor_8f1e2929fcb7cefa, []int{0} @@ -139,9 +140,10 @@ func (m *MessageB) Reset() { *m = MessageB{} } // This is commented out because otherwise the logging in tests // calls it, which we don't want. -//func (m *MessageB) String() string { -// return proto.CompactTextString(m) -//} +// +// func (m *MessageB) String() string { +// return proto.CompactTextString(m) +// } func (*MessageB) ProtoMessage() {} func (*MessageB) Descriptor() ([]byte, []int) { return fileDescriptor_8f1e2929fcb7cefa, []int{1} diff --git a/internal/typeinfo/schema.go b/internal/typeinfo/schema.go index 7280898..ada5be6 100644 --- a/internal/typeinfo/schema.go +++ b/internal/typeinfo/schema.go @@ -1,11 +1,10 @@ package typeinfo import ( - "fmt" - "github.com/actgardner/gogen-avro/v10/parser" "github.com/actgardner/gogen-avro/v10/resolver" "github.com/actgardner/gogen-avro/v10/schema" + "gopkg.in/errgo.v2/fmt/errors" ) // ParseSchema parses the given Avro type and resolves @@ -20,11 +19,11 @@ func ParseSchema(s string, ns *parser.Namespace) (schema.AvroType, error) { } avroType, err := ns.TypeForSchema([]byte(s)) if err != nil { - return nil, fmt.Errorf("invalid schema %q: %v", s, err) + return nil, errors.Newf("invalid schema %q: %v", s, err) } for _, def := range ns.Roots { if err := resolver.ResolveDefinition(def, ns.Definitions); err != nil { - return nil, fmt.Errorf("cannot resolve references in schema\n%s\n: %v", s, err) + return nil, errors.Newf("cannot resolve references in schema\n%s\n: %v", s, err) } } return avroType, nil diff --git a/internal/typeinfo/typeinfo.go b/internal/typeinfo/typeinfo.go index 121059d..e6f33d0 100644 --- a/internal/typeinfo/typeinfo.go +++ b/internal/typeinfo/typeinfo.go @@ -1,7 +1,7 @@ package typeinfo import ( - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "log" "reflect" "strings" @@ -67,7 +67,7 @@ func ForType(t reflect.Type) (Info, error) { if f.Anonymous { // TODO consider struct embedding. // https://github.com/heetch/avro/issues/40 - return Info{}, fmt.Errorf("anonymous fields not supported") + return Info{}, errors.Newf("anonymous fields not supported") } if shouldOmitField(f) { continue diff --git a/names.go b/names.go index 499363e..65b4eca 100644 --- a/names.go +++ b/names.go @@ -1,7 +1,7 @@ package avro import ( - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "reflect" "sync" @@ -68,7 +68,7 @@ func (names *Names) Marshal(x interface{}) ([]byte, *Type, error) { // Rename panics if oldName is any of the built-in Avro types. func (n *Names) Rename(oldName string, newName string, newAliases ...string) *Names { if builtinTypes[oldName] { - panic(fmt.Errorf("rename of built-in type %q to %q", oldName, newName)) + panic(errors.Newf("rename of built-in type %q to %q", oldName, newName)) } n1 := &Names{ renames: make(map[string][]string), @@ -98,11 +98,11 @@ func (n *Names) RenameType(x interface{}, newName string, newAliases ...string) // See https://github.com/heetch/avro/issues/38 t, err := TypeOf(x) if err != nil { - panic(fmt.Errorf("cannot rename %T to %q: cannot get Avro type: %v", x, newName, err)) + panic(errors.Newf("cannot rename %T to %q: cannot get Avro type: %v", x, newName, err)) } name := t.Name() if name == "" { - panic(fmt.Errorf("cannot rename %T to %q: it does not represent an Avro definition", x, newName)) + panic(errors.Newf("cannot rename %T to %q: it does not represent an Avro definition", x, newName)) } return n.Rename(name, newName, newAliases...) } @@ -157,7 +157,7 @@ func (names *Names) renameSchema1(at schema.AvroType, enclosingNamespace string, case *schema.FixedDefinition: case *schema.EnumDefinition: default: - panic(fmt.Errorf("unknown definition type %T", adef)) + panic(errors.Newf("unknown definition type %T", adef)) } delete(def, "namespace") def["name"] = relativeName(enclosingNamespace, qname) @@ -215,7 +215,7 @@ func copyOfSchemaObj(at interface{}) map[string]interface{} { } return obj1 default: - panic(fmt.Errorf("unexpected type for Avro definition %T", obj)) + panic(errors.Newf("unexpected type for Avro definition %T", obj)) } } diff --git a/reader.go b/reader.go index 152c3d9..8acca14 100644 --- a/reader.go +++ b/reader.go @@ -2,7 +2,7 @@ package avro import ( "encoding/binary" - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "io" "math" ) @@ -77,7 +77,7 @@ func (d *decoder) readBytes() []byte { // Make a temporary buffer for the bytes, limiting the size to // an arbitrary sane default (~2.2GB). if size < 0 || size > math.MaxInt32 { - d.error(fmt.Errorf("length out of range: %d", size)) + d.error(errors.Newf("length out of range: %d", size)) } return d.readFixed(int(size)) } @@ -110,7 +110,7 @@ func (d *decoder) readLong() int64 { case nr == 0: d.error(io.ErrUnexpectedEOF) default: - d.error(fmt.Errorf("integer too large")) + d.error(errors.Newf("integer too large")) } panic("unreachable") } diff --git a/singledecoder.go b/singledecoder.go index 4e0e674..9014fdf 100644 --- a/singledecoder.go +++ b/singledecoder.go @@ -2,7 +2,7 @@ package avro import ( "context" - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "reflect" "sync" ) @@ -82,17 +82,17 @@ func NewSingleDecoder(r DecodingRegistry, names *Names) *SingleDecoder { func (c *SingleDecoder) Unmarshal(ctx context.Context, data []byte, x interface{}) (*Type, error) { v := reflect.ValueOf(x) if v.Kind() != reflect.Ptr { - return nil, fmt.Errorf("cannot decode into non-pointer value %T", x) + return nil, errors.Newf("cannot decode into non-pointer value %T", x) } v = v.Elem() vt := v.Type() wID, body := c.registry.DecodeSchemaID(data) if wID == 0 && body == nil { - return nil, fmt.Errorf("cannot get schema ID from message") + return nil, errors.Newf("cannot get schema ID from message") } prog, err := c.getProgram(ctx, vt, wID) if err != nil { - return nil, fmt.Errorf("cannot unmarshal: %v", err) + return nil, errors.Newf("cannot unmarshal: %v", err) } return unmarshal(nil, body, prog, v) } diff --git a/singledecoder_test.go b/singledecoder_test.go index 5073977..2b2a831 100644 --- a/singledecoder_test.go +++ b/singledecoder_test.go @@ -2,7 +2,7 @@ package avro_test import ( "context" - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "testing" qt "github.com/frankban/quicktest" @@ -176,7 +176,7 @@ func (m memRegistry) DecodeSchemaID(msg []byte) (int64, []byte) { func (m memRegistry) SchemaForID(ctx context.Context, id int64) (*avro.Type, error) { t, ok := m[id] if !ok { - return nil, fmt.Errorf("schema not found for id %d", id) + return nil, errors.Newf("schema not found for id %d", id) } return t, nil } @@ -194,5 +194,5 @@ func (m memRegistry) IDForSchema(ctx context.Context, schema *avro.Type) (int64, return id, nil } } - return 0, fmt.Errorf("schema not found") + return 0, errors.Newf("schema not found") } diff --git a/type.go b/type.go index a9d4d8a..fe84edc 100644 --- a/type.go +++ b/type.go @@ -2,7 +2,7 @@ package avro import ( "encoding/json" - "fmt" + "gopkg.in/errgo.v2/fmt/errors" "strings" "sync" @@ -216,10 +216,10 @@ func (c *canonicalizer) canonicalValue1(at schema.AvroType) interface{} { } return cf default: - panic(fmt.Errorf("unknown definition type %T", def)) + panic(errors.Newf("unknown definition type %T", def)) } default: - panic(fmt.Errorf("unknown Avro type %T", at)) + panic(errors.Newf("unknown Avro type %T", at)) } }