443 lines
12 KiB
Plaintext
443 lines
12 KiB
Plaintext
|
#!/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
|
||
|
|
||
|
usage="$(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` 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
|
||
|
don't already exist in ./deps; dependencies are described
|
||
|
in ./build.info
|
||
|
END
|
||
|
)"
|
||
|
|
||
|
build="$(cat <<\END
|
||
|
outdir="$(pwd)"
|
||
|
|
||
|
if command -v mktemp >/dev/null 2>&1; then
|
||
|
workdir="$(mktemp -d "${TMPDIR:-/tmp}"/gitstatus-build.XXXXXXXXXX)"
|
||
|
else
|
||
|
workdir="${TMPDIR:-/tmp}/gitstatus-build.tmp.$$"
|
||
|
mkdir -- "$workdir"
|
||
|
fi
|
||
|
|
||
|
cd -- "$workdir"
|
||
|
workdir="$(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-"$gitstatus_kernel"-"$gitstatus_arch"
|
||
|
libgit2_tmp="$outdir"/deps/"$appname".libgit2.tmp
|
||
|
|
||
|
cleanup() {
|
||
|
cd /
|
||
|
rm -rf -- "$workdir" "$outdir"/usrbin/"$appname".tmp "$libgit2_tmp"
|
||
|
trap - INT QUIT TERM EXIT ILL PIPE
|
||
|
}
|
||
|
trap cleanup INT QUIT TERM EXIT ILL PIPE
|
||
|
|
||
|
if [ -n "$gitstatus_install_tools" ]; then
|
||
|
case "$gitstatus_kernel" in
|
||
|
linux)
|
||
|
apk update
|
||
|
apk add binutils cmake gcc g++ git make musl-dev
|
||
|
;;
|
||
|
freebsd)
|
||
|
pkg install -y cmake gmake binutils gcc git
|
||
|
;;
|
||
|
netbsd)
|
||
|
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 brew >/dev/null 2>&1; then
|
||
|
>&2 echo "[error] please install homebrew from https://brew.sh/ and retry"
|
||
|
exit 1
|
||
|
fi
|
||
|
for formula in libiconv cmake git wget; do
|
||
|
if brew list "$formula" &>/dev/null; then
|
||
|
brew upgrade "$formula"
|
||
|
else
|
||
|
brew install "$formula"
|
||
|
fi
|
||
|
done
|
||
|
;;
|
||
|
msys*|mingw*)
|
||
|
pacman -Syu --noconfirm
|
||
|
pacman -S --needed --noconfirm binutils cmake gcc git make
|
||
|
;;
|
||
|
*)
|
||
|
>&2 echo "[internal error] unhandled kernel: $gitstatus_kernel"
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
fi
|
||
|
|
||
|
cpus="$(getconf _NPROCESSORS_ONLN)" || cpus="$(sysctl -n hw.ncpu)" || cpus=8
|
||
|
|
||
|
libgit2_cmake_flags=
|
||
|
libgit2_cflags="-march=$gitstatus_cpu"
|
||
|
|
||
|
gitstatus_cxx=g++
|
||
|
gitstatus_cxxflags="-I${workdir}/libgit2/include -DGITSTATUS_ZERO_NSEC -D_GNU_SOURCE -march=$gitstatus_cpu"
|
||
|
gitstatus_ldflags="-L${workdir}/libgit2/build"
|
||
|
gitstatus_ldlibs=
|
||
|
gitstatus_make=make
|
||
|
|
||
|
case "$gitstatus_kernel" in
|
||
|
linux)
|
||
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
||
|
;;
|
||
|
freebsd)
|
||
|
gitstatus_make=gmake
|
||
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
||
|
;;
|
||
|
netbsd)
|
||
|
gitstatus_make=gmake
|
||
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
||
|
;;
|
||
|
darwin)
|
||
|
mkdir -- "$workdir"/lib
|
||
|
ln -s -- /usr/local/opt/libiconv/lib/libiconv.a "$workdir"/lib
|
||
|
libgit2_cmake_flags="$libgit2_cmake_flags -DUSE_ICONV=ON"
|
||
|
libgit2_cflags="$libgit2_cflags -I/usr/local/opt/libiconv/include"
|
||
|
gitstatus_cxxflags="$gitstatus_cxxflags -I/usr/local/opt/libiconv/include"
|
||
|
gitstatus_ldlibs="$gitstatus_ldlibs -liconv"
|
||
|
gitstatus_ldflags="$gitstatus_ldflags -L${workdir}/lib"
|
||
|
;;
|
||
|
msys*|mingw*)
|
||
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
||
|
;;
|
||
|
cygwin*)
|
||
|
gitstatus_ldflags="$gitstatus_ldflags -static"
|
||
|
;;
|
||
|
*)
|
||
|
>&2 echo "[internal error] unhandled kernel: $gitstatus_kernel"
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
for cmd in cmake gcc g++ git ld "$gitstatus_make" wget; 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
|
||
|
libgit2_tarball="$outdir"/deps/libgit2-"$libgit2_version".tar.gz
|
||
|
if [ ! -e "$libgit2_tarball" ]; then
|
||
|
if [ -n "$gitstatus_download_deps" ]; then
|
||
|
libgit2_url=https://github.com/romkatv/libgit2/archive/"$libgit2_version".tar.gz
|
||
|
wget -O "$libgit2_tmp" -- "$libgit2_url"
|
||
|
mv -f -- "$libgit2_tmp" "$libgit2_tarball"
|
||
|
else
|
||
|
>&2 echo "[error] file not found: deps/libgit2-"$libgit2_version".tar.gz"
|
||
|
exit 1
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
cd -- "$workdir"
|
||
|
tar -xzf "$libgit2_tarball"
|
||
|
mv -- libgit2-"$libgit2_version" libgit2
|
||
|
mkdir libgit2/build
|
||
|
cd libgit2/build
|
||
|
|
||
|
CFLAGS="$libgit2_cflags" 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 \
|
||
|
-DENABLE_REPRODUCIBLE_BUILDS=OFF \
|
||
|
$libgit2_cmake_flags \
|
||
|
..
|
||
|
make -j "$cpus" VERBOSE=1
|
||
|
|
||
|
APPNAME="$appname".tmp \
|
||
|
OBJDIR="$workdir"/gitstatus \
|
||
|
CXX="$gitstatus_cxx" \
|
||
|
CXXFLAGS="$gitstatus_cxxflags" \
|
||
|
LDFLAGS="$gitstatus_ldflags" \
|
||
|
LDLIBS="$gitstatus_ldlibs" \
|
||
|
"$gitstatus_make" -C "$outdir" -j "$cpus"
|
||
|
|
||
|
app="$outdir"/usrbin/"$appname"
|
||
|
|
||
|
strip "$app".tmp
|
||
|
|
||
|
mkdir -- "$workdir"/repo
|
||
|
git -C "$workdir"/repo init --
|
||
|
git -C "$workdir"/repo config user.email "you@example.com"
|
||
|
git -C "$workdir"/repo commit --allow-empty --allow-empty-message -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*}" ]
|
||
|
|
||
|
mv -f -- "$app".tmp "$app"
|
||
|
|
||
|
cleanup
|
||
|
|
||
|
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;;
|
||
|
aarch64) gitstatus_cpu=armv8-a;;
|
||
|
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;;
|
||
|
*)
|
||
|
>&2 echo '[error] unable to infer docker image'
|
||
|
>&2 echo 'Please specify explicitly with `-i IMAGE`.'
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
fi
|
||
|
elif [ -n "$gitstatus_install_tools" ]; then
|
||
|
>&2 echo '[error] -s without -d is not supported on linux'
|
||
|
exit 1
|
||
|
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 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
|