Browse Source

build: conditionally install or reinstall protobuf supporting tools as needed (#12674)

pull/12699/head
R.B. Boyer 3 years ago committed by GitHub
parent
commit
a85a4b3bbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 72
      GNUmakefile
  2. 2
      build-support/functions/00-vars.sh
  3. 6
      build-support/functions/10-util.sh
  4. 17
      build-support/scripts/build-docker.sh
  5. 8
      build-support/scripts/functions.sh
  6. 162
      build-support/scripts/proto-gen.sh
  7. 340
      build-support/scripts/protobuf.sh
  8. 19
      build-support/scripts/release.sh
  9. 19
      build-support/scripts/version.sh

72
GNUmakefile

@ -12,23 +12,23 @@ GOTOOLS = \
github.com/hashicorp/lint-consul-retry@master
PROTOC_VERSION=3.15.8
PROTOC_OS := $(shell if test "$$(uname)" == "Darwin"; then echo osx; else echo linux; fi)
PROTOC_ZIP := protoc-$(PROTOC_VERSION)-$(PROTOC_OS)-x86_64.zip
PROTOC_URL := https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/$(PROTOC_ZIP)
PROTOC_ROOT := .protobuf/protoc-$(PROTOC_OS)-$(PROTOC_VERSION)
PROTOC_BIN := $(PROTOC_ROOT)/bin/protoc
GOPROTOVERSION?=$(shell grep github.com/golang/protobuf go.mod | awk '{print $$2}')
GOPROTOTOOLS = \
github.com/golang/protobuf/protoc-gen-go@$(GOPROTOVERSION) \
github.com/hashicorp/protoc-gen-go-binary@master \
github.com/favadi/protoc-go-inject-tag@v1.3.0 \
github.com/hashicorp/mog@v0.2.0
###
# MOG_VERSION can be either a valid string for "go install <module>@<version>"
# or the string @DEV to imply use whatever is currently installed locally.
###
MOG_VERSION='v0.2.0'
###
# PROTOC_GO_INJECT_TAG_VERSION can be either a valid string for "go install <module>@<version>"
# or the string @DEV to imply use whatever is currently installed locally.
###
PROTOC_GO_INJECT_TAG_VERSION='v1.3.0'
GOTAGS ?=
GOPATH=$(shell go env GOPATH)
MAIN_GOPATH=$(shell go env GOPATH | cut -d: -f1)
export PATH := $(PWD)/bin:$(PATH)
export PATH := $(PWD)/bin:$(GOPATH)/bin:$(PATH)
ASSETFS_PATH?=agent/uiserver/bindata_assetfs.go
# Get the git commit
@ -38,11 +38,6 @@ GIT_DIRTY?=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true
GIT_IMPORT=github.com/hashicorp/consul/version
GOLDFLAGS=-X $(GIT_IMPORT).GitCommit=$(GIT_COMMIT)$(GIT_DIRTY)
PROTOFILES?=$(shell find . -name '*.proto' | grep -v 'vendor/' | grep -v '.protobuf' )
PROTOGOFILES=$(PROTOFILES:.proto=.pb.go)
PROTOGOBINFILES=$(PROTOFILES:.proto=.pb.binary.go)
PROTO_MOG_ORDER=$(shell go list -tags '$(GOTAGS)' -deps ./proto/pb... | grep "consul/proto")
ifeq ($(FORCE_REBUILD),1)
NOCACHE=--no-cache
else
@ -304,11 +299,9 @@ tools: proto-tools
done
proto-tools:
@if [[ -d .gotools ]]; then rm -rf .gotools ; fi
@for TOOL in $(GOPROTOTOOLS); do \
echo "=== TOOL: $$TOOL" ; \
go install -v $$TOOL ; \
done
@$(SHELL) $(CURDIR)/build-support/scripts/protobuf.sh \
--protoc-version "$(PROTOC_VERSION)" \
--tools-only
version:
@echo -n "Version: "
@ -359,39 +352,10 @@ else
@go test -v ./agent -run Vault
endif
.PHONY: protoc-install
protoc-install:
$(info locally installing protocol buffer compiler version if needed (expect: $(PROTOC_VERSION)))
@if [[ ! -x $(PROTOC_ROOT)/bin/protoc ]]; then \
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_ROOT)/bin/protoc ; \
fi
.PHONY: proto
proto: -protoc-files -mog-files
.PHONY: -mog-files
-mog-files:
@for FULL_PKG in $(PROTO_MOG_ORDER); do \
PKG="$${FULL_PKG/#github.com\/hashicorp\/consul\//.\/}" ; \
find "$$PKG" -name '*.gen.go' -delete ; \
echo "mog -tags '$(GOTAGS)' -source \"$${PKG}/*.pb.go\"" ; \
mog -tags '$(GOTAGS)' -source "$${PKG}/*.pb.go" ; \
done
@echo "Generated all mog Go files"
.PHONY: -protoc-files
-protoc-files: protoc-install $(PROTOGOFILES) $(PROTOGOBINFILES)
@echo "Generated all protobuf Go files"
%.pb.go %.pb.binary.go: %.proto
@$(SHELL) $(CURDIR)/build-support/scripts/proto-gen.sh --grpc --protoc-bin "$(PROTOC_BIN)" "$<"
proto:
@$(SHELL) $(CURDIR)/build-support/scripts/protobuf.sh \
--protoc-version "$(PROTOC_VERSION)"
# utility to echo a makefile variable (i.e. 'make print-PROTOC_VERSION')
print-% : ; @echo $($*)

2
build-support/functions/00-vars.sh

@ -8,7 +8,7 @@ GO_BUILD_CONTAINER_DEFAULT="consul-build-go"
# Whether to colorize shell output
COLORIZE=${COLORIZE-1}
# determine GOPATH and the first GOPATH to use for intalling binaries
# determine GOPATH and the first GOPATH to use for installing binaries
if command -v go >/dev/null; then
GOPATH=${GOPATH:-$(go env GOPATH)}
case $(uname) in

6
build-support/functions/10-util.sh

@ -64,6 +64,12 @@ function debug_run {
return $?
}
function print_run {
echo "$@"
"$@"
return $?
}
function sed_i {
if test "$(uname)" == "Darwin"
then

17
build-support/scripts/build-docker.sh

@ -1,14 +1,9 @@
#!/bin/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
#!/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"

8
build-support/scripts/functions.sh

@ -3,15 +3,11 @@
#
# It provides all the scripting around building Consul and the release process
pushd $(dirname ${BASH_SOURCE[0]}) > /dev/null
pushd ../functions > /dev/null
FUNC_DIR=$(pwd)
popd > /dev/null
popd > /dev/null
readonly FUNC_DIR="$(dirname "$(dirname "${BASH_SOURCE[0]}")")/functions"
func_sources=$(find ${FUNC_DIR} -mindepth 1 -maxdepth 1 -name "*.sh" -type f | sort -n)
for src in $func_sources
do
source $src
done
done

162
build-support/scripts/proto-gen.sh

@ -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 $?

340
build-support/scripts/protobuf.sh

@ -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 $?

19
build-support/scripts/release.sh

@ -1,14 +1,9 @@
#!/bin/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
#!/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"
@ -153,4 +148,4 @@ function main {
main "$@"
exit $?

19
build-support/scripts/version.sh

@ -1,14 +1,9 @@
#!/bin/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
#!/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"
@ -89,4 +84,4 @@ function main {
main "$@"
exit $?

Loading…
Cancel
Save