Files
Ben NeigherandGitHub 15d004912b builder.sh: propagate the build failure instead of always exiting 0 (#136)
Verified rather than taken on description.

`BUILD_RC=$?` is the line immediately after `make BOARD=${DEVICE}`, so nothing
clobbers the status before it is captured, and `exit ${BUILD_RC}` uses the saved
value rather than re-reading `$?` after `echo_c`. `sh -n`, `dash -n` and
`bash -n` all clean. The branch point (`222db9e`) carries a byte-identical
`builder.sh` to master -- md5 `2292222e081fecf876e022c373a943e5` at both -- so
the diff is exactly these twenty lines. 114 checks green.

Agreed on explicit status propagation over `set -e`: the script does enough
unguarded `cp`/`rm`/`cd` that global errexit would change failure behaviour well
beyond this line, and `size-report` keeping its `|| true` is right.

Worth stating plainly for whoever reads this later: this makes the six-step
backoff in `master.yml` live for the first time. A deterministically failing
board -- a rootfs that no longer fits NOR, say -- will now be rebuilt seven times
across roughly 38 minutes of sleeps before the job goes red, where previously it
went green instantly. That is the correct behaviour and the point of the change,
but it is a real shift in what a broken nightly costs, and if it proves
expensive the fix is to make the retry discriminate transient failures from
deterministic ones, not to go back to a script that cannot fail.
2026-08-29 07:15:19 +03:00

187 lines
6.5 KiB
Bash
Executable File

#!/bin/bash
#
# OpenIPC | version 2023.11.30
# Autoupdate BUILDER repo
# Remove old building folder (for full rebuild)
# Download OpenIPC repo
# Copy files from Device Overlay
# Build Firmware
# Copy Kernel and Rootfs to Archive
# Copy Kernel and Rootfs to TFTP server
DEVICE="$1"
BUILDER_DIR=$(pwd)
FIRMWARE_DIR="${BUILDER_DIR}/openipc"
TIMESTAMP=$(date +"%Y%m%d%H%M")
VERSION=$(stat -c"%Y" $0)
echo_c() {
# 30 grey, 31 red, 32 green, 33 yellow, 34 blue, 35 magenta, 36 cyan, 37 white
t="\e[1;$1m$2\e[0m" || t="$2"
echo -e "$t"
}
autoup_rootfs() {
DT=$(date +"%y.%m.%d")
OPENIPC_VER=$(echo OpenIPC v${DT:0:1}.${DT:1})
SOC=$(echo ${DEVICE} | cut -d_ -f1)
echo_c 34 "\nDownloading u-boot created by OpenIPC"
curl --location --output ./output/images/u-boot-${SOC}-universal.bin \
https://github.com/OpenIPC/firmware/releases/download/latest/u-boot-${SOC}-universal.bin
echo_c 34 "\nMaking autoupdate u-boot image"
./output/host/bin/mkimage -A arm -O linux -T firmware -n "$OPENIPC_VER" \
-a 0x0 -e 0x50000 -d ./output/images/u-boot-${SOC}-universal.bin \
./output/images/autoupdate-uboot.img
echo_c 34 "\nMaking autoupdate kernel image"
./output/host/bin/mkimage -A arm -O linux -T kernel -C none -n "$OPENIPC_VER" \
-a 0x50000 -e 0x250000 -d ./output/images/uImage.${SOC} \
./output/images/autoupdate-kernel.img
echo_c 34 "\nMaking autoupdate rootfs image"
./output/host/bin/mkimage -A arm -O linux -T filesystem -n "$OPENIPC_VER" \
-a 0x250000 -e 0x750000 -d ./output/images/rootfs.squashfs.${SOC} \
./output/images/autoupdate-rootfs.img
}
copy_to_archive() {
echo_c 32 "Copying files to local archive"
mkdir -p "${BUILDER_DIR}/archive/${DEVICE}/${TIMESTAMP}"
cp -a \
${FIRMWARE_DIR}/output/images/rootfs.squashfs.* \
${FIRMWARE_DIR}/output/images/uImage.* \
${FIRMWARE_DIR}/output/images/*.tar \
${FIRMWARE_DIR}/output/images/openipc.*.tgz \
${BUILDER_DIR}/archive/${DEVICE}/${TIMESTAMP}
cp -a ${FIRMWARE_DIR}/output/images/sizes.*.json \
${BUILDER_DIR}/archive/${DEVICE}/${TIMESTAMP} 2>/dev/null || true
if [ -f "${FIRMWARE_DIR}/output/images/autoupdate-kernel.img" ]; then
cp -a ${FIRMWARE_DIR}/output/images/autoupdate* ${BUILDER_DIR}/archive/${DEVICE}/${TIMESTAMP}
fi
echo_c 35 "\nAssembled firmware available in:"
tree -C "${BUILDER_DIR}/archive/${DEVICE}/${TIMESTAMP}"
if $(echo ${DEVICE} | grep -q hi3518ev200_lite); then
autoup_rootfs
fi
}
copy_to_tftp() {
echo_c 32 "\nCopying files to a TFTP server using SCP protocol"
scp -r \
${FIRMWARE_DIR}/output/images/rootfs.squashfs.* \
${FIRMWARE_DIR}/output/images/uImage.* \
${FIRMWARE_DIR}/output/images/openipc.*.tgz \
${TFTP_STORAGE}
if [ -f "${FIRMWARE_DIR}/output/images/autoupdate-kernel.img" ]; then
scp -r ${FIRMWARE_DIR}/output/images/autoupdate* ${TFTP_STORAGE}
fi
}
select_device() {
AVAILABLE_DEVICES=$(find devices -name *_defconfig | sort | cut -d/ -f5)
cmd="whiptail --title \"Available devices\" --menu \"Please select a device from the list below:\" 20 70 12"
for p in ${AVAILABLE_DEVICES//_defconfig}; do cmd="${cmd} \"$p\" \"\""; done
DEVICE=$(eval "${cmd} 3>&1 1>&2 2>&3")
if [ $? != 0 ]; then
echo_c 31 "Cancelled."
exit 1
fi
}
copy_extra_packages() {
extra_package=${BUILDER_DIR}/package
firmware_package=${FIRMWARE_DIR}/general/package
cp -afv $extra_package/* $firmware_package
package_list_file=$firmware_package/Config.in
for f in "$extra_package"/*
do
package_name=$(basename $f)
if ! grep -Fq "$package_name" $package_list_file
then
printf 'source "$BR2_EXTERNAL_GENERAL_PATH/package/%s/Config.in"\n' $package_name >> $package_list_file
fi
done
}
echo_c 37 "Experimental system for building OpenIPC firmware for known devices"
echo_c 30 "https://openipc.org/"
echo_c 30 "Version: ${VERSION}"
while [ -z "${DEVICE}" ]; do select_device; done
echo_c 31 "\nStarting a device for ${DEVICE}"
ITEM=$(find devices -name ${DEVICE}_defconfig | cut -d/ -f1,2)
tree -C "${ITEM}"
sleep 3
echo_c 33 "\nUpdating Builder"
git pull
rm -rf openipc
# OPENIPC_FW_REV pins firmware to a specific ref (branch, tag, or SHA) for
# cross-repo bisect of size/regression issues — set by build-one.yml's
# firmware_ref input. When unset, clones HEAD of master as before.
if [ ! -d "$FIRMWARE_DIR" ]; then
if [ -n "$OPENIPC_FW_REV" ]; then
echo_c 33 "\nDownloading Firmware @ ${OPENIPC_FW_REV}"
git clone https://github.com/OpenIPC/firmware.git "$FIRMWARE_DIR"
git -C "$FIRMWARE_DIR" checkout "$OPENIPC_FW_REV"
else
echo_c 33 "\nDownloading Firmware"
git clone --depth=1 https://github.com/OpenIPC/firmware.git "$FIRMWARE_DIR"
fi
cd "$FIRMWARE_DIR"
else
echo_c 33 "\nUpdating Firmware"
cd "$FIRMWARE_DIR"
# git reset HEAD --hard
# git pull --rebase
fi
echo_c 33 "\nCopying extra packages"
copy_extra_packages
echo_c 33 "\nCopying device files"
cp -afv ${BUILDER_DIR}/${ITEM}/* ${FIRMWARE_DIR}
echo_c 33 "\nBuilding the device"
# Propagate make's status. Without this the script ALWAYS exits 0: the result is
# discarded, copy_to_archive then runs over an empty output/images and still
# prints "Assembled firmware available in:", and the caller sees success over an
# empty directory.
#
# The expensive consequence is in CI. master.yml calls this inside a retry loop
# written as `bash builder.sh ${NAME} && break`, wrapped in a six-step backoff
# meant to absorb transient toolchain and CDN flakes. A script that cannot fail
# breaks on the first attempt, so the budget never retried anything and the
# `exit 1` after the loop was unreachable — a genuinely failed build reported
# green instead of being re-attempted.
#
# Explicit rather than `set -e` at the top: this script does a lot of unguarded
# cp/rm/cd, and enabling errexit globally would change failure behaviour well
# beyond this line.
make BOARD=${DEVICE}
BUILD_RC=$?
if [ ${BUILD_RC} -ne 0 ]; then
echo_c 31 "\nBuild FAILED (make exited ${BUILD_RC}) - not archiving"
exit ${BUILD_RC}
fi
# Best-effort: emit per-package/per-kernel-module size JSON next to the .tgz.
# Target lives in firmware's Makefile (PR #2166); ignore failure so legacy
# pinned firmware refs without the target don't sink the build.
make BOARD=${DEVICE} size-report || true
copy_to_archive
echo_c 35 "\nDone"
cd "$BUILDER_DIR"