541 lines
16 KiB
Bash
Executable File
541 lines
16 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# Type `build -h` for help and see https://github.com/romkatv/gitstatus
|
|
# for full documentation.
|
|
|
|
set -ue
|
|
|
|
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
emulate sh -o err_exit -o no_unset
|
|
fi
|
|
|
|
export LC_ALL=C
|
|
|
|
if [ -z "${ZSH_VERSION-}" ] && command -v zsh >/dev/null 2>&1; then
|
|
case "${BASH_VERSION-}" in
|
|
[0-3].*) exec zsh "$0" "$@";;
|
|
esac
|
|
fi
|
|
|
|
usage="$(command cat <<\END
|
|
Usage: build [-m ARCH] [-c CPU] [-d CMD] [-i IMAGE] [-s] [-w]
|
|
|
|
Options:
|
|
|
|
-m ARCH `uname -m` from the target machine; defaults to `uname -m`
|
|
from the local machine
|
|
-c CPU generate machine instructions for CPU of this type; this
|
|
value gets passed as `-march` (or `-mcpu` for ppc64le) to gcc;
|
|
inferred from ARCH if not set explicitly
|
|
-d CMD build in a Docker container and use CMD as the `docker`
|
|
command; e.g., `-d docker` or `-d podman`
|
|
-i IMAGE build in this Docker image; inferred from ARCH if not set
|
|
explicitly
|
|
-s install whatever software is necessary for build to
|
|
succeed; on some operating systems this option is not
|
|
supported; on others it can have partial effect
|
|
-w automatically download tarballs for dependencies if they
|
|
do not already exist in ./deps; dependencies are described
|
|
in ./build.info
|
|
END
|
|
)"
|
|
|
|
build="$(command cat <<\END
|
|
outdir="$(command pwd)"
|
|
|
|
if command -v mktemp >/dev/null 2>&1; then
|
|
workdir="$(command mktemp -d "${TMPDIR:-/tmp}"/gitstatus-build.XXXXXXXXXX)"
|
|
else
|
|
workdir="${TMPDIR:-/tmp}/gitstatus-build.tmp.$$"
|
|
command mkdir -- "$workdir"
|
|
fi
|
|
|
|
cd -- "$workdir"
|
|
workdir="$(command pwd)"
|
|
|
|
narg() { echo $#; }
|
|
|
|
if [ "$(narg $workdir)" != 1 -o -z "${workdir##*:*}" ]; then
|
|
>&2 echo "[error] cannot build in this directory: $workdir"
|
|
exit 1
|
|
fi
|
|
|
|
appname=gitstatusd
|
|
libgit2_tmp="$outdir"/deps/"$appname".libgit2.tmp
|
|
|
|
cleanup() {
|
|
trap - INT QUIT TERM ILL PIPE
|
|
cd /
|
|
if ! command rm -rf -- "$workdir" "$outdir"/usrbin/"$appname".tmp "$libgit2_tmp"; then
|
|
command sleep 5
|
|
command rm -rf -- "$workdir" "$outdir"/usrbin/"$appname".tmp "$libgit2_tmp"
|
|
fi
|
|
}
|
|
trap cleanup INT QUIT TERM ILL PIPE
|
|
|
|
if [ -n "$gitstatus_install_tools" ]; then
|
|
case "$gitstatus_kernel" in
|
|
linux)
|
|
if command -v apk >/dev/null 2>&1; then
|
|
command apk update
|
|
command apk add binutils cmake gcc g++ git make musl-dev perl-utils
|
|
elif command -v apt-get >/dev/null 2>&1; then
|
|
apt-get update
|
|
apt-get install -y binutils cmake gcc g++ make wget
|
|
else
|
|
>&2 echo "[error] -s is not supported on this system"
|
|
exit 1
|
|
fi
|
|
;;
|
|
freebsd)
|
|
command pkg install -y cmake gmake binutils gcc git perl5
|
|
;;
|
|
netbsd)
|
|
command pkgin -y install cmake gmake binutils git
|
|
;;
|
|
darwin)
|
|
if ! command -v make >/dev/null 2>&1 || ! command -v gcc >/dev/null 2>&1; then
|
|
>&2 echo "[error] please run 'xcode-select --install' and retry"
|
|
exit 1
|
|
fi
|
|
if command -v port >/dev/null 2>&1; then
|
|
sudo port -N install libiconv cmake wget
|
|
elif command -v brew >/dev/null 2>&1; then
|
|
for formula in libiconv cmake git wget; do
|
|
if command brew list "$formula" &>/dev/null; then
|
|
command brew upgrade "$formula"
|
|
else
|
|
command brew install "$formula"
|
|
fi
|
|
done
|
|
else
|
|
>&2 echo "[error] please install MacPorts or Homebrew and retry"
|
|
exit 1
|
|
fi
|
|
;;
|
|
msys*|mingw*)
|
|
command pacman -Syu --noconfirm
|
|
command pacman -S --needed --noconfirm binutils cmake gcc git make perl
|
|
;;
|
|
*)
|
|
>&2 echo "[internal error] unhandled kernel: $gitstatus_kernel"
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
cpus="$(command getconf _NPROCESSORS_ONLN 2>/dev/null)" ||
|
|
cpus="$(command sysctl -n hw.ncpu 2>/dev/null)" ||
|
|
cpus=8
|
|
|
|
case "$gitstatus_cpu" in
|
|
powerpc64le) archflag="-mcpu";;
|
|
*) archflag="-march";;
|
|
esac
|
|
|
|
cflags="$archflag=$gitstatus_cpu -fno-plt"
|
|
|
|
if [ "$gitstatus_cpu" = x86-64 ]; then
|
|
cflags="$cflags -mtune=generic"
|
|
fi
|
|
|
|
libgit2_cmake_flags=
|
|
libgit2_cflags="$cflags"
|
|
|
|
gitstatus_cxx=g++
|
|
gitstatus_cxxflags="$cflags -I${workdir}/libgit2/include -DGITSTATUS_ZERO_NSEC -D_GNU_SOURCE"
|
|
gitstatus_ldflags="-L${workdir}/libgit2/build"
|
|
gitstatus_ldlibs=
|
|
gitstatus_make=make
|
|
|
|
case "$gitstatus_kernel" in
|
|
linux)
|
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
|
gitstatus_ldflags="$gitstatus_ldflags -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
|
|
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
|
|
;;
|
|
freebsd)
|
|
gitstatus_make=gmake
|
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
|
gitstatus_ldflags="$gitstatus_ldflags -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
|
|
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
|
|
;;
|
|
netbsd)
|
|
gitstatus_make=gmake
|
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
|
gitstatus_ldflags="$gitstatus_ldflags -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
|
|
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
|
|
;;
|
|
darwin)
|
|
command mkdir -- "$workdir"/lib
|
|
if [ -e /opt/local/lib/libiconv.a ]; then
|
|
command ln -s -- /opt/local/lib/libiconv.a "$workdir"/lib
|
|
libgit2_cflags="$libgit2_cflags -I/opt/local/include"
|
|
gitstatus_cxxflags="$gitstatus_cxxflags -I/opt/local/include"
|
|
else
|
|
brew_prefix="$(command brew --prefix)"
|
|
command ln -s -- "$brew_prefix"/opt/libiconv/lib/libiconv.a "$workdir"/lib
|
|
libgit2_cflags="$libgit2_cflags -I"$brew_prefix"/opt/libiconv/include"
|
|
gitstatus_cxxflags="$gitstatus_cxxflags -I"$brew_prefix"/opt/libiconv/include"
|
|
fi
|
|
libgit2_cmake_flags="$libgit2_cmake_flags -DUSE_ICONV=ON"
|
|
gitstatus_ldlibs="$gitstatus_ldlibs -liconv"
|
|
gitstatus_ldflags="$gitstatus_ldflags -L${workdir}/lib"
|
|
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=OFF"
|
|
;;
|
|
msys*|mingw*)
|
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
|
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
|
|
;;
|
|
cygwin*)
|
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
|
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
|
|
;;
|
|
*)
|
|
>&2 echo "[internal error] unhandled kernel: $gitstatus_kernel"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
for cmd in cat cmake gcc g++ git ld ln mkdir rm strip tar "$gitstatus_make"; do
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
if [ -n "$gitstatus_install_tools" ]; then
|
|
>&2 echo "[internal error] $cmd not found"
|
|
exit 1
|
|
else
|
|
>&2 echo "[error] command not found: $cmd"
|
|
exit 1
|
|
fi
|
|
fi
|
|
done
|
|
|
|
. "$outdir"/build.info
|
|
if [ -z "${libgit2_version:-}" ]; then
|
|
>&2 echo "[internal error] libgit2_version not set"
|
|
exit 1
|
|
fi
|
|
if [ -z "${libgit2_sha256:-}" ]; then
|
|
>&2 echo "[internal error] libgit2_sha256 not set"
|
|
exit 1
|
|
fi
|
|
libgit2_tarball="$outdir"/deps/libgit2-"$libgit2_version".tar.gz
|
|
if [ ! -e "$libgit2_tarball" ]; then
|
|
if [ -n "$gitstatus_download_deps" ]; then
|
|
if ! command -v wget >/dev/null 2>&1; then
|
|
if [ -n "$gitstatus_install_tools" ]; then
|
|
>&2 echo "[internal error] wget not found"
|
|
exit 1
|
|
else
|
|
>&2 echo "[error] command not found: wget"
|
|
exit 1
|
|
fi
|
|
fi
|
|
libgit2_url=https://github.com/romkatv/libgit2/archive/"$libgit2_version".tar.gz
|
|
command wget -O "$libgit2_tmp" -- "$libgit2_url"
|
|
command mv -f -- "$libgit2_tmp" "$libgit2_tarball"
|
|
else
|
|
>&2 echo "[error] file not found: deps/libgit2-"$libgit2_version".tar.gz"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
libgit2_actual_sha256=
|
|
if command -v shasum >/dev/null 2>/dev/null; then
|
|
libgit2_actual_sha256="$(command shasum -b -a 256 -- "$libgit2_tarball")"
|
|
libgit2_actual_sha256="${libgit2_actual_sha256%% *}"
|
|
elif command -v sha256sum >/dev/null 2>/dev/null; then
|
|
libgit2_actual_sha256="$(command sha256sum -b -- "$libgit2_tarball")"
|
|
libgit2_actual_sha256="${libgit2_actual_sha256%% *}"
|
|
elif command -v sha256 >/dev/null 2>/dev/null; then
|
|
libgit2_actual_sha256="$(command sha256 -- "$libgit2_tarball" </dev/null)"
|
|
# Ignore sha256 output if it's from hashalot. It's incompatible.
|
|
if [ ${#libgit2_actual_sha256} -lt 64 ]; then
|
|
libgit2_actual_sha256=
|
|
else
|
|
libgit2_actual_sha256="${libgit2_actual_sha256##* }"
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$libgit2_actual_sha256" ]; then
|
|
>&2 echo "[error] command not found: shasum or sha256sum"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$libgit2_actual_sha256" != "$libgit2_sha256" ]; then
|
|
>&2 echo "[error] sha256 mismatch"
|
|
>&2 echo ""
|
|
>&2 echo " file : deps/libgit2-$libgit2_version.tar.gz"
|
|
>&2 echo " expected: $libgit2_sha256"
|
|
>&2 echo " actual : $libgit2_actual_sha256"
|
|
exit 1
|
|
fi
|
|
|
|
cd -- "$workdir"
|
|
command tar -xzf "$libgit2_tarball"
|
|
command mv -- libgit2-"$libgit2_version" libgit2
|
|
command mkdir libgit2/build
|
|
cd libgit2/build
|
|
|
|
CFLAGS="$libgit2_cflags" command cmake \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DZERO_NSEC=ON \
|
|
-DTHREADSAFE=ON \
|
|
-DUSE_BUNDLED_ZLIB=ON \
|
|
-DREGEX_BACKEND=builtin \
|
|
-DUSE_HTTP_PARSER=builtin \
|
|
-DUSE_SSH=OFF \
|
|
-DUSE_HTTPS=OFF \
|
|
-DBUILD_CLAR=OFF \
|
|
-DUSE_GSSAPI=OFF \
|
|
-DUSE_NTLMCLIENT=OFF \
|
|
-DBUILD_SHARED_LIBS=OFF \
|
|
$libgit2_cmake_flags \
|
|
..
|
|
command make -j "$cpus" VERBOSE=1
|
|
|
|
APPNAME="$appname".tmp \
|
|
OBJDIR="$workdir"/gitstatus \
|
|
CXX="$gitstatus_cxx" \
|
|
CXXFLAGS="$gitstatus_cxxflags" \
|
|
LDFLAGS="$gitstatus_ldflags" \
|
|
LDLIBS="$gitstatus_ldlibs" \
|
|
command "$gitstatus_make" -C "$outdir" -j "$cpus"
|
|
|
|
app="$outdir"/usrbin/"$appname"
|
|
|
|
command strip "$app".tmp
|
|
|
|
command mkdir -- "$workdir"/repo
|
|
command git -C "$workdir"/repo init
|
|
command git -C "$workdir"/repo config user.name "Your Name"
|
|
command git -C "$workdir"/repo config user.email "you@example.com"
|
|
command git -C "$workdir"/repo commit --allow-empty --allow-empty-message --no-gpg-sign -m ''
|
|
|
|
resp="$(printf "hello\037$workdir/repo\036" | "$app".tmp)"
|
|
[ -n "$resp" -a -z "${resp##hello*1*$workdir/repo*master*}" ]
|
|
|
|
resp="$(printf 'hello\037\036' | "$app".tmp)"
|
|
[ -n "$resp" -a -z "${resp##hello*0*}" ]
|
|
|
|
command mv -f -- "$app".tmp "$app"
|
|
|
|
cleanup
|
|
|
|
command cat >&2 <<-END
|
|
-------------------------------------------------
|
|
SUCCESS: created usrbin/$appname
|
|
END
|
|
END
|
|
)"
|
|
|
|
docker_image=
|
|
docker_cmd=
|
|
|
|
gitstatus_arch=
|
|
gitstatus_cpu=
|
|
gitstatus_install_tools=
|
|
gitstatus_download_deps=
|
|
|
|
while getopts ':m:c:i:d:swh' opt "$@"; do
|
|
case "$opt" in
|
|
h)
|
|
printf '%s\n' "$usage"
|
|
exit
|
|
;;
|
|
m)
|
|
if [ -n "$gitstatus_arch" ]; then
|
|
>&2 echo "[error] duplicate option: -$opt"
|
|
exit 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
exit 1
|
|
fi
|
|
gitstatus_arch="$OPTARG"
|
|
;;
|
|
c)
|
|
if [ -n "$gitstatus_cpu" ]; then
|
|
>&2 echo "[error] duplicate option: -$opt"
|
|
exit 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
exit 1
|
|
fi
|
|
gitstatus_cpu="$OPTARG"
|
|
;;
|
|
i)
|
|
if [ -n "$docker_image" ]; then
|
|
>&2 echo "[error] duplicate option: -$opt"
|
|
exit 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
exit 1
|
|
fi
|
|
docker_image="$OPTARG"
|
|
;;
|
|
d)
|
|
if [ -n "$docker_cmd" ]; then
|
|
>&2 echo "[error] duplicate option: -$opt"
|
|
exit 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
exit 1
|
|
fi
|
|
docker_cmd="$OPTARG"
|
|
;;
|
|
s)
|
|
if [ -n "$gitstatus_install_tools" ]; then
|
|
>&2 echo "[error] duplicate option: -$opt"
|
|
exit 1
|
|
fi
|
|
gitstatus_install_tools=1
|
|
;;
|
|
w)
|
|
if [ -n "$gitstatus_download_deps" ]; then
|
|
>&2 echo "[error] duplicate option: -$opt"
|
|
exit 1
|
|
fi
|
|
gitstatus_download_deps=1
|
|
;;
|
|
\?) >&2 echo "[error] invalid option: -$OPTARG" ; exit 1;;
|
|
:) >&2 echo "[error] missing required argument: -$OPTARG"; exit 1;;
|
|
*) >&2 echo "[internal error] unhandled option: -$opt" ; exit 1;;
|
|
esac
|
|
done
|
|
|
|
if [ "$OPTIND" -le $# ]; then
|
|
>&2 echo "[error] unexpected positional argument"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$docker_image" -a -z "$docker_cmd" ]; then
|
|
>&2 echo "[error] cannot use -i without -d"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$gitstatus_arch" ]; then
|
|
gitstatus_arch="$(uname -m)"
|
|
gitstatus_arch="$(printf '%s' "$gitstatus_arch" | tr '[A-Z]' '[a-z]')"
|
|
fi
|
|
|
|
if [ -z "$gitstatus_cpu" ]; then
|
|
case "$gitstatus_arch" in
|
|
armv6l) gitstatus_cpu=armv6;;
|
|
armv7l) gitstatus_cpu=armv7;;
|
|
arm64) gitstatus_cpu=armv8;;
|
|
aarch64) gitstatus_cpu=armv8-a;;
|
|
ppc64le) gitstatus_cpu=powerpc64le;;
|
|
riscv64) gitstatus_cpu=rv64imafdc;;
|
|
x86_64|amd64) gitstatus_cpu=x86-64;;
|
|
i386|i586|i686) gitstatus_cpu="$gitstatus_arch";;
|
|
*)
|
|
>&2 echo '[error] unable to infer target CPU architecture'
|
|
>&2 echo 'Please specify explicitly with `-c CPU`.'
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
gitstatus_kernel="$(uname -s)"
|
|
gitstatus_kernel="$(printf '%s' "$gitstatus_kernel" | tr '[A-Z]' '[a-z]')"
|
|
|
|
case "$gitstatus_kernel" in
|
|
linux)
|
|
if [ -n "$docker_cmd" ]; then
|
|
if [ -z "${docker_cmd##*/*}" ]; then
|
|
if [ ! -x "$docker_cmd" ]; then
|
|
>&2 echo "[error] not an executable file: $docker_cmd"
|
|
exit 1
|
|
fi
|
|
else
|
|
if ! command -v "$docker_cmd" >/dev/null 2>&1; then
|
|
>&2 echo "[error] command not found: $docker_cmd"
|
|
exit 1
|
|
fi
|
|
fi
|
|
if [ -z "$docker_image" ]; then
|
|
case "$gitstatus_arch" in
|
|
x86_64) docker_image=alpine:3.11.6;;
|
|
i386|i586|i686) docker_image=i386/alpine:3.11.6;;
|
|
armv6l) docker_image=arm32v6/alpine:3.11.6;;
|
|
armv7l) docker_image=arm32v7/alpine:3.11.6;;
|
|
aarch64) docker_image=arm64v8/alpine:3.11.6;;
|
|
ppc64le) docker_image=ppc64le/alpine:3.11.6;;
|
|
*)
|
|
>&2 echo '[error] unable to infer docker image'
|
|
>&2 echo 'Please specify explicitly with `-i IMAGE`.'
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
;;
|
|
freebsd|netbsd|darwin)
|
|
if [ -n "$docker_cmd" ]; then
|
|
>&2 echo "[error] docker (-d) is not supported on $gitstatus_kernel"
|
|
exit 1
|
|
fi
|
|
;;
|
|
msys_nt-*|mingw32_nt-*|mingw64_nt-*|cygwin_nt-*)
|
|
if ! printf '%s' "$gitstatus_kernel" | grep -Eqx '[^-]+-[0-9]+\.[0-9]+(-.*)?'; then
|
|
>&2 echo '[error] unsupported kernel, sorry!'
|
|
exit 1
|
|
fi
|
|
gitstatus_kernel="$(printf '%s' "$gitstatus_kernel" | sed 's/^\([^-]*-[0-9]*\.[0-9]*\).*/\1/')"
|
|
if [ -n "$docker_cmd" ]; then
|
|
>&2 echo '[error] docker (-d) is not supported on windows'
|
|
exit 1
|
|
fi
|
|
if [ -n "$gitstatus_install_tools" -a -z "${gitstatus_kernel##cygwin_nt-*}" ]; then
|
|
>&2 echo '[error] -s is not supported on cygwin'
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
>&2 echo '[error] unsupported kernel, sorry!'
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
dir="$(dirname -- "$0")"
|
|
cd -- "$dir"
|
|
dir="$(pwd)"
|
|
|
|
>&2 echo "Building gitstatusd..."
|
|
>&2 echo ""
|
|
>&2 echo " kernel := $gitstatus_kernel"
|
|
>&2 echo " arch := $gitstatus_arch"
|
|
>&2 echo " cpu := $gitstatus_cpu"
|
|
[ -z "$docker_cmd" ] || >&2 echo " docker command := $docker_cmd"
|
|
[ -z "$docker_image" ] || >&2 echo " docker image := $docker_image"
|
|
if [ -n "$gitstatus_install_tools" ]; then
|
|
>&2 echo " install tools := yes"
|
|
else
|
|
>&2 echo " install tools := no"
|
|
fi
|
|
if [ -n "$gitstatus_download_deps" ]; then
|
|
>&2 echo " download deps := yes"
|
|
else
|
|
>&2 echo " download deps := no"
|
|
fi
|
|
|
|
if [ -n "$docker_cmd" ]; then
|
|
"$docker_cmd" run \
|
|
-e docker_cmd="$docker_cmd" \
|
|
-e docker_image="$docker_image" \
|
|
-e gitstatus_kernel="$gitstatus_kernel" \
|
|
-e gitstatus_arch="$gitstatus_arch" \
|
|
-e gitstatus_cpu="$gitstatus_cpu" \
|
|
-e gitstatus_install_tools="$gitstatus_install_tools" \
|
|
-e gitstatus_download_deps="$gitstatus_download_deps" \
|
|
-v "$dir":/out \
|
|
-w /out \
|
|
--rm \
|
|
-- "$docker_image" /bin/sh -uexc "$build"
|
|
else
|
|
eval "$build"
|
|
fi
|