#!/bin/bash
|
|
|
|
# symbol prefixes:
|
|
# g_ -> global
|
|
# l_ - local variable
|
|
# f_ -> function
|
|
|
|
set -euo pipefail
|
|
|
|
GITIAN_CACHE_DIRNAME='.gitian-builder-cache'
|
|
GO_DEBIAN_RELEASE='1.12.5-1'
|
|
GO_TARBALL="golang-debian-${GO_DEBIAN_RELEASE}.tar.gz"
|
|
GO_TARBALL_URL="https://salsa.debian.org/go-team/compiler/golang/-/archive/debian/${GO_DEBIAN_RELEASE}/${GO_TARBALL}"
|
|
|
|
# Defaults
|
|
|
|
DEFAULT_SIGN_COMMAND='gpg --detach-sign'
|
|
DEFAULT_TENDERMINT_SIGS=${TENDERMINT_SIGS:-'tendermint.sigs'}
|
|
DEFAULT_GITIAN_REPO='https://github.com/devrandom/gitian-builder'
|
|
DEFAULT_GBUILD_FLAGS=''
|
|
DEFAULT_SIGS_REPO='https://github.com/tendermint/tendermint.sigs'
|
|
|
|
# Overrides
|
|
|
|
SIGN_COMMAND=${SIGN_COMMAND:-${DEFAULT_SIGN_COMMAND}}
|
|
GITIAN_REPO=${GITIAN_REPO:-${DEFAULT_GITIAN_REPO}}
|
|
GBUILD_FLAGS=${GBUILD_FLAGS:-${DEFAULT_GBUILD_FLAGS}}
|
|
|
|
# Globals
|
|
|
|
g_workdir=''
|
|
g_gitian_cache=''
|
|
g_cached_gitian=''
|
|
g_cached_go_tarball=''
|
|
g_sign_identity=''
|
|
g_sigs_dir=''
|
|
g_flag_commit=''
|
|
|
|
|
|
f_help() {
|
|
cat >&2 <<EOF
|
|
Usage: $(basename $0) [-h] PLATFORM
|
|
Launch a gitian build from the current source directory for the given PLATFORM.
|
|
The following platforms are supported:
|
|
darwin
|
|
linux
|
|
windows
|
|
all
|
|
|
|
Options:
|
|
-h display this help and exit
|
|
-c clone the signatures repository and commit signatures;
|
|
ignored if sign identity is not supplied
|
|
-s IDENTITY sign build as IDENTITY
|
|
|
|
If a GPG identity is supplied via the -s flag, the build will be signed and verified.
|
|
The signature will be saved in '${DEFAULT_TENDERMINT_SIGS}/'. An alternative output directory
|
|
for signatures can be supplied via the environment variable \$TENDERMINT_SIGS.
|
|
|
|
The default signing command used to sign the build is '$DEFAULT_SIGN_COMMAND'.
|
|
An alternative signing command can be supplied via the environment
|
|
variable \$SIGN_COMMAND.
|
|
EOF
|
|
}
|
|
|
|
|
|
f_builddir() {
|
|
printf '%s' "${g_workdir}/gitian-build-$1"
|
|
}
|
|
|
|
f_prep_build() {
|
|
local l_platforms \
|
|
l_os \
|
|
l_builddir
|
|
|
|
l_platforms="$1"
|
|
|
|
if [ -n "${g_flag_commit}" -a ! -d "${g_sigs_dir}" ]; then
|
|
git clone ${DEFAULT_SIGS_REPO} "${g_sigs_dir}"
|
|
fi
|
|
|
|
for l_os in ${l_platforms}; do
|
|
l_builddir="$(f_builddir ${l_os})"
|
|
|
|
f_echo_stderr "Preparing build directory $(basename ${l_builddir}), restoring files from cache"
|
|
cp -ar "${g_cached_gitian}" "${l_builddir}" >&2
|
|
mkdir "${l_builddir}/inputs/"
|
|
cp -v "${g_cached_go_tarball}" "${l_builddir}/inputs/"
|
|
done
|
|
}
|
|
|
|
f_build() {
|
|
local l_descriptor
|
|
|
|
l_descriptor=$1
|
|
|
|
bin/gbuild --commit tendermint="$g_commit" ${GBUILD_FLAGS} "$l_descriptor"
|
|
libexec/stop-target || f_echo_stderr "warning: couldn't stop target"
|
|
}
|
|
|
|
f_sign_verify() {
|
|
local l_descriptor
|
|
|
|
l_descriptor=$1
|
|
|
|
bin/gsign -p "${SIGN_COMMAND}" -s "${g_sign_identity}" --destination="${g_sigs_dir}" --release=${g_release} ${l_descriptor}
|
|
bin/gverify --destination="${g_sigs_dir}" --release="${g_release}" ${l_descriptor}
|
|
}
|
|
|
|
f_commit_sig() {
|
|
local l_release_name
|
|
|
|
l_release_name=$1
|
|
|
|
pushd "${g_sigs_dir}"
|
|
git add . || echo "git add failed" >&2
|
|
git commit -m "Add ${l_release_name} reproducible build" || echo "git commit failed" >&2
|
|
popd
|
|
}
|
|
|
|
f_prep_docker_image() {
|
|
pushd $1
|
|
bin/make-base-vm --docker --suite bionic --arch amd64
|
|
popd
|
|
}
|
|
|
|
f_ensure_cache() {
|
|
g_gitian_cache="${g_workdir}/${GITIAN_CACHE_DIRNAME}"
|
|
[ -d "${g_gitian_cache}" ] || mkdir "${g_gitian_cache}"
|
|
|
|
g_cached_go_tarball="${g_gitian_cache}/${GO_TARBALL}"
|
|
if [ ! -f "${g_cached_go_tarball}" ]; then
|
|
f_echo_stderr "${g_cached_go_tarball}: cache miss, caching..."
|
|
curl -L "${GO_TARBALL_URL}" --output "${g_cached_go_tarball}"
|
|
fi
|
|
|
|
g_cached_gitian="${g_gitian_cache}/gitian-builder"
|
|
if [ ! -d "${g_cached_gitian}" ]; then
|
|
f_echo_stderr "${g_cached_gitian}: cache miss, caching..."
|
|
git clone ${GITIAN_REPO} "${g_cached_gitian}"
|
|
fi
|
|
}
|
|
|
|
f_demangle_platforms() {
|
|
case "${1}" in
|
|
all)
|
|
printf '%s' 'darwin linux windows' ;;
|
|
linux|darwin|windows)
|
|
printf '%s' "${1}" ;;
|
|
*)
|
|
echo "invalid platform -- ${1}"
|
|
exit 1
|
|
esac
|
|
}
|
|
|
|
f_echo_stderr() {
|
|
echo $@ >&2
|
|
}
|
|
|
|
|
|
while getopts ":cs:h" opt; do
|
|
case "${opt}" in
|
|
h) f_help ; exit 0 ;;
|
|
c) g_flag_commit=y ;;
|
|
s) g_sign_identity="${OPTARG}" ;;
|
|
esac
|
|
done
|
|
|
|
shift "$((OPTIND-1))"
|
|
|
|
g_platforms=$(f_demangle_platforms "${1}")
|
|
g_workdir="$(pwd)"
|
|
g_commit="$(git rev-parse HEAD)"
|
|
g_sigs_dir=${TENDERMINT_SIGS:-"${g_workdir}/${DEFAULT_TENDERMINT_SIGS}"}
|
|
|
|
f_ensure_cache
|
|
|
|
f_prep_docker_image "${g_cached_gitian}"
|
|
|
|
f_prep_build "${g_platforms}"
|
|
|
|
export USE_DOCKER=1
|
|
for g_os in ${g_platforms}; do
|
|
g_release="$(git describe --tags --abbrev=9 | sed 's/^v//')-${g_os}"
|
|
g_descriptor="${g_workdir}/scripts/gitian-descriptors/gitian-${g_os}.yml"
|
|
[ -f ${g_descriptor} ]
|
|
g_builddir="$(f_builddir ${g_os})"
|
|
|
|
pushd "${g_builddir}"
|
|
f_build "${g_descriptor}"
|
|
if [ -n "${g_sign_identity}" ]; then
|
|
f_sign_verify "${g_descriptor}"
|
|
fi
|
|
popd
|
|
|
|
if [ -n "${g_sign_identity}" -a -n "${g_flag_commit}" ]; then
|
|
[ -d "${g_sigs_dir}/.git/" ] && f_commit_sig ${g_release} || f_echo_stderr "couldn't commit, ${g_sigs_dir} is not a git clone"
|
|
fi
|
|
done
|
|
|
|
exit 0
|