commit 5a87cf89954fcc1a052e2a0629529671afb55c2f Author: Brodino Date: Mon Apr 27 00:24:14 2026 +0200 Initial commit diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5941cb9 --- /dev/null +++ b/.env.example @@ -0,0 +1,20 @@ +# GitHub credentials +# Personal access token with 'repo' and 'write:packages' scopes +GITHUB_TOKEN=your_github_token_here + +# GitHub repository in the form owner/repo +GITHUB_REPO=Brodino96/webkit2gtk-automator + +# Path to the SSH private key registered on your AUR account +# The key must NOT have a passphrase (or use ssh-agent) +AUR_SSH_KEY_PATH=/run/secrets/aur_id_rsa + +# Name of the AUR binary package to publish to +AUR_PACKAGE_NAME=webkit2gtk-bin + +# AUR maintainer info (used in the generated PKGBUILD) +AUR_MAINTAINER_NAME=Your Name +AUR_MAINTAINER_EMAIL=your@email.com + +# How often to poll the AUR for updates, in seconds (default: 3600 = 1 hour) +POLL_INTERVAL_SECONDS=3600 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae8c081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Secrets +.env + +# Build artifacts +state/artifacts/ +state/build.log +state/cron.log + +# AUR SSH key (if stored locally) +*.pem +*.key +id_rsa +id_ed25519 + +# Docker +.docker/ + +# Misc +*.tmp +*.swp diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..43a083b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,108 @@ +FROM archlinux:latest + +# System update & base tools +RUN pacman -Syu --noconfirm && \ + pacman -S --noconfirm --needed \ + base-devel \ + git \ + sudo \ + curl \ + jq \ + openssh \ + github-cli \ + # webkit2gtk makedepends + clang \ + cmake \ + gi-docgen \ + glib2-devel \ + gobject-introspection \ + gperf \ + gst-plugins-bad \ + lld \ + ninja \ + python \ + ruby \ + ruby-stdlib \ + systemd \ + unifdef \ + wayland-protocols \ + # webkit2gtk runtime depends + at-spi2-core \ + atk \ + bubblewrap \ + cairo \ + enchant \ + expat \ + fontconfig \ + freetype2 \ + gdk-pixbuf2 \ + glib2 \ + glibc \ + gst-plugins-bad-libs \ + gst-plugins-base-libs \ + gstreamer \ + gtk3 \ + harfbuzz \ + harfbuzz-icu \ + hyphen \ + icu \ + lcms2 \ + libatomic \ + libavif \ + libdrm \ + libegl \ + libepoxy \ + libgcrypt \ + libgl \ + libjpeg-turbo \ + libjxl \ + libmanette \ + libpng \ + libseccomp \ + libsecret \ + libsoup \ + libsystemd \ + libtasn1 \ + libwebp \ + libx11 \ + libxml2 \ + libxslt \ + mesa \ + openjpeg2 \ + pango \ + sqlite \ + ttf-dejavu \ + wayland \ + woff2 \ + xdg-dbus-proxy \ + zlib \ + && pacman -Scc --noconfirm + +# Import WebKitGTK PGP signing keys +RUN gpg --keyserver keyserver.ubuntu.com --recv-keys \ + 5AA3BC334FD7E3369E7C77B291C559DBE4C9123B \ + 013A0127AC9C65B34FFA62526C1009B693975393 || \ + gpg --keyserver hkps://keys.openpgp.org --recv-keys \ + 5AA3BC334FD7E3369E7C77B291C559DBE4C9123B \ + 013A0127AC9C65B34FFA62526C1009B693975393 + +# Non-root build user (makepkg refuses to run as root) +RUN useradd -m -G wheel builduser && \ + echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers + +# SSH config for AUR +RUN mkdir -p /home/builduser/.ssh && \ + printf 'Host aur.archlinux.org\n User aur\n IdentityFile /home/builduser/.ssh/aur_id_rsa\n StrictHostKeyChecking no\n' \ + > /home/builduser/.ssh/config && \ + chown -R builduser:builduser /home/builduser/.ssh && \ + chmod 700 /home/builduser/.ssh && \ + chmod 600 /home/builduser/.ssh/config + +# Allow git to operate on the mounted workspace +RUN git config --system --add safe.directory '*' + +WORKDIR /workspace + +# The entrypoint runs as root, sets up the SSH key, then drops to builduser +# for the polling loop. +ENTRYPOINT ["/workspace/scripts/entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..61c1bd9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +services: + builder: + build: + context: . + dockerfile: Dockerfile + image: webkit2gtk-builder + container_name: webkit2gtk-builder + restart: unless-stopped + env_file: + - .env + volumes: + # Entire project mounted so the container can read/write state, artifacts, + # and the webkit2gtk / webkit2gtk-bin git repos. + - .:/workspace + # AUR SSH private key (path set in .env via AUR_SSH_KEY_PATH) + - ${AUR_SSH_KEY_PATH}:/run/secrets/aur_id_rsa:ro + # No ports needed – this is a pure background worker. + # Logs are available via: docker compose logs -f diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..e6f1d8c --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# build.sh +# Runs INSIDE the Docker container as builduser. +# Builds webkit2gtk from the AUR PKGBUILD and copies the resulting +# .pkg.tar.zst packages to /workspace/state/artifacts/. + +set -euo pipefail + +WORKSPACE=/workspace +SRC_DIR="${WORKSPACE}/webkit2gtk" +ARTIFACTS_DIR="${WORKSPACE}/state/artifacts" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [build] $*" +} + +# Sanity checks +if [[ ! -f "${SRC_DIR}/PKGBUILD" ]]; then + log "ERROR: PKGBUILD not found at ${SRC_DIR}/PKGBUILD" + exit 1 +fi + +mkdir -p "${ARTIFACTS_DIR}" + +# Clean any leftover build artifacts from a previous run +log "Cleaning previous build artifacts in ${SRC_DIR}" +# makepkg leaves behind src/, pkg/ and the .pkg.tar.zst files +cd "${SRC_DIR}" +rm -rf src/ pkg/ +find . -maxdepth 1 -name '*.pkg.tar.zst' -delete +find . -maxdepth 1 -name '*.pkg.tar.zst.sig' -delete + +# Build +log "Running makepkg in ${SRC_DIR}" +# --syncdeps : install missing makedepends automatically +# --noconfirm : do not ask for confirmations +# --clean : clean up src/ and pkg/ after a successful build +# --log : write build log to makepkg-.log +makepkg \ + --syncdeps \ + --noconfirm \ + --log + +# Collect artifacts +log "Collecting built packages" +packages=() +while IFS= read -r -d '' pkg; do + packages+=("${pkg}") +done < <(find "${SRC_DIR}" -maxdepth 1 -name '*.pkg.tar.zst' -print0) + +if [[ ${#packages[@]} -eq 0 ]]; then + log "ERROR: No .pkg.tar.zst files found after build" + exit 1 +fi + +for pkg in "${packages[@]}"; do + log "Copying $(basename "${pkg}") to ${ARTIFACTS_DIR}/" + cp "${pkg}" "${ARTIFACTS_DIR}/" +done + +log "Build complete, artifacts:" +ls -lh "${ARTIFACTS_DIR}"/*.pkg.tar.zst diff --git a/scripts/check-update.sh b/scripts/check-update.sh new file mode 100755 index 0000000..0667a5c --- /dev/null +++ b/scripts/check-update.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# check-update.sh +# Polls the AUR RPC API for the latest webkit2gtk version. +# If a newer version is detected, runs build.sh then publish.sh directly. +# Called by entrypoint.sh on a loop — runs entirely inside the container. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" + +# Paths +STATE_DIR="${ROOT_DIR}/state" +LAST_VERSION_FILE="${STATE_DIR}/last_version" +mkdir -p "${STATE_DIR}" + +# Logging +# Output goes to stdout so docker compose logs picks it up automatically. +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [check-update] $*" +} + +# Fetch latest AUR version +AUR_API_URL="https://aur.archlinux.org/rpc/v5/info/webkit2gtk" + +log "Querying AUR for webkit2gtk" +response=$(curl -fsSL "${AUR_API_URL}") +aur_version=$(echo "${response}" | jq -r '.results[0].Version') + +if [[ -z "${aur_version}" || "${aur_version}" == "null" ]]; then + log "ERROR: Failed to parse version from AUR response: ${response}" + exit 1 +fi + +log "AUR version: ${aur_version}" + +# Compare with last built version +last_version="" +if [[ -f "${LAST_VERSION_FILE}" ]]; then + last_version=$(cat "${LAST_VERSION_FILE}") +fi + +log "Last built version: ${last_version:-}" + +if [[ "${aur_version}" == "${last_version}" ]]; then + log "Already up to date, nothing to do" + exit 0 +fi + +log "New version detected: ${aur_version} (was: ${last_version:-}), starting build" + +# Update the webkit2gtk AUR clone +WEBKIT2GTK_DIR="${ROOT_DIR}/webkit2gtk" +if [[ -d "${WEBKIT2GTK_DIR}/.git" ]]; then + log "Pulling latest PKGBUILD from AUR" + git -C "${WEBKIT2GTK_DIR}" pull --ff-only +else + log "Cloning webkit2gtk from AUR" + git clone https://aur.archlinux.org/webkit2gtk.git "${WEBKIT2GTK_DIR}" +fi + +# Build +log "Running build" +if "${SCRIPT_DIR}/build.sh"; then + log "Build succeeded" +else + log "ERROR: Build failed, aborting" + exit 1 +fi + +# Publish +log "Running publish" +if "${SCRIPT_DIR}/publish.sh"; then + log "Publish succeeded" +else + log "ERROR: Publish failed" + exit 1 +fi + +# Record new version +echo "${aur_version}" > "${LAST_VERSION_FILE}" +log "Updated last_version to ${aur_version}, done" diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh new file mode 100755 index 0000000..60ab805 --- /dev/null +++ b/scripts/entrypoint.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# entrypoint.sh +# Container entry point. Runs as root, sets up the SSH key and git identity +# for builduser, then drops to builduser and starts the polling loop. +# +# The loop runs check-update.sh every POLL_INTERVAL_SECONDS (default: 3600). +# All output goes to stdout/stderr so 'docker compose logs -f' works naturally. + +set -euo pipefail + +POLL_INTERVAL_SECONDS="${POLL_INTERVAL_SECONDS:-3600}" + +# Set up AUR SSH key +SSH_DIR=/home/builduser/.ssh +KEY_SRC=/run/secrets/aur_id_rsa +KEY_DST="${SSH_DIR}/aur_id_rsa" + +if [[ -f "${KEY_SRC}" ]]; then + cp "${KEY_SRC}" "${KEY_DST}" + chown builduser:builduser "${KEY_DST}" + chmod 600 "${KEY_DST}" + echo "[entrypoint] AUR SSH key installed" +else + echo "[entrypoint] WARNING: AUR SSH key not found at ${KEY_SRC}, publishing to AUR will fail" >&2 +fi + +# Set git identity for builduser +sudo -u builduser git config --global user.name "${AUR_MAINTAINER_NAME:-webkit2gtk-automator}" +sudo -u builduser git config --global user.email "${AUR_MAINTAINER_EMAIL:-noreply@localhost}" + +# Drop to builduser and start the polling loop +echo "[entrypoint] Starting polling loop, interval: ${POLL_INTERVAL_SECONDS}s" +exec sudo -u builduser bash -c ' + set -euo pipefail + POLL_INTERVAL_SECONDS="'"${POLL_INTERVAL_SECONDS}"'" + while true; do + /workspace/scripts/check-update.sh + echo "[entrypoint] Sleeping for ${POLL_INTERVAL_SECONDS}s" + sleep "${POLL_INTERVAL_SECONDS}" + done +' diff --git a/scripts/publish.sh b/scripts/publish.sh new file mode 100755 index 0000000..340d17d --- /dev/null +++ b/scripts/publish.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash +# publish.sh +# Runs INSIDE the Docker container as builduser. +# +# Steps: +# 1. Find the built webkit2gtk .pkg.tar.zst in state/artifacts/ +# 2. Upload it to a GitHub Release (creates the release if needed) +# 3. Update webkit2gtk-bin/PKGBUILD with the new version, URL and sha256sum +# 4. Regenerate webkit2gtk-bin/.SRCINFO +# 5. Commit and push webkit2gtk-bin/ to the AUR + +set -euo pipefail + +WORKSPACE=/workspace +ARTIFACTS_DIR="${WORKSPACE}/state/artifacts" +BIN_PKG_DIR="${WORKSPACE}/webkit2gtk-bin" +SRC_PKGBUILD="${WORKSPACE}/webkit2gtk/PKGBUILD" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [publish] $*" +} + +die() { + log "ERROR: $*" >&2 + exit 1 +} + +# Validate required env vars +: "${GITHUB_TOKEN:?GITHUB_TOKEN is not set}" +: "${GITHUB_REPO:?GITHUB_REPO is not set}" +: "${AUR_PACKAGE_NAME:?AUR_PACKAGE_NAME is not set}" +: "${AUR_MAINTAINER_NAME:?AUR_MAINTAINER_NAME is not set}" +: "${AUR_MAINTAINER_EMAIL:?AUR_MAINTAINER_EMAIL is not set}" + +# Authenticate gh CLI +echo "${GITHUB_TOKEN}" | gh auth login --with-token + +# Find the main webkit2gtk package (not -docs) +log "Looking for built package in ${ARTIFACTS_DIR}" +# We want webkit2gtk---x86_64.pkg.tar.zst, NOT webkit2gtk-docs-* +pkg_file=$(find "${ARTIFACTS_DIR}" -maxdepth 1 \ + -name 'webkit2gtk-*.pkg.tar.zst' \ + ! -name 'webkit2gtk-docs-*' \ + -print | sort -V | tail -n1) + +[[ -n "${pkg_file}" ]] || die "No webkit2gtk .pkg.tar.zst found in ${ARTIFACTS_DIR}" +log "Found package: ${pkg_file}" +# Derive version from the built PKGBUILD +pkgver=$(bash -c "source ${SRC_PKGBUILD}; echo \${pkgver}") +pkgrel=$(bash -c "source ${SRC_PKGBUILD}; echo \${pkgrel}") +full_version="${pkgver}-${pkgrel}" +log "Package version: ${full_version}" +# Compute sha256sum of the artifact +sha256=$(sha256sum "${pkg_file}" | awk '{print $1}') +log "sha256sum: ${sha256}" +pkg_filename=$(basename "${pkg_file}") + +# Upload to GitHub Releases +release_tag="v${full_version}" +release_title="webkit2gtk ${full_version}" + +log "Creating/updating GitHub release ${release_tag}" + +# Create the release if it doesn't exist; ignore error if it already does +gh release create "${release_tag}" \ + --repo "${GITHUB_REPO}" \ + --title "${release_title}" \ + --notes "Automated build of webkit2gtk ${full_version}" \ + 2>/dev/null || log "Release ${release_tag} already exists, proceeding to upload asset" + +# Upload the package (--clobber overwrites an existing asset with the same name) +log "Uploading ${pkg_filename} to release ${release_tag}" +gh release upload "${release_tag}" \ + --repo "${GITHUB_REPO}" \ + --clobber \ + "${pkg_file}" + +# Build the public download URL +download_url="https://github.com/${GITHUB_REPO}/releases/download/${release_tag}/${pkg_filename}" +log "Download URL: ${download_url}" +# Ensure webkit2gtk-bin AUR clone exists +AUR_REMOTE="ssh://aur@aur.archlinux.org/${AUR_PACKAGE_NAME}.git" + +if [[ ! -d "${BIN_PKG_DIR}/.git" ]]; then + log "Cloning ${AUR_PACKAGE_NAME} from AUR" + git clone "${AUR_REMOTE}" "${BIN_PKG_DIR}" +else + log "Pulling latest ${AUR_PACKAGE_NAME} from AUR" + git -C "${BIN_PKG_DIR}" pull --ff-only +fi + +# Generate PKGBUILD +log "Generating PKGBUILD for ${AUR_PACKAGE_NAME}" + +# Read the full depends array from the source PKGBUILD to keep them in sync +depends_block=$(bash -c " + source ${SRC_PKGBUILD} + for d in \"\${depends[@]}\"; do printf ' %s\n' \"\$d\"; done +") +provides_block=$(bash -c " + source ${SRC_PKGBUILD} + # package_webkit2gtk() sets provides; source the function then call it in a subshell + # Simpler: hardcode from .SRCINFO since provides is stable + echo ' libjavascriptcoregtk-4.0.so' + echo ' libwebkit2gtk-4.0.so' + echo ' webkit2gtk' +") + +cat > "${BIN_PKG_DIR}/PKGBUILD" < +# Automated binary repackaging of webkit2gtk built from AUR sources. +# Source: https://github.com/${GITHUB_REPO} + +pkgname=${AUR_PACKAGE_NAME} +pkgver=${pkgver} +pkgrel=${pkgrel} +pkgdesc="Web content engine for GTK (prebuilt binary)" +url="https://webkitgtk.org" +arch=(x86_64) +license=( + 'AFL-2.0 OR GPL-2.0-or-later' + Apache-2.0 + 'Apache-2.0 WITH LLVM-exception' + BSD-2-Clause + BSD-2-Clause-Views + BSD-3-Clause + BSD-Source-Code + BSL-1.0 + bzip2-1.0.6 + GPL-2.0-only + 'GPL-3.0-only WITH Autoconf-exception-3.0' + 'GPL-3.0-or-later WITH Bison-exception-2.2' + ICU + ISC + LGPL-2.1-only + LGPL-2.1-or-later + MIT + MPL-1.1 + MPL-2.0 + NCSA + 'NCSA OR MIT' + OFL-1.1 + SunPro + Unicode-TOU +) +depends=( + at-spi2-core + atk + bubblewrap + cairo + enchant + expat + fontconfig + freetype2 + gdk-pixbuf2 + glib2 + glibc + gst-plugins-bad-libs + gst-plugins-base-libs + gstreamer + gtk3 + harfbuzz + harfbuzz-icu + hyphen + icu + lcms2 + libatomic + libavif + libdrm + libegl + libepoxy + libgcc + libgcrypt + libgl + libgles + libjpeg-turbo + libjxl + libmanette + libpng + libseccomp + libsecret + libsoup + libstdc++ + libsystemd + libtasn1 + libwebp + libx11 + libxml2 + libxslt + mesa + openjpeg2 + pango + sqlite + ttf-font + wayland + woff2 + xdg-dbus-proxy + zlib +) +provides=( + libjavascriptcoregtk-4.0.so + libwebkit2gtk-4.0.so + webkit2gtk +) +conflicts=(webkit2gtk) +source=("${pkg_filename}::${download_url}") +sha256sums=('${sha256}') + +package() { + # The .pkg.tar.zst is a pre-built Arch package. + # bsdtar extracts it; we relocate its contents into \$pkgdir. + cd "\${srcdir}" + bsdtar -xf "${pkg_filename}" -C "\${pkgdir}" + # Remove the embedded .PKGINFO and .MTREE metadata files that + # bsdtar includes – they are not part of the installed file tree. + rm -f "\${pkgdir}"/.PKGINFO "\${pkgdir}"/.MTREE "\${pkgdir}"/.BUILDINFO +} +PKGBUILD + +log "PKGBUILD generated" + +# Generate .SRCINFO +log "Generating .SRCINFO" +cd "${BIN_PKG_DIR}" +makepkg --printsrcinfo > .SRCINFO +log ".SRCINFO generated" + +# Commit and push to AUR +log "Committing changes to AUR" +git -C "${BIN_PKG_DIR}" add PKGBUILD .SRCINFO +git -C "${BIN_PKG_DIR}" commit -m "Update to ${full_version}" || { + log "Nothing to commit, package already at ${full_version}" + exit 0 +} + +log "Pushing to AUR remote (${AUR_REMOTE})" +git -C "${BIN_PKG_DIR}" push origin master + +log "Successfully published ${AUR_PACKAGE_NAME} ${full_version} to AUR" diff --git a/state/last_version b/state/last_version new file mode 100644 index 0000000..e69de29