#!/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 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 command brew list "$formula" &>/dev/null; then command brew upgrade "$formula" else command brew install "$formula" fi done ;; 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 brew_prefix="$(command brew --prefix)" command ln -s -- "$brew_prefix"/opt/libiconv/lib/libiconv.a "$workdir"/lib libgit2_cmake_flags="$libgit2_cmake_flags -DUSE_ICONV=ON" libgit2_cflags="$libgit2_cflags -I"$brew_prefix"/opt/libiconv/include" gitstatus_cxxflags="$gitstatus_cxxflags -I"$brew_prefix"/opt/libiconv/include" 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" &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