Verified Commit 07239499 authored by David Runge's avatar David Runge 🐿
Browse files

Add scripts for continuous integration

Add script to be run in a container with access to qemu.
It is a slight modification of arch-boxes' script to cater to the specific archiso requirements.

Add script to be run in virtualized environment, established by
This script builds the actual archiso profiles and creates checksum for the resulting image files.
parent f9a7b206
# runs in a qemu VM running the latest Arch installer iso
# nounset: "Treat unset variables and parameters [...] as an error when performing parameter expansion."
# errexit: "Exit immediately if [...] command exits with a non-zero status."
set -o nounset -o errexit
readonly MIRROR=""
function init() {
readonly ORIG_PWD="${PWD}"
readonly OUTPUT="${PWD}/output"
readonly TMPDIR="$(mktemp --dry-run --directory --tmpdir="${PWD}/tmp")"
mkdir -p "${OUTPUT}" "${TMPDIR}"
cd "${TMPDIR}"
# Do some cleanup when the script exits
function cleanup() {
rm -rf "${TMPDIR}"
jobs -p | xargs --no-run-if-empty kill
trap cleanup EXIT
# Use local Arch iso or download the latest iso and extract the relevant files
function prepare_boot() {
if LOCAL_ISO="$(ls "${ORIG_PWD}/"archlinux-*-x86_64.iso 2>/dev/null)"; then
echo "Using local iso: ${LOCAL_ISO}"
if [ -z "${LOCAL_ISO}" ]; then
LATEST_ISO="$(curl -fs "${MIRROR}/iso/latest/" | grep -Eo 'archlinux-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64.iso' | head -n 1)"
if [ -z "${LATEST_ISO}" ]; then
echo "Error: Couldn't find latest iso'"
exit 1
curl -fO "${MIRROR}/iso/latest/${LATEST_ISO}"
# We need to extract the kernel and initrd so we can set a custom cmdline:
# console=ttyS0, so the kernel and systemd sends output to the serial.
xorriso -osirrox on -indev "${ISO}" -extract arch/boot/x86_64 .
ISO_VOLUME_ID="$(xorriso -indev "${ISO}" |& awk -F : '$1 ~ "Volume id" {print $2}' | tr -d "' ")"
function start_qemu() {
# Used to communicate with qemu
mkfifo guest.out
# We could use a sparse file but we want to fail early
fallocate -l 8G scratch-disk.img
{ qemu-system-x86_64 \
-machine accel=kvm:tcg \
-smp "$(nproc)" \
-m 4096 \
-net nic \
-net user \
-kernel vmlinuz-linux \
-initrd initramfs-linux.img \
-append "archisobasedir=arch archisolabel=${ISO_VOLUME_ID} ip=dhcp net.ifnames=0 console=ttyS0 mirror=${MIRROR}" \
-drive file=scratch-disk.img,format=raw,if=virtio \
-drive file="${ISO}",format=raw,if=virtio,media=cdrom,read-only \
-virtfs "local,path=${ORIG_PWD},mount_tag=host,security_model=none" \
-monitor none \
-serial pipe:guest \
-nographic || kill "${$}"; } &
# We want to send the output to both stdout (fd1) and fd10 (used by the expect function)
exec 3>&1 10< <(tee /dev/fd/3 <guest.out)
# Wait for a specific string from qemu
function expect() {
local length="${#1}"
local i=0
local timeout="${2:-30}"
# We can't use ex: grep as we could end blocking forever, if the string isn't followed by a newline
while true; do
# read should never exit with a non-zero exit code,
# but it can happen if the fd is EOF or it times out
IFS= read -r -u 10 -n 1 -t "${timeout}" c
if [ "${1:${i}:1}" = "${c}" ]; then
i="$((i + 1))"
if [ "${length}" -eq "${i}" ]; then
# Send string to qemu
function send() {
echo -en "${1}" >
function main() {
# Login
expect "archiso login:"
send "root\n"
expect "# "
# Switch to bash and shutdown on error
send "bash\n"
expect "# "
send "trap \"shutdown now\" ERR\n"
expect "# "
# Prepare environment
send "mkdir /mnt/project && mount -t 9p -o trans=virtio host /mnt/project -oversion=9p2000.L\n"
expect "# "
send "mkfs.ext4 /dev/vda && mkdir /mnt/scratch-disk/ && mount /dev/vda /mnt/scratch-disk && cd /mnt/scratch-disk\n"
expect "# "
send "cp -a /mnt/project/{.gitlab,archiso,configs,scripts} .\n"
expect "# "
send "mkdir pkg && mount --bind pkg /var/cache/pacman/pkg\n"
expect "# "
# Wait for pacman-init
send "until systemctl is-active pacman-init; do sleep 1; done\n"
expect "# "
# Explicitly lookup mirror address as we'd get random failures otherwise during pacman
send "curl -sSo /dev/null ${MIRROR}\n"
expect "# "
# Install required packages
send "pacman -Sy --noconfirm qemu-headless jq dosfstools e2fsprogs libisoburn mtools squashfs-tools\n"
expect "# "
## Start build and copy output to local disk
send "bash -x ./.gitlab/ci/ ${PROFILE}\n "
expect "# " 1000 # mksquashfs can take a long time
send "cp -r --preserve=mode,timestamps output /mnt/project/tmp/$(basename "${TMPDIR}")/\n"
expect "# " 60
mv output/* "${OUTPUT}/"
# Shutdown the VM
send "shutdown now\n"
#!/usr/bin/env bash
# This script is run within a virtual environment to build the available archiso profiles and create checksum files for
# the resulting images.
# The script needs to be run as root and assumes $PWD to be the root of the repository.
readonly orig_pwd="${PWD}"
readonly output="${orig_pwd}/output"
readonly tmpdir="$(mktemp --dry-run --directory --tmpdir="${orig_pwd}/tmp")"
cleanup() {
# clean up temporary directories
if [ -n "${tmpdir:-}" ]; then
rm -rf "${tmpdir}"
create_checksums() {
# create checksums for a file
# $1: a file
sha256sum "${1}" >"${1}.sha256"
sha512sum "${1}" >"${1}.sha512"
b2sum "${1}" >"${1}.b2"
if [ -n "${SUDO_UID:-}" ]; then
chown "${SUDO_UID}:${SUDO_GID}" "${1}"{,.b2,.sha{256,512}}
run_mkarchiso() {
# run mkarchiso
# $1: template name
mkdir -p "${output}/${1}" "${tmpdir}/${1}"
./archiso/mkarchiso -o "${output}/${1}" -w "${tmpdir}/${1}" -v "configs/${1}"
create_checksums "${output}/${1}/"*.iso
trap cleanup EXIT
run_mkarchiso "${1}"
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment