197 lines
5.6 KiB
Bash
Executable File
197 lines
5.6 KiB
Bash
Executable File
#!/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
|
|
chmod 700 /root/.gnupg
|
|
|
|
# needed for headless signing
|
|
echo 'allow-loopback-pinentry' > /root/.gnupg/gpg-agent.conf
|
|
gpg-connect-agent reloadagent /bye
|
|
|
|
# import to root
|
|
gpg --batch --import /tmp/signing.key
|
|
gpg --list-keys --with-colons | awk -F: '/^fpr:/ { print \$10 \":6:\" }' | gpg --import-ownertrust
|
|
|
|
mkdir -p /etc/portage/gnupg
|
|
chmod 700 /etc/portage/gnupg
|
|
|
|
# import our and gentoo keys to portage
|
|
gpg --homedir /etc/portage/gnupg --batch --import /tmp/signing.key /usr/share/openpgp-keys/gentoo-release.asc
|
|
gpg --homedir /etc/portage/gnupg --list-keys --with-colons | \
|
|
awk -F: '/^fpr:/ { print \$10 \":6:\" }' | \
|
|
gpg --homedir /etc/portage/gnupg --import-ownertrust
|
|
|
|
gpg --homedir /etc/portage/gnupg --check-trustdb
|
|
|
|
chmod 700 /root/.gnupg
|
|
find /root/.gnupg -type f -exec chmod 600 {} +
|
|
|
|
chmod 755 /etc/portage/gnupg
|
|
find /etc/portage/gnupg -type f -exec chmod 644 {} +
|
|
|
|
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"
|
|
|