Skip to content

Instantly share code, notes, and snippets.

@shaxbee
Last active June 27, 2016 02:44
Show Gist options
  • Save shaxbee/b2840997c20d9c07c27476dba4f971b0 to your computer and use it in GitHub Desktop.
Save shaxbee/b2840997c20d9c07c27476dba4f971b0 to your computer and use it in GitHub Desktop.
Protobuf GRPC compiler driver
#!/usr/bin/env perl
use strict;
use warnings;
use File::Which;
use File::Spec;
use File::Basename;
use Env qw(GOPATH);
use Getopt::Long;
my $protoc = File::Which::which('protoc');
my $grpc_inc = "-I${GOPATH}/src/github.com/gengo/grpc-gateway/third_party/googleapis";
my $std_modules = {
'google/api/annotations.proto' => 'github.com/gengo/grpc-gateway/third_party/googleapis/google/api',
'google/protobuf/descriptor.proto' => 'github.com/golang/protobuf/protoc-gen-go/descriptor'
};
__PACKAGE__->main();
my $verbose;
sub mapping {
my ($t, $r) = @$_;
if (my $std = $$std_modules{$t}) {
return "M${t}=${std}"
}
my $dir = dirname(File::Spec->rel2abs($t, $r));
my $rel = File::Spec->abs2rel($dir, $GOPATH . "/src");
return "M${t}=${rel}"
}
sub include_path {
my ($i) = @_;
return '-I' . dirname($i)
}
sub protoc {
my ($t, $includes, $gen, $output, $params, $alias) = @_;
if (!defined($output)) {
$output = '.'
};
if (!defined($alias)) {
$alias = $gen
};
if (!defined($includes)) {
$includes = []
}
push @$includes, include_path($t);
my $genp;
if (defined($params) && scalar(@$params)) {
$genp = "--${gen}_out=${\join(',', @$params)}:${output}"
} else {
$genp = "--${gen}_out=${output}"
};
if ($verbose) {
print STDERR "$protoc " . join(' ', @$includes) . " $genp $t\n";
};
return system($protoc, @$includes, $genp, $t) == 0;
}
sub protoc_gen_go {
my ($t, $imports, $includes, $output, $params, $plugins, $alias) = @_;
if (!defined($params)) {
$params = []
};
if (defined($imports)) {
push @$params, map { mapping($_) } @$imports;
};
if (defined($plugins)) {
push @$params, ("plugins=${\join('+,', @$plugins)}")
};
return protoc($t, $includes, 'go', $output, $params, $alias)
}
sub protoc_gen_grpc {
my ($t, $imports, $output) = @_;
if (!defined($imports)) {
$imports = []
}
push(@$imports, ["google/api/annotations.proto"]);
return protoc_gen_go(
$t,
$imports,
[$grpc_inc],
$output,
[],
['grpc'],
'grpc'
);
}
sub protoc_gen_grpc_gw {
my ($t, $imports, $output) = @_;
my $params = [map { mapping($_) } @$imports];
return protoc($t, [$grpc_inc], 'grpc-gateway', $output, $params)
}
sub protoc_gen_swagger {
my ($t, $output) = @_;
return protoc($t, [$grpc_inc], 'swagger', $output)
}
sub main {
my $usage = <<END_USAGE;
Usage:
protogen.pl [options] [--] PROTO
Options:
-v | --verbose Verbose output.
--with-gateway Generate grpc-gateway code.
--with-swagger Generate swagger API definitions.
--swagger-out=<dir> Destination for swagger files.
--import=<imports> Comma-separated list of proto import mappings.
END_USAGE
sub parse_imports {
my ($name, $raw) = @_;
return [map([split(':')], split(',', $raw))];
}
my $grpc_out;
my $swagger_out;
my $with_gateway;
my $with_swagger;
my $imports;
GetOptions(
"verbose" => \$verbose,
"with-gateway" => \$with_gateway,
"with-swagger" => \$with_swagger,
"grpc_out=s" => \$grpc_out,
"swagger-out=s" => \$swagger_out,
"import=s" => sub { $imports = parse_imports(@_) }
)
or die($usage);
if (scalar(@ARGV) != 1) {
die("PROTO is required\n" . $usage)
};
my $proto = pop @ARGV;
my $path = dirname($proto);
protoc_gen_grpc($proto, $imports, defined $grpc_out ? $grpc_out : $path)
or die("Failed to generate GRPC service.");
if ($with_gateway) {
protoc_gen_grpc_gw($proto, $imports, defined $grpc_out ? $grpc_out : $path)
or die("Failed to generate GRPC gateway.");
}
if ($with_swagger) {
protoc_gen_swagger($proto, defined $swagger_out ? $swagger_out : $path)
or die("Failed to generate Swagger API definitions.");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment