#!/bin/sh # shellcheck disable=SC3043 . $CI_PROJECT_DIR/.gitlab/bin/functions.sh # shellcheck disable=SC3040 set -eu -o pipefail readonly APORTSDIR=$CI_PROJECT_DIR readonly REPOS="cross backports user testing community" readonly ALPINE_REPOS="main community testing" readonly ARCH=$(apk --print-arch) # gitlab variables readonly BASEBRANCH=$CI_MERGE_REQUEST_TARGET_BRANCH_NAME : "${REPODEST:=$HOME/packages}" : "${MIRROR:=https://lab.ilot.io/ayakael/repo-apk/-/raw}" : "${ALPINE_MIRROR:=http://dl-cdn.alpinelinux.org/alpine}" : "${MAX_ARTIFACT_SIZE:=300000000}" #300M : "${CI_DEBUG_BUILD:=}" : "${CI_ALPINE_BUILD_OFFSET:=0}" : "${CI_ALPINE_BUILD_LIMIT:=9999}" : "${CI_ALPINE_TARGET_ARCH:=$(uname -m)}" msg() { local color=${2:-green} case "$color" in red) color="31";; green) color="32";; yellow) color="33";; blue) color="34";; *) color="32";; esac printf "\033[1;%sm>>>\033[1;0m %s\n" "$color" "$1" | xargs >&2 } verbose() { echo "> " "$@" # shellcheck disable=SC2068 $@ } debugging() { [ -n "$CI_DEBUG_BUILD" ] } debug() { if debugging; then verbose "$@" fi } die() { msg "$1" red exit 1 } capture_stderr() { "$@" 2>&1 } report() { report=$1 reportsdir=$APORTSDIR/logs/ mkdir -p "$reportsdir" tee -a "$reportsdir/$report.log" } get_release() { case $BASEBRANCH in v*) echo "${BASEBRANCH%-*}";; edge) echo edge;; *) die "Branch \"$BASEBRANCH\" not supported!" esac } build_aport() { local repo="$1" aport="$2" cd "$APORTSDIR/$repo/$aport" export CHOST=$CI_ALPINE_TARGET_ARCH if abuild -r 2>&1 | report "build-$aport"; then checkapk | report "checkapk-$aport" || true aport_ok="$aport_ok $repo/$aport" else aport_ng="$aport_ng $repo/$aport" fi } check_aport() { local repo="$1" aport="$2" cd "$APORTSDIR/$repo/$aport" export CHOST=$CI_ALPINE_TARGET_ARCH # TODO: this enables crossbuild only on user, this should be cleaner if [ "$repo" != "user" ] && [ "$repo" != "backports" ] && [ "$CI_ALPINE_TARGET_ARCH" != "$ARCH" ]; then aport_na="$aport_na $repo/$aport" return 1 fi if ! abuild check_arch 2>/dev/null; then aport_na="$aport_na $repo/$aport" return 1 fi } set_repositories_for() { local target_repo="$1" repos='' repo='' local release release=$(get_release) for repo in $REPOS; do repos="$repos $MIRROR/$release/$repo $REPODEST/$repo" [ "$repo" = "$target_repo" ] && break done sudo sh -c "printf '%s\n' $repos >> /etc/apk/repositories" sudo apk update || true if [ "$CI_ALPINE_TARGET_ARCH" != "$ARCH" ]; then sudo sh -c "printf '%s\n' $repos >> $HOME/sysroot-$CI_ALPINE_TARGET_ARCH/etc/apk/repositories" sudo cp -R /etc/apk/keys/* $HOME/sysroot-$CI_ALPINE_TARGET_ARCH/etc/apk/keys/. sudo apk --root=$HOME/sysroot-$CI_ALPINE_TARGET_ARCH update || true fi } apply_offset_limit() { start=$1 limit=$2 end=$((start+limit)) sed -n "$((start+1)),${end}p" } setup_system() { local repos='' repo='' local release release=$(get_release) for repo in $ALPINE_REPOS; do [ "$release" != "edge" ] && [ "$repo" == "testing" ] && continue repos="$repos $ALPINE_MIRROR/$release/$repo" done repos="$repos $MIRROR/$release/cross" sudo sh -c "printf '%s\n' $repos > /etc/apk/repositories" sudo apk -U upgrade -a || sudo apk fix || die "Failed to up/downgrade system" if [ "$CI_ALPINE_TARGET_ARCH" != "$ARCH" ]; then sudo apk add gcc-$CI_ALPINE_TARGET_ARCH fi gitlab_key_to_rsa $ABUILD_KEY rsa-private $HOME/.abuild/$ABUILD_KEY_NAME.rsa gitlab_key_to_rsa $ABUILD_KEY_PUB rsa-public $HOME/.abuild/$ABUILD_KEY_NAME.rsa.pub chmod 700 $HOME/.abuild/$ABUILD_KEY_NAME.rsa echo "PACKAGER_PRIVKEY=$HOME/.abuild/$ABUILD_KEY_NAME.rsa" >> $HOME/.abuild/abuild.conf sudo cp $HOME/.abuild/$ABUILD_KEY_NAME.rsa.pub /etc/apk/keys/$ABUILD_KEY_NAME.rsa.pub # patch abuild for crosscompiling sudo patch -p1 -d / -i $CI_PROJECT_DIR/.gitlab/patches/abuild-cross.patch sudo sed -i -E 's/export JOBS=[0-9]+$/export JOBS=$(nproc)/' /etc/abuild.conf ( . /etc/abuild.conf && echo "Building with $JOBS jobs" ) mkdir -p "$REPODEST" git config --global init.defaultBranch master } sysinfo() { printf ">>> Host system information (arch: %s, release: %s) <<<\n" "$ARCH" "$(get_release)" printf "- Number of Cores: %s\n" "$(nproc)" printf "- Memory: %s Gb\n" "$(awk '/^MemTotal/ {print ($2/1024/1024)}' /proc/meminfo)" printf "- Free space: %s\n" "$(df -hP / | awk '/\/$/ {print $4}')" } copy_artifacts() { cd "$APORTSDIR" packages_size="$(du -sk "$REPODEST" | awk '{print $1 * 1024}')" if [ -z "$packages_size" ]; then return fi echo "Artifact size: $packages_size bytes" mkdir -p keys/ packages/ if [ "$packages_size" -lt $MAX_ARTIFACT_SIZE ]; then msg "Copying packages for artifact upload" cp -ar "$REPODEST"/* packages/ 2>/dev/null cp ~/.abuild/*.rsa.pub keys/ else msg "Artifact size $packages_size larger than max ($MAX_ARTIFACT_SIZE), skipping uploading them" yellow fi } section_start setup "Setting up the system" collapse if debugging; then set -x fi aport_ok= aport_na= aport_ng= failed= sysinfo || true setup_system || die "Failed to setup system" # git no longer allows to execute in repositories owned by different users sudo chown -R $USER: . fetch_flags="-qn" debugging && fetch_flags="-v" git fetch $fetch_flags "$CI_MERGE_REQUEST_PROJECT_URL" \ "+refs/heads/$BASEBRANCH:refs/heads/$BASEBRANCH" if debugging; then merge_base=$(git merge-base "$BASEBRANCH" HEAD) || echo "Could not determine merge-base" echo "Merge base: $merge_base" git --version git config -l [ -n "$merge_base" ] && git tag -f merge-base "$merge_base" git --no-pager log -200 --oneline --graph --decorate --all fi section_end setup build_start=$CI_ALPINE_BUILD_OFFSET build_limit=$CI_ALPINE_BUILD_LIMIT for repo in $(changed_repos); do mkdir -p "$APORTSDIR"/logs "$APORTSDIR"/packages "$APORTSDIR"/keys set_repositories_for "$repo" built_aports=0 changed_aports_in_repo=$(changed_aports "$repo") changed_aports_in_repo_count=$(echo "$changed_aports_in_repo" | wc -l) changed_aports_to_build=$(echo "$changed_aports_in_repo" | apply_offset_limit "$build_start" "$build_limit") msg "Changed aports in $repo:" # shellcheck disable=SC2086 # Splitting is expected here printf " - %s\n" $changed_aports_to_build for pkgname in $changed_aports_to_build; do section_start "build_$pkgname" "Building package $pkgname" built_aports=$((built_aports+1)) if check_aport "$repo" "$pkgname"; then build_aport "$repo" "$pkgname" fi section_end "build_$pkgname" done build_start=$((build_start-(changed_aports_in_repo_count-built_aports))) build_limit=$((build_limit-built_aports)) if [ $build_limit -le 0 ]; then msg "Limit reached, breaking" break fi done section_start artifacts "Handeling artifacts" collapse copy_artifacts || true section_end artifacts section_start summary "Build summary" echo "### Build summary ###" for ok in $aport_ok; do msg "$ok: build succesfully" done for na in $aport_na; do msg "$na: disabled for $CI_ALPINE_TARGET_ARCH" yellow done for ng in $aport_ng; do msg "$ng: build failed" red failed=true done section_end summary if [ "$failed" = true ]; then exit 1 elif [ -z "$aport_ok" ]; then msg "No packages found to be built." yellow fi