https://github.com/stackb/protoc-gen-starlark
Scriptable protoc plugins
https://github.com/stackb/protoc-gen-starlark
Last synced: 10 months ago
JSON representation
Scriptable protoc plugins
- Host: GitHub
- URL: https://github.com/stackb/protoc-gen-starlark
- Owner: stackb
- License: apache-2.0
- Created: 2023-06-08T05:41:16.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2023-06-10T23:00:41.000Z (over 2 years ago)
- Last Synced: 2025-02-14T14:51:41.251Z (11 months ago)
- Language: Starlark
- Size: 53.7 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://github.com/stackb/protoc-gen-starlark/actions/workflows/ci.yaml)
# protoc-gen-starlark
protobuf
starlark
`protoc-gen-starlark` is a scriptable protocol buffer plugin. It might just be
the the easiest way to write a protoc plugin! 😍
## Installation
Download a binary from the [releases
page](https://github.com/stackb/protoc-gen-starlark/releases), or install from source:
```sh
go install github.com/stackb/protoc-gen-starlark/cmd/protoc-gen-starlark@latest
```
## Usage
`protoc-gen-starlark` works like any other typical protoc plugin: it reads an
encoded `CodeGeneratorRequest` from stdin and writes an encoded
`CodeGeneratorResponse` to stdout.
The logic of generating a response is performed within a starlark script that
you must write. The simplest such script looks something like:
```py
pb = proto.package("google.protobuf.compiler")
def generate(request):
"""generate prepares the response.
Args:
request: the pb.CodeGeneratorRequest that was read from stdin.
Returns:
a pb.CodeGeneratorResponse
"""
return pb.CodeGeneratorResponse(
error = "not implemented",
)
def main(ctx):
"""main is the entrypoint function.
Args:
ctx: the script context. It has a struct member named
'vars' which is a StringDict of variables injected into
the entrypoint. vars is guaranteed to have an entry named
"request" that is the pb.CodeGeneratorRequest read from stdin.
Returns:
A single pb.CodeGeneratorResponse. Per skycfg semantics,
the return value from `main` must be a list however so it
is wrapped accordingly.
"""
return [generate(ctx.vars["request"])]
```
Although starlark is an interpreted language, the protobuf message types are stongly typed: it is an error to set/get fields that are not part of the message definition. See [stackb/grpc-starlark](https://github.com/stackb/grpc-starlark) and [stripe/skycfg](https://github.com/stripe/skycfg) for more details about this.
> `protoc-gen-starlark` is built using
> [stackb/grpc-starlark](https://github.com/stackb/grpc-starlark) and shares the
> same command line flags.
A sample protoc invocation might look something like:
```sh
$ export PROTOC_GEN_STARLARK_SCRIPT=foo.star
$ protoc \
--foo_out=./gendir \
--plugin=protoc-gen-foo=/usr/bin/protoc-gen-starlark
```
In this case `protoc-gen-starlark` discovers which script to evaluate using the
`PROTOC_GEN_STARLARK_SCRIPT` environment variable.
Another strategy is to copy/rename `protoc-gen-starlark` and the script to a
common name. If a file named `$0.star` exists where `$0` is the name of the
executable itself, this will be loaded. For example:
```sh
$ ln -s /usr/bin/protoc-gen-starlark tools/protoc-gen-foo
$ mv foo.plugin.star tools/protoc-gen-foo.star
$ ln -s /usr/bin/protoc-gen-starlark tools/protoc-gen-bar
$ mv bar.plugin.star tools/protoc-gen-bar.star
$ protoc \
--foo_out=./gendir \
--plugin=protoc-gen-foo=./tools/protoc-gen-foo
--bar_out=./gendir \
--plugin=protoc-gen-bar=./tools/protoc-gen-bar
```
Alternatively, a shell script can be used to wrap the invocation of the plugin:
```sh
#!/bin/bash
# protoc-gen-foo.sh wraps protoc-gen-starlark and sets
# the file argument explicitly.
set -euox pipefail
/usr/bin/protoc-gen-starlark \
-file ./tools/protoc-gen-foo.star
```
```sh
$ protoc \
--foo_out=./gendir \
--plugin=protoc-gen-foo=./tools/protoc-gen-foo.sh
```
By default, the message types from
[plugin.proto](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/plugin.proto)
are pre-loaded. You can make additional types available to `proto.package`
using the `--protoset=/path/to/a/descriptor_set_out.pb` flag.