Protocol Buffers compiler plugin allows you quickly generate boilerplate code from your Google Protocol Buffer (proto) definitions using template scripts on Python.
The plugin creates a JSON file with intermediate representation (IR) of your proto definitions and then runs template scripts on Python to generate code.
The plugin provides methods to easily navigate through specific proto definitions in the intermediate representation. For example, to iterate through all services, you can write the following:
# for each .proto file
for file, _ in IR.node_iter(IR.decl, 'FILE'):
# for each service
for service, _ in IR.node_iter(file['decl'], 'SERVICE'):
print('service:', service['name'])
# for each method
for method, _ in IR.node_iter(service['decl']):
print(' method:', method['name'])
print(' input:', method['input'])
print(' streaming:', method['client_streaming'])
print(' output:', method['output'])
print(' streaming:', method['server_streaming'])
The script should implement the function that takes an IR filename and optional a .proto file name parameters:
def boiling(json_filename: str, proto_filename: str | None)
The plugin calls the boiling()
function to generate code. The json_filename
file contains an intermediate representation of all processed .proto files.
The additional parameter proto_filename
can be used to filter the data and
generate code only for the file specified in the TEMPLATE_LIST
parameter
of the configuration file.
The script should output the result code into the stdout
stream, for that
f-codec
, that wraps lonesome f-strings
in print()
can be used. Or you can involve any other output method, such as
the standard print()
function.
Example templates for generating .cpp, .swift and .proto source code can be found in "sample/templ/".
You can test code generation using the "sample/" templates and proto files by running:
./boiling-sample.sh
A configuration file (in Python) can contain the following parameters:
LOGGING_FILE
: a filename for logging,str
LOGGING_LEVEL
: a logging level,int
TEMPLATE_LIST
: a list of template files, with optionally specifying a .proto file,list[templ | tuple[templ, proto]]
templ
: a file mask, like "..py"proto
: a name of the specific .proto file that will be provided to the template'sboiling()
function.
IR_FILE
: a filename for saving IR,str
Custom configuration parameters must be prefixed with MY_
.
python3 -m venv ./venv
source ./venv/bin/activate
python3 -m pip install protoboiler
deactivate
To generate code, invoke protoc
and provide a configuration file (optional)
to the plugin using the protoboiler_out
parameter:
source ./venv/bin/activate
protoc -I$proto_dir --protoboiler_out=config=$config_file:$output_dir $proto_dir/*.proto
deactivate
Given you have a proto file "logging.proto":
syntax = "proto3";
package logging;
enum Level {
NOTSET = 0;
DEBUG = 10;
INFO = 20;
WARNING = 30;
ERROR = 40;
CRITICAL = 50;
}
and a template file "logging.cpp.py" that use f-codec
to output the generated code into stdout
:
# -*- coding: f -*-
from protoboiler import IR
def boiling(json_filename: str, _):
IR.open(json_filename)
f'''
// Generated file.
'''
for file, _ in IR.node_iter(IR.decl, 'FILE'):
for enum, _ in IR.node_iter(file['decl'], 'ENUM'):
f'''
enum class {enum['name']} {{
'''
for value in enum['value']:
f'''
{value['name']} = {value['number']},
'''
f'''
}};
'''
Running the following command:
protoc -I. --protoboiler_out=. ./logging.proto
you will generate "logging.cpp":
// Generated file.
enum class Level {
NOTSET = 0,
DEBUG = 10,
INFO = 20,
WARNING = 30,
ERROR = 40,
CRITICAL = 50,
};
Given that you have cloned this repository and installed poetry
, you can
install the plugin dependencies:
cd protoboiler/
poetry install
Now you are ready to run the plugin without installing the package.
The launcher
script is included in the repository for your convenience:
poetry run ./launcher $config_file $proto_dir $output_dir