mirror of https://github.com/hashicorp/consul
R.B. Boyer
3 years ago
committed by
GitHub
9 changed files with 387 additions and 258 deletions
@ -1,162 +0,0 @@
|
||||
#!/usr/bin/env bash |
||||
|
||||
SCRIPT_NAME="$(basename ${BASH_SOURCE[0]})" |
||||
pushd $(dirname ${BASH_SOURCE[0]}) > /dev/null |
||||
SCRIPT_DIR=$(pwd) |
||||
pushd ../.. > /dev/null |
||||
SOURCE_DIR=$(pwd) |
||||
popd > /dev/null |
||||
pushd ../functions > /dev/null |
||||
FN_DIR=$(pwd) |
||||
popd > /dev/null |
||||
popd > /dev/null |
||||
|
||||
source "${SCRIPT_DIR}/functions.sh" |
||||
|
||||
function usage { |
||||
cat <<-EOF |
||||
Usage: ${SCRIPT_NAME} [<options ...>] <proto filepath> |
||||
|
||||
Description: |
||||
Generate the Go files from protobuf definitions. In addition to |
||||
running the protoc generator it will also fixup build tags in the |
||||
generated code. |
||||
|
||||
Options: |
||||
--protoc-bin Path to protoc. |
||||
--import-replace Replace imports of google types with those from the protobuf repo. |
||||
--grpc Enable the gRPC plugin |
||||
-h | --help Print this help text. |
||||
EOF |
||||
} |
||||
|
||||
function err_usage { |
||||
err "$1" |
||||
err "" |
||||
err "$(usage)" |
||||
} |
||||
|
||||
function main { |
||||
local -i grpc=0 |
||||
local proto_path= |
||||
local protoc_bin= |
||||
|
||||
while test $# -gt 0 |
||||
do |
||||
case "$1" in |
||||
-h | --help ) |
||||
usage |
||||
return 0 |
||||
;; |
||||
--grpc ) |
||||
grpc=1 |
||||
shift |
||||
;; |
||||
--protoc-bin ) |
||||
protoc_bin="$2" |
||||
shift 2 |
||||
;; |
||||
* ) |
||||
proto_path="$1" |
||||
shift |
||||
;; |
||||
esac |
||||
done |
||||
|
||||
if test -z "${proto_path}" |
||||
then |
||||
err_usage "ERROR: No proto file specified" |
||||
return 1 |
||||
fi |
||||
|
||||
if test -z "${protoc_bin}" |
||||
then |
||||
protoc_bin="$(command -v protoc)" |
||||
if test -z "${protoc_bin}" |
||||
then |
||||
err_usage "ERROR: no proto-bin specified and protoc could not be discovered" |
||||
return 1 |
||||
fi |
||||
fi |
||||
|
||||
|
||||
go mod download |
||||
|
||||
local golang_proto_path=$(go list -f '{{ .Dir }}' -m github.com/golang/protobuf) |
||||
local golang_proto_mod_path=$(sed -e 's,\(.*\)github.com.*,\1,' <<< "${golang_proto_path}") |
||||
|
||||
local proto_go_path=${proto_path%%.proto}.pb.go |
||||
local proto_go_bin_path=${proto_path%%.proto}.pb.binary.go |
||||
local proto_go_rpcglue_path=${proto_path%%.proto}.rpcglue.pb.go |
||||
|
||||
local go_proto_out="paths=source_relative" |
||||
if is_set "${grpc}" |
||||
then |
||||
go_proto_out="${go_proto_out},plugins=grpc" |
||||
fi |
||||
|
||||
if test -n "${go_proto_out}" |
||||
then |
||||
go_proto_out="${go_proto_out}:" |
||||
fi |
||||
|
||||
rm -f "${proto_go_path}" ${proto_go_bin_path}" ${proto_go_rpcglue_path}" |
||||
|
||||
# How we run protoc probably needs some documentation. |
||||
# |
||||
# This is the path to where |
||||
# -I="${golang_proto_path}/protobuf" \ |
||||
local -i ret=0 |
||||
status_stage "Generating ${proto_path} into ${proto_go_path} and ${proto_go_bin_path}" |
||||
echo "debug_run ${protoc_bin} \ |
||||
-I=\"${golang_proto_path}\" \ |
||||
-I=\"${golang_proto_mod_path}\" \ |
||||
-I=\"${SOURCE_DIR}\" \ |
||||
--go_out=\"${go_proto_out}${SOURCE_DIR}\" \ |
||||
--go-binary_out=\"${SOURCE_DIR}\" \ |
||||
\"${proto_path}\"" |
||||
debug_run ${protoc_bin} \ |
||||
-I="${golang_proto_path}" \ |
||||
-I="${golang_proto_mod_path}" \ |
||||
-I="${SOURCE_DIR}" \ |
||||
--go_out="${go_proto_out}${SOURCE_DIR}" \ |
||||
--go-binary_out="${SOURCE_DIR}" \ |
||||
"${proto_path}" |
||||
|
||||
if test $? -ne 0 |
||||
then |
||||
err "Failed to run protoc for ${proto_path}" |
||||
return 1 |
||||
fi |
||||
|
||||
debug_run protoc-go-inject-tag \ |
||||
-input="${proto_go_path}" |
||||
|
||||
if test $? -ne 0 |
||||
then |
||||
err "Failed to run protoc-go-inject-tag for ${proto_path}" |
||||
return 1 |
||||
fi |
||||
|
||||
BUILD_TAGS=$(head -n 2 "${proto_path}" | grep '^//go:build\|// +build') |
||||
if test -n "${BUILD_TAGS}" |
||||
then |
||||
echo -e "${BUILD_TAGS}\n" >> "${proto_go_bin_path}.new" |
||||
cat "${proto_go_bin_path}" >> "${proto_go_bin_path}.new" |
||||
mv "${proto_go_bin_path}.new" "${proto_go_bin_path}" |
||||
fi |
||||
|
||||
# note: this has to run after we fix up the build tags above |
||||
rm -f "${proto_go_rpcglue_path}" |
||||
debug_run go run ./internal/tools/proto-gen-rpc-glue/main.go -path "${proto_go_path}" |
||||
if test $? -ne 0 |
||||
then |
||||
err "Failed to generate consul rpc glue outputs from ${proto_path}" |
||||
return 1 |
||||
fi |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
main "$@" |
||||
exit $? |
@ -0,0 +1,340 @@
|
||||
#!/usr/bin/env bash |
||||
|
||||
readonly SCRIPT_NAME="$(basename ${BASH_SOURCE[0]})" |
||||
readonly SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" |
||||
readonly SOURCE_DIR="$(dirname "$(dirname "${SCRIPT_DIR}")")" |
||||
readonly FN_DIR="$(dirname "${SCRIPT_DIR}")/functions" |
||||
|
||||
source "${SCRIPT_DIR}/functions.sh" |
||||
|
||||
unset CDPATH |
||||
|
||||
set -euo pipefail |
||||
|
||||
usage() { |
||||
cat <<-EOF |
||||
Usage: ${SCRIPT_NAME} [<options ...>] |
||||
|
||||
Description: |
||||
Installs protoc, various supporting Go tools, and then regenerates all Go |
||||
files from protobuf definitions. In addition to running the protoc |
||||
generator it will also fixup build tags in the generated code and |
||||
regenerate mog outputs and RPC stubs. |
||||
|
||||
Options: |
||||
--protoc-version Version of protoc to install. It defaults to what is specified in the makefile. |
||||
--tools-only Install all required tools but do not generate outputs. |
||||
-h | --help Print this help text. |
||||
EOF |
||||
} |
||||
|
||||
function err_usage { |
||||
err "$1" |
||||
err "" |
||||
err "$(usage)" |
||||
} |
||||
|
||||
function main { |
||||
local protoc_version= |
||||
local tools_only= |
||||
|
||||
while test $# -gt 0 |
||||
do |
||||
case "$1" in |
||||
-h | --help ) |
||||
usage |
||||
return 0 |
||||
;; |
||||
--protoc-version ) |
||||
protoc_version="$2" |
||||
shift 2 |
||||
;; |
||||
--tools-only ) |
||||
tools_only=1 |
||||
shift |
||||
;; |
||||
esac |
||||
done |
||||
|
||||
if test -z "${protoc_version}" |
||||
then |
||||
protoc_version="$(make --no-print-directory print-PROTOC_VERSION)" |
||||
if test -z "${protoc_version}" |
||||
then |
||||
err_usage "ERROR: no proto-version specified and version could not be discovered" |
||||
return 1 |
||||
fi |
||||
fi |
||||
|
||||
# ensure the correct protoc compiler is installed |
||||
protoc_install "${protoc_version}" |
||||
if test -z "${protoc_bin}" ; then |
||||
exit 1 |
||||
fi |
||||
|
||||
# ensure these tools are installed |
||||
proto_tools_install |
||||
|
||||
if [[ -n $tools_only ]]; then |
||||
return 0 |
||||
fi |
||||
|
||||
# Compute some data from dependencies in non-local variables. |
||||
go mod download |
||||
golang_proto_path="$(go list -f '{{ .Dir }}' -m github.com/golang/protobuf)" |
||||
# golang_proto_mod_path="$(sed -e 's,\(.*\)github.com.*,\1,' <<< "${golang_proto_path}")" |
||||
golang_proto_mod_path="$(go env GOMODCACHE)" |
||||
|
||||
declare -a proto_files |
||||
while IFS= read -r pkg; do |
||||
pkg="${pkg#"./"}" |
||||
proto_files+=( "$pkg" ) |
||||
done < <(find . -name '*.proto' | grep -v 'vendor/' | grep -v '.protobuf' | sort ) |
||||
|
||||
for proto_file in "${proto_files[@]}"; do |
||||
generate_protobuf_code "${proto_file}" |
||||
done |
||||
|
||||
status "Generated all protobuf Go files" |
||||
|
||||
generate_mog_code |
||||
|
||||
status "Generated all mog Go files" |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
# Installs the version of protoc specified by the first argument. |
||||
# |
||||
# Will set 'protoc_bin' |
||||
function protoc_install { |
||||
local protoc_version="${1:-}" |
||||
local protoc_os |
||||
|
||||
if test -z "${protoc_version}" |
||||
then |
||||
protoc_version="$(make --no-print-directory print-PROTOC_VERSION)" |
||||
if test -z "${protoc_version}" |
||||
then |
||||
err "ERROR: no protoc-version specified and version could not be discovered" |
||||
return 1 |
||||
fi |
||||
fi |
||||
|
||||
case "$(uname)" in |
||||
Darwin) |
||||
protoc_os="osx" |
||||
;; |
||||
Linux) |
||||
protoc_os="linux" |
||||
;; |
||||
*) |
||||
err "unexpected OS: $(uname)" |
||||
return 1 |
||||
esac |
||||
|
||||
local protoc_zip="protoc-${protoc_version}-${protoc_os}-x86_64.zip" |
||||
local protoc_url="https://github.com/protocolbuffers/protobuf/releases/download/v${protoc_version}/${protoc_zip}" |
||||
local protoc_root=".protobuf/protoc-${protoc_os}-${protoc_version}" |
||||
# This is updated for use outside of the function. |
||||
protoc_bin="${protoc_root}/bin/protoc" |
||||
|
||||
if [[ -x "${protoc_bin}" ]]; then |
||||
status "protocol buffer compiler version already installed: ${protoc_version}" |
||||
return 0 |
||||
fi |
||||
|
||||
status_stage "installing protocol buffer compiler version: ${protoc_version}" |
||||
|
||||
mkdir -p .protobuf/tmp |
||||
if [[ ! -f .protobuf/tmp/${protoc_zip} ]]; then \ |
||||
( cd .protobuf/tmp && curl -sSL "${protoc_url}" -o "${protoc_zip}" ) |
||||
fi |
||||
|
||||
mkdir -p "${protoc_root}" |
||||
unzip -d "${protoc_root}" ".protobuf/tmp/${protoc_zip}" |
||||
chmod -R a+Xr "${protoc_root}" |
||||
chmod +x "${protoc_bin}" |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
function proto_tools_install { |
||||
local protoc_gen_go_version |
||||
local mog_version |
||||
local protoc_go_inject_tag_version |
||||
|
||||
protoc_gen_go_version="$(grep github.com/golang/protobuf go.mod | awk '{print $2}')" |
||||
mog_version="$(make --no-print-directory print-MOG_VERSION)" |
||||
protoc_go_inject_tag_version="$(make --no-print-directory print-PROTOC_GO_INJECT_TAG_VERSION)" |
||||
|
||||
# echo "go: ${protoc_gen_go_version}" |
||||
# echo "mog: ${mog_version}" |
||||
# echo "tag: ${protoc_go_inject_tag_version}" |
||||
|
||||
install_versioned_tool \ |
||||
'protoc-gen-go' \ |
||||
'github.com/golang/protobuf' \ |
||||
"${protoc_gen_go_version}" \ |
||||
'github.com/golang/protobuf/protoc-gen-go' |
||||
|
||||
install_unversioned_tool \ |
||||
protoc-gen-go-binary \ |
||||
'github.com/hashicorp/protoc-gen-go-binary@master' |
||||
|
||||
install_versioned_tool \ |
||||
'protoc-go-inject-tag' \ |
||||
'github.com/favadi/protoc-go-inject-tag' \ |
||||
"${protoc_go_inject_tag_version}" \ |
||||
'github.com/favadi/protoc-go-inject-tag' |
||||
|
||||
install_versioned_tool \ |
||||
'mog' \ |
||||
'github.com/hashicorp/mog' \ |
||||
"${mog_version}" \ |
||||
'github.com/hashicorp/mog' |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
function install_unversioned_tool { |
||||
local command="$1" |
||||
local install="$2" |
||||
|
||||
if ! command -v "${command}" &>/dev/null ; then |
||||
status_stage "installing tool: ${install}" |
||||
go install "${install}" |
||||
else |
||||
debug "skipping tool: ${install} (installed)" |
||||
fi |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
function install_versioned_tool { |
||||
local command="$1" |
||||
local module="$2" |
||||
local version="$3" |
||||
local installbase="$4" |
||||
|
||||
local should_install= |
||||
local got |
||||
|
||||
local expect="${module}@${version}" |
||||
local install="${installbase}@${version}" |
||||
|
||||
if [[ -z "$version" ]]; then |
||||
err "cannot install '${command}' no version selected" |
||||
return 1 |
||||
fi |
||||
|
||||
if [[ "$version" = "@DEV" ]]; then |
||||
if ! command -v "${command}" &>/dev/null ; then |
||||
err "dev version of '${command}' requested but not installed" |
||||
return 1 |
||||
fi |
||||
status "skipping tool: ${installbase} (using development version)" |
||||
return 0 |
||||
fi |
||||
|
||||
if command -v "${command}" &>/dev/null ; then |
||||
got="$(go version -m $(which "${command}") | grep '\bmod\b' | grep "${module}" | |
||||
awk '{print $2 "@" $3}')" |
||||
if [[ "$expect" != "$got" ]]; then |
||||
should_install=1 |
||||
fi |
||||
else |
||||
should_install=1 |
||||
fi |
||||
|
||||
if [[ -n $should_install ]]; then |
||||
status_stage "installing tool: ${install}" |
||||
go install "${install}" |
||||
else |
||||
debug "skipping tool: ${install} (installed)" |
||||
fi |
||||
return 0 |
||||
} |
||||
|
||||
function generate_protobuf_code { |
||||
local proto_path="${1:-}" |
||||
if [[ -z "${proto_path}" ]]; then |
||||
err "missing protobuf path argument" |
||||
return 1 |
||||
fi |
||||
|
||||
if [[ -z "${golang_proto_path}" ]]; then |
||||
err "golang_proto_path was not set" |
||||
return 1 |
||||
fi |
||||
if [[ -z "${golang_proto_mod_path}" ]]; then |
||||
err "golang_proto_mod_path was not set" |
||||
return 1 |
||||
fi |
||||
|
||||
local proto_go_path="${proto_path%%.proto}.pb.go" |
||||
local proto_go_bin_path="${proto_path%%.proto}.pb.binary.go" |
||||
local proto_go_rpcglue_path="${proto_path%%.proto}.rpcglue.pb.go" |
||||
|
||||
local go_proto_out='paths=source_relative,plugins=grpc:' |
||||
|
||||
status_stage "Generating ${proto_path} into ${proto_go_path} and ${proto_go_bin_path}" |
||||
|
||||
rm -f "${proto_go_path}" ${proto_go_bin_path}" ${proto_go_rpcglue_path}" |
||||
|
||||
print_run ${protoc_bin} \ |
||||
-I="${golang_proto_path}" \ |
||||
-I="${golang_proto_mod_path}" \ |
||||
-I="${SOURCE_DIR}" \ |
||||
--go_out="${go_proto_out}${SOURCE_DIR}" \ |
||||
--go-binary_out="${SOURCE_DIR}" \ |
||||
"${proto_path}" || { |
||||
|
||||
err "Failed to run protoc for ${proto_path}" |
||||
return 1 |
||||
} |
||||
|
||||
print_run protoc-go-inject-tag -input="${proto_go_path}" || { |
||||
err "Failed to run protoc-go-inject-tag for ${proto_path}" |
||||
return 1 |
||||
} |
||||
|
||||
local build_tags |
||||
build_tags="$(head -n 2 "${proto_path}" | grep '^//go:build\|// +build' || true)" |
||||
if test -n "${build_tags}"; then |
||||
echo -e "${build_tags}\n" >> "${proto_go_bin_path}.new" |
||||
cat "${proto_go_bin_path}" >> "${proto_go_bin_path}.new" |
||||
mv "${proto_go_bin_path}.new" "${proto_go_bin_path}" |
||||
fi |
||||
|
||||
# NOTE: this has to run after we fix up the build tags above |
||||
rm -f "${proto_go_rpcglue_path}" |
||||
print_run go run ./internal/tools/proto-gen-rpc-glue/main.go -path "${proto_go_path}" || { |
||||
err "Failed to generate consul rpc glue outputs from ${proto_path}" |
||||
return 1 |
||||
} |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
function generate_mog_code { |
||||
local mog_order |
||||
|
||||
mog_order="$(go list -tags "${GOTAGS}" -deps ./proto/pb... | grep "consul/proto")" |
||||
|
||||
for FULL_PKG in ${mog_order}; do |
||||
PKG="${FULL_PKG/#github.com\/hashicorp\/consul\/}" |
||||
status_stage "Generating ${PKG}/*.pb.go into ${PKG}/*.gen.go with mog" |
||||
find "$PKG" -name '*.gen.go' -delete |
||||
if [[ -n "${GOTAGS}" ]]; then |
||||
print_run mog -tags "${GOTAGS}" -source "./${PKG}/*.pb.go" |
||||
else |
||||
print_run mog -source "./${PKG}/*.pb.go" |
||||
fi |
||||
done |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
main "$@" |
||||
exit $? |
Loading…
Reference in new issue