https://github.com/alta/protopatch
protoc-gen-go patch utility
https://github.com/alta/protopatch
go golang protobuf protoc protocol-buffers protos
Last synced: 3 months ago
JSON representation
protoc-gen-go patch utility
- Host: GitHub
- URL: https://github.com/alta/protopatch
- Owner: alta
- License: mit
- Created: 2020-06-18T00:23:18.000Z (about 6 years ago)
- Default Branch: main
- Last Pushed: 2025-05-29T05:34:56.000Z (about 1 year ago)
- Last Synced: 2025-05-29T06:36:00.206Z (about 1 year ago)
- Topics: go, golang, protobuf, protoc, protocol-buffers, protos
- Language: Go
- Homepage:
- Size: 464 KB
- Stars: 109
- Watchers: 8
- Forks: 20
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# protopatch
[](https://pkg.go.dev/github.com/alta/protopatch) [](https://github.com/alta/protopatch/actions)
Patch `protoc` plugin output with Go-specific features. The `protoc-gen-go-patch` command wraps calls to Go code generators like [`protoc-gen-go`](https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go) or [`protoc-gen-go-grpc`](https://pkg.go.dev/google.golang.org/grpc/cmd/protoc-gen-go-grpc) and patches the Go syntax before being written to disk.
## Install
`go install github.com/alta/protopatch/cmd/protoc-gen-go-patch`
## Usage
After installing `protoc-gen-go-patch`, use it by specifying it with a `--go-patch_out=...` argument to `protoc`:
```shell
protoc \
-I . \
-I `go list -m -f {{.Dir}} github.com/alta/protopatch` \
-I `go list -m -f {{.Dir}} google.golang.org/protobuf` \
--go-patch_out=plugin=go,paths=source_relative:. \
--go-patch_out=plugin=go-grpc,paths=source_relative:. \
*.proto
```
## Features
Patches are defined via an `Options` extension on messages, fields, `oneof` fields, enums, and enum values.
- `go.message` — message options, which modify the generated Go struct for a message.
- `go.field` — message field options, which modify Go struct fields and getter methods.
- `go.oneof` — oneof field options, which modify struct fields, interface types, and wrapper types.
- `go.enum` — enum options, which modify Go enum types and values.
- `go.value` — enum value options, which modify Go const values.
### Custom Names
```proto
import "patch/go.proto";
message OldName {
option (go.message).name = 'NewName';
int id = 1 [(go.field).name = 'ID'];
}
enum Error {
option (go.enum).name = 'ProtocolError';
INVALID = 1 [(go.value).name = 'ErrInvalid'];
NOT_FOUND = 2 [(go.value).name = 'ErrNotFound'];
TOO_FUN = 3 [(go.value).name = 'ErrTooFun'];
}
```
#### Alternate Syntax
Multiple options can be grouped together with a message bounded by `{}`:
```proto
import "patch/go.proto";
message OldName {
option (go.message) = {name: 'NewName'};
int32 id = 1 [(go.field) = {name: 'ID'}];
}
enum Error {
option (go.enum) = {name: 'ProtocolError'};
INVALID = 1 [(go.value) = {name: 'ErrInvalid'}];
NOT_FOUND = 2 [(go.value) = {name: 'ErrNotFound'}];
TOO_FUN = 3 [(go.value) = {name: 'ErrTooFun'}];
}
```
### Struct Tags
```proto
message ToDo {
int32 id = 1 [(go.field).name: 'ID', (go.field).tags = 'xml:"id,attr"'];
string description = 2 [(go.field).tags: 'xml:"desc"'];
}
```
#### Alternate Syntax
Multiple options can be grouped together with a message bounded by `{}`:
```proto
message ToDo {
int32 id = 1 [(go.field) = {name: 'ID', tags: 'xml:"id,attr"'}];
string description = 2 [(go.field) = {tags: 'xml:"desc"'}];
}
```
### Embedded Fields
A message field can be embedded in the generated [Go struct](https://golang.org/ref/spec#Struct_types) with the `(go.field).embed` option. This only works for message fields, and will not work for oneof fields or basic types.
```proto
import "patch/go.proto";
message A {
B b = 1 [(go.field).embed = true];
}
message B {
string value = 1;
}
```
The resulting Go struct will partially have the form:
```go
type A struct {
*B
}
type B struct {
Value string
}
var a A
a.Value = "value" // This works because B is embedded in A
```
#### Alternate Syntax
Multiple options can be grouped together with a message bounded by `{}`:
```proto
import "patch/go.proto";
message A {
B b = 1 [(go.field) = {embed: true}];
}
message B {
string value = 1;
}
```
### Linting
Protopatch can automatically “lint” generated names into something resembling [idiomatic Go style](https://golang.org/doc/effective_go.html#names). This feature should be considered *unstable*, and the names it generates are subject to change as this feature evolves.
- **Initialisms:** names with `ID` or `URL` or other well-known initialisms will have their case preserved. For example `Id` would lint to `ID`, and `ApiBaseUrl` would lint to `APIBaseURL`.
- **Stuttering:** it will attempt to remove repeated prefixed names from enum values. An enum value of type `Foo` named `Foo_FOO_BAR` would lint to `FooBar`.
To lint all generated Go names, add `option (go.lint).all = true` to your `proto` file. To lint only enum values, add `option (go.lint).values = true`. To specify one or more custom initialisms, specify an initialism with `option (go.lint).initialisms = 'HSV'` for the `HSV` initialism. All names with `HSV` will preserve its case.
```proto
option (go.lint).all = true;
option (go.lint).initialisms = 'RGB';
option (go.lint).initialisms = 'RGBA';
option (go.lint).initialisms = 'HSV';
enum Protocol {
// PROTOCOL_INVALID value should lint to ProtocolInvalid.
PROTOCOL_INVALID = 0;
// PROTOCOL_IP value should lint to ProtocolIP.
PROTOCOL_IP = 1;
// PROTOCOL_UDP value should lint to ProtocolUDP.
PROTOCOL_UDP = 2;
// PROTOCOL_TCP value should lint to ProtocolTCP.
PROTOCOL_TCP = 3;
}
message Color {
oneof value {
// rgb should lint to RGB.
string rgb = 1;
// rgba should lint to RGBA.
string rgba = 2;
// hsv should lint to HSV.
string hsv = 3;
}
}
```