#!/bin/bash set -euo pipefail WORK_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_URL="git@git.ayau.me:mira/gentoo-pill.git" REPO="${WORK_DIR}/repo" CTX="${WORK_DIR}/ctx" IMAGE="docker.io/gentoo/stage3:amd64-desktop-openrc" CONTAINER_NAME="gentoo_builder" PROFILE="default/linux/amd64/23.0/desktop" LOG_FILE="/var/log/gentoo_build.log" # inside container HOST_KEY_PATH="${WORK_DIR}/secrets/signing.key" if [[ ! -f "$HOST_KEY_PATH" ]]; then echo "Error: no key at $HOST_KEY_PATH" exit 1 fi if [[ ! -d "$REPO/.git" ]]; then echo "Cloning repo..." git clone "$REPO_URL" "$REPO" else echo "Updating repo..." # juts reset here git -C "$REPO" fetch origin git -C "$REPO" reset --hard origin/master fi echo "Aggregating config..." rm -rf "$CTX" && mkdir -p "$CTX"/var/lib/portage inject() { local src=$1 prefix=$2 dest_dir=$3 [[ ! -e "$src" ]] && return if [[ -d "$src" ]]; then shopt -s nullglob for f in "$src"/*; do [[ -f "$f" ]] && cp "$f" "$dest_dir/${prefix}-$(basename "$f")" done shopt -u nullglob else cp "$src" "$dest_dir/${prefix}-$(basename "$src")" fi } # config types to merge CONFIGS=(package.use package.accept_keywords package.license package.mask package.unmask package.env repos.conf) for type in "${CONFIGS[@]}"; do dest="$CTX/etc/portage/$type" mkdir -p "$dest" inject "$REPO/common/$type" "00-common" "$dest" for host_dir in "$REPO/hosts"/*; do [[ -d "$host_dir" ]] || continue hostname=$(basename "$host_dir") inject "$host_dir/$type" "50-${hostname}" "$dest" done done # generate world union cat "$REPO"/hosts/*/world 2>/dev/null | sort -u | sed '/^#/d;/^$/d' > "$CTX/var/lib/portage/world" echo "Packages in aggregated world file: $(wc -l < "$CTX/var/lib/portage/world")" # make.conf mkdir -p "$CTX/etc/portage" cp "$REPO/binhost/make.conf" "$CTX/etc/portage/make.conf" init_container() { echo "Creating new builder container..." # podman volume create portage_db # podman volume create distfiles # podman volume create binpkgs podman run -d \ --name "$CONTAINER_NAME" \ --cap-add=SYS_PTRACE \ -v portage_db:/var/db/repos/gentoo \ -v distfiles:/var/cache/distfiles \ -v binpkgs:/var/cache/binpkgs \ -v "$HOST_KEY_PATH":/tmp/signing.key:ro \ --tmpfs /var/tmp/portage:rw,size=48G,mode=1777 \ "$IMAGE" \ bin/bash -c "sleep infinity" echo "Running setup..." podman exec "$CONTAINER_NAME" bash -c " mkdir -p /root/.gnupg echo 'allow-loopback-pinentry' > /root/.gnupg/gpg-agent.conf gpg-connect-agent reloadagent /bye gpg --batch --import /tmp/signing.key mkdir -p /etc/portage/gnupg gpg --export | gpg --homedir /etc/portage/gnupg --import # really yikes man, i don't know what it's doing # that it can't read trustdb chmod 755 /etc/portage/gnupg chmod 755 /root/.gnupg find /etc/portage/gnupg -type f -exec chmod 666 {} + FINGERPRINT=\$(gpg --with-colons --show-keys /tmp/signing.key | awk -F: '/^pub/ { print \$5 }' | head -n1) echo \"\$FINGERPRINT:6:\" | gpg --homedir /etc/portage/gnupg --import-ownertrust gpg --homedir /etc/portage/gnupg --check-trustdb if [[ ! -d /var/db/repos/gentoo/profiles ]]; then emerge-webrsync -q fi emerge -1vn --usepkg --buildpkg dev-vcs/git app-eselect/eselect-repository eselect profile set '$PROFILE' " } if ! podman container exists "$CONTAINER_NAME"; then init_container else if ! podman container inspect -f '{{.State.Running}}' "$CONTAINER_NAME" | grep -q "true"; then echo "Container running" else echo "Starting existing container..." podman start "$CONTAINER_NAME" fi fi echo "Injecting current config..." podman cp "$CTX/etc/portage/" "$CONTAINER_NAME":/etc/ podman cp "$CTX/var/lib/portage/world" "$CONTAINER_NAME":/var/lib/portage/world echo "Starting Builder..." cat <<'EOF' | podman exec -i "$CONTAINER_NAME" sh -c "cat > /usr/local/bin/run_job.sh" #!/bin/bash set -e exec 9>/var/tmp/gentoo_builder.lock if ! flock -n 9; then echo "Build is already active (Lock held). Exiting." exit 1 fi source /etc/profile SYNC_MARKER="/var/db/repos/gentoo/.last_sync_marker" chown root:root /var/lib/portage/world echo "Syncing..." # if we're missing the tree, sync snapshot if [[ ! -d /var/db/repos/gentoo/profiles ]]; then echo "Tree missing, running webrsync..." emerge-webrsync -q elif [[ -f "$SYNC_MARKER" ]] && [[ -n "$(find "$SYNC_MARKER" -mtime -1 2>/dev/null)" ]]; then echo "Skipping sync: Repo synced <24h ago" else echo "Sync timer expired (or marker missing)..." emaint sync -a touch "$SYNC_MARKER" fi echo "Building world.." emerge --verbose --usepkg --buildpkg \ --update --deep --changed-use \ --with-bdeps=y --binpkg-respect-use=y --binpkg-changed-deps=y \ --keep-going @world echo "Cleaning up.." emerge --depclean emaint binhost --fix echo "[$(date)] Build Finished successfully." EOF echo "Triggering build in background..." podman exec -d "$CONTAINER_NAME" bash -c "chmod +x /usr/local/bin/run_job.sh && /usr/local/bin/run_job.sh > $LOG_FILE 2>&1" echo "Build is running in the background." echo "To view progress: podman exec -it $CONTAINER_NAME tail -f $LOG_FILE"