#!/bin/bash set -e NO_CACHE="" KEEP_PKG_CACHE="" LOCAL_OMARCHY_PATH="" LOCAL_PKGS_PATH="" while [[ $# -gt 0 ]]; do case $1 in --no-cache) NO_CACHE=1 shift ;; --keep-pkg-cache) KEEP_PKG_CACHE=1 shift ;; --no-boot-offer) NO_BOOT_OFFER=1 shift ;; --debug) OMARCHY_INSTALL_DEBUG=1 shift ;; --edge) OMARCHY_ISO_REF=edge OMARCHY_MIRROR=edge shift ;; --local-source) LOCAL_OMARCHY_PATH="${2:-}" LOCAL_PKGS_PATH="${3:-}" if [[ -z $LOCAL_OMARCHY_PATH || -z $LOCAL_PKGS_PATH ]]; then echo "Error: --local-source requires two args: " >&2 exit 1 fi OMARCHY_MIRROR=edge OMARCHY_ISO_REF=local shift 3 ;; --dev) OMARCHY_ISO_REF=dev OMARCHY_MIRROR=edge shift ;; --quattro) OMARCHY_INSTALLER_REF=quattro OMARCHY_MIRROR=edge shift ;; --rc) OMARCHY_ISO_REF=rc OMARCHY_MIRROR=rc shift ;; *) echo "Unknown option: $1" echo "Usage: $0 [--no-cache] [--keep-pkg-cache] [--no-boot-offer] [--debug] [--edge] [--dev|--rc] [--local-source ]" exit 1 ;; esac done if [[ -n $LOCAL_OMARCHY_PATH ]]; then [[ -d $LOCAL_OMARCHY_PATH ]] || { echo "Error: Omarchy checkout not found at $LOCAL_OMARCHY_PATH" >&2; exit 1; } [[ -d $LOCAL_PKGS_PATH ]] || { echo "Error: pkgs checkout not found at $LOCAL_PKGS_PATH" >&2; exit 1; } LOCAL_OMARCHY_PATH=$(realpath "$LOCAL_OMARCHY_PATH") LOCAL_PKGS_PATH=$(realpath "$LOCAL_PKGS_PATH") fi lint_file_permissions() { local profiledef="configs/profiledef.sh" local -A declared=() local missing=() while IFS= read -r path; do [[ -n $path ]] && declared["$path"]=1 done < <(grep -oP '^\s*\["\K[^"]+(?="\])' "$profiledef" || true) while IFS= read -r f; do [[ -f $f ]] || continue local rel="${f#configs/airootfs}" local mode mode=$(git ls-files --stage -- "$f" | awk '{print $1}') if [[ $mode != 100755 && $(head -c 2 "$f") != "#!" ]]; then continue fi if [[ -z ${declared[$rel]+x} ]]; then missing+=("$rel") fi done < <(find configs/airootfs/usr/local/bin configs/airootfs/root -type f 2>/dev/null) if (( ${#missing[@]} > 0 )); then echo "ERROR: the following executable files are missing from $profiledef file_permissions:" >&2 printf ' %s\n' "${missing[@]}" >&2 echo "Add entries like [\"\"]=\"0:0:755\" to profiledef.sh and retry." >&2 exit 1 fi } lint_file_permissions # Purging the host package cache needs interactive sudo; --keep-pkg-cache # skips it so unattended builds (test rigs, agents) can run without a prompt. if [[ -z $KEEP_PKG_CACHE ]]; then sudo rm -rf /var/cache/pacman/pkg/* fi git submodule update --init --recursive --jobs=8 BUILD_SCRIPT="builder/build-iso.sh" BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..") BUILD_RELEASE_PATH="$BUILD_ROOT/release" mkdir -p "$BUILD_RELEASE_PATH" OMARCHY_ISO_REF="${OMARCHY_ISO_REF:-quattro}" OMARCHY_MIRROR="${OMARCHY_MIRROR:-stable}" DOCKER_ARGS=( --rm --privileged -e "OMARCHY_ISO_REF=$OMARCHY_ISO_REF" -e "OMARCHY_MIRROR=$OMARCHY_MIRROR" -e "OMARCHY_INSTALL_DEBUG=${OMARCHY_INSTALL_DEBUG:-}" -e "HOST_UID=$(id -u)" -e "HOST_GID=$(id -g)" -v "$BUILD_RELEASE_PATH/:/out/" -v "$BUILD_ROOT/$BUILD_SCRIPT:/$BUILD_SCRIPT:ro" -v "$BUILD_ROOT/archiso:/archiso:ro" -v "$BUILD_ROOT/builder:/builder:ro" -v "$BUILD_ROOT/configs:/configs:ro" ) if [[ -n $LOCAL_OMARCHY_PATH ]]; then DOCKER_ARGS+=( -v "$LOCAL_OMARCHY_PATH:/omarchy-source:ro" -v "$LOCAL_PKGS_PATH:/omarchy-pkgs:ro" ) fi if [[ -d /var/cache/pacman/pkg ]]; then DOCKER_ARGS+=(-v "/var/cache/pacman/pkg:/var/cache/pacman/pkg") fi # Mount the build cache directory where packages are downloaded. Channels use # different package snapshots and must never share an offline mirror cache. if [[ -z "$NO_CACHE" ]]; then OFFLINE_REPO_BUILD_CACHE_DIR="$HOME/.cache/omarchy/iso_${OMARCHY_MIRROR}/airootfs/var/cache/omarchy" mkdir -p "$OFFLINE_REPO_BUILD_CACHE_DIR" DOCKER_ARGS+=(-v "$OFFLINE_REPO_BUILD_CACHE_DIR:/var/cache/airootfs/var/cache/omarchy") else # The locally cached :latest image is a cache too — docker run never # re-checks the registry for it, so refresh it when building cold. DOCKER_ARGS+=(--pull=always) fi # The docker group is root-equivalent, so Omarchy operators stay out of it on # purpose. When the socket refuses the calling user, run the client through # sudo instead of requiring group membership. DOCKER=(docker) if ! docker version &>/dev/null; then DOCKER=(sudo docker) fi "${DOCKER[@]}" run "${DOCKER_ARGS[@]}" ghcr.io/archlinux/archlinux:latest /$BUILD_SCRIPT latest_iso=$(\ls -t "$BUILD_RELEASE_PATH"/*.iso | head -n1) iso_ref="${latest_iso%.*}-$OMARCHY_ISO_REF.iso" mv -f "$latest_iso" "$iso_ref" if [[ -z "${NO_BOOT_OFFER:-}" ]]; then echo gum confirm "Boot $iso_ref?" && "$BUILD_ROOT/bin/omarchy-iso-boot" "$iso_ref" fi