Files
agnos-builder/build_system.sh
Trey Moen 71e7369174 build_system: stream build output directly into rootfs (#552)
* build_system: stream build output directly into rootfs

Pipe buildx tar output directly into the mounted rootfs instead of
loading into Docker image store and then exporting. Skips the slow
"exporting layers" step and the intermediate container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* no

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-30 11:35:15 -07:00

140 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -e
UBUNTU_BASE_URL="https://cdimage.ubuntu.com/ubuntu-base/releases/24.04/release/"
UBUNTU_FILE="ubuntu-base-24.04.3-base-arm64.tar.gz"
UBUNTU_FILE_CHECKSUM="7b2dced6dd56ad5e4a813fa25c8de307b655fdabc6ea9213175a92c48dabb048"
# Make sure we're in the correct spot
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
cd $DIR
BUILD_DIR="$DIR/build"
OUTPUT_DIR="$DIR/output"
ROOTFS_DIR="$BUILD_DIR/agnos-rootfs"
ROOTFS_IMAGE="$BUILD_DIR/system.img"
OUT_IMAGE="$OUTPUT_DIR/system.img"
# the partition is 10G, but openpilot's updater didn't always handle the full size
# openpilot fix, shipped in 0.9.8 (8/18/24): https://github.com/commaai/openpilot/pull/33320
ROOTFS_IMAGE_SIZE=4500M
# Create temp dir if non-existent
mkdir -p $BUILD_DIR $OUTPUT_DIR
# Download Ubuntu Base if not done already
if [ ! -f $UBUNTU_FILE ]; then
echo -e "Downloading Ubuntu Base: $UBUNTU_FILE"
if ! curl -C - -o $UBUNTU_FILE $UBUNTU_BASE_URL/$UBUNTU_FILE --silent --remote-time --fail; then
echo "Download failed, please check Ubuntu releases: $UBUNTU_BASE_URL"
exit 1
fi
fi
# Check SHA256 sum
if [ "$(shasum -a 256 "$UBUNTU_FILE" | awk '{print $1}')" != "$UBUNTU_FILE_CHECKSUM" ]; then
echo "Checksum mismatch, please check Ubuntu releases: $UBUNTU_BASE_URL"
exit 1
fi
# Setup qemu multiarch
if [ "$(uname -m)" = "x86_64" ]; then
echo "Registering emulator"
docker run --rm --privileged tonistiigi/binfmt --install all
fi
# Check agnos-builder Dockerfile
export DOCKER_BUILDKIT=1
docker buildx build -f Dockerfile.agnos --check $DIR
# Check agnos-meta-builder Dockerfile
docker buildx build --load -f Dockerfile.builder --check $DIR \
--build-arg UNAME=$(id -nu) \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g)
# Setup mount container for macOS and CI support (namespace.so)
echo "Building agnos-meta-builder docker image"
docker buildx build --load -f Dockerfile.builder -t agnos-meta-builder $DIR \
--build-arg UNAME=$(id -nu) \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g)
echo "Starting agnos-meta-builder container"
MOUNT_CONTAINER_ID=$(docker run -d --privileged -v $DIR:$DIR agnos-meta-builder)
# Cleanup containers on possible exit
trap "echo \"Cleaning up containers:\"; \
docker container rm -f $MOUNT_CONTAINER_ID" EXIT
# Define functions for docker execution
exec_as_user() {
docker exec -u $(id -nu) $MOUNT_CONTAINER_ID "$@"
}
exec_as_root() {
docker exec $MOUNT_CONTAINER_ID "$@"
}
# Create filesystem ext4 image
echo "Creating empty filesystem"
exec_as_user fallocate -l $ROOTFS_IMAGE_SIZE $ROOTFS_IMAGE
exec_as_user mkfs.ext4 $ROOTFS_IMAGE &> /dev/null
# Mount filesystem
echo "Mounting empty filesystem"
exec_as_root mkdir -p $ROOTFS_DIR
exec_as_root mount $ROOTFS_IMAGE $ROOTFS_DIR
# Also unmount filesystem (overwrite previous trap)
trap "exec_as_root umount -l $ROOTFS_DIR &> /dev/null || true; \
echo \"Cleaning up containers:\"; \
docker container rm -f $MOUNT_CONTAINER_ID" EXIT
echo "Building and extracting agnos-builder docker image"
BUILD="docker buildx build"
if [ ! -z "$NS" ]; then
BUILD="nsc build"
fi
$BUILD -f Dockerfile.agnos \
--output "type=tar,dest=-" \
--provenance=false \
--build-arg UBUNTU_BASE_IMAGE=$UBUNTU_FILE \
--platform=linux/arm64 \
"$DIR" | docker exec -i $MOUNT_CONTAINER_ID tar -xf - -C $ROOTFS_DIR
# Avoid detecting as container
echo "Removing .dockerenv file"
exec_as_root rm -f $ROOTFS_DIR/.dockerenv
echo "Setting network stuff"
set_network_stuff() {
cd $ROOTFS_DIR
# Add hostname and hosts. This cannot be done in the docker container...
HOST=comma
bash -c "ln -sf /proc/sys/kernel/hostname etc/hostname"
bash -c "echo \"127.0.0.1 localhost.localdomain localhost\" > etc/hosts"
bash -c "echo \"127.0.0.1 $HOST\" >> etc/hosts"
# Fix resolv config
bash -c "ln -sf /run/systemd/resolve/stub-resolv.conf etc/resolv.conf"
# Set capability for ping
bash -c "setcap cap_net_raw+ep bin/ping"
# Write build info
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
bash -c "printf \"$GIT_HASH\n$DATETIME\n\" > BUILD"
}
GIT_HASH=${GIT_HASH:-$(git --git-dir=$DIR/.git rev-parse HEAD)}
exec_as_root bash -c "set -e; export ROOTFS_DIR=$ROOTFS_DIR GIT_HASH=$GIT_HASH; $(declare -f set_network_stuff); set_network_stuff"
# Unmount image
echo "Unmount filesystem"
exec_as_root umount -l $ROOTFS_DIR
# Sparsify system image
exec_as_user img2simg $ROOTFS_IMAGE $OUT_IMAGE
echo "Done!"