From ff196e37b80e46acd99b06da5dc7ec8e53c459a7 Mon Sep 17 00:00:00 2001 From: nyyu Date: Sun, 6 Apr 2025 10:40:05 +0200 Subject: [PATCH] chore: rework script build --- .util.sh | 20 +++- .woodpecker.yml | 6 +- build.sh | 240 +++++++++++++++++++++++++++++++++++------------- 3 files changed, 199 insertions(+), 67 deletions(-) diff --git a/.util.sh b/.util.sh index dc10ade..fca0c27 100644 --- a/.util.sh +++ b/.util.sh @@ -1,12 +1,23 @@ #!/bin/bash +update_repo_tags() { + local repo + repo=$(grep -oPm 1 'github\.com\/\K(\w|-)+\/(\w|-)+' .SRCINFO) + [[ -n "${repo}" ]] && update_github_tag "${repo}" + + repo=$(grep -oPm 1 'gitea\.com\/\K(\w|-)+\/(\w|-)+' .SRCINFO) + [[ -n "${repo}" ]] && update_gitea_tag "${repo}" +} + update_github_tag() { - local ver=$(curl -Ls https://api.github.com/repos/"$1"/tags | jq -r '[.[] | select(.name | index("rc") | not) | select (.name | index("dev") | not) | select (.name | index("beta") | not)] | first | .name' | sed 's/^v//') + local ver + ver=$(curl -Ls https://api.github.com/repos/"$1"/tags | jq -r '[.[] | select(.name | index("rc") | not) | select (.name | index("dev") | not) | select (.name | index("beta") | not)] | first | .name' | sed 's/^v//') echo "${ver}" | grep -Eq "^(\w|\+|\.)+$" && sed -i "s/pkgver=.*/pkgver=${ver}/" PKGBUILD } update_gitea_tag() { - local ver=$(curl -Ls https://gitea.com/api/v1/repos/"$1"/releases/latest | jq -r '.name' | sed 's/^v//') + local ver + ver=$(curl -Ls https://gitea.com/api/v1/repos/"$1"/releases/latest | jq -r '.name' | sed 's/^v//') echo "${ver}" | grep -Eq "^(\w|\+|\.)+$" && sed -i "s/pkgver=.*/pkgver=${ver}/" PKGBUILD } @@ -17,9 +28,10 @@ update_pkg() { if updpkgsums; then makepkg --printsrcinfo >.SRCINFO - local ver=$(grep 'pkgver' .SRCINFO | cut -d'=' -f2 | tr -d ' ') + local ver + ver=$(grep 'pkgver' .SRCINFO | cut -d'=' -f2 | tr -d ' ') git add .SRCINFO PKGBUILD - if git commit -m "$(basename $(pwd)): update to ${ver} [CI SKIP]"; then + if git commit -m "$(basename "$(pwd)"): update to ${ver} [CI SKIP]"; then git push --set-upstream origin "${CI_COMMIT_BRANCH}" fi fi diff --git a/.woodpecker.yml b/.woodpecker.yml index 508c4a3..f3109cb 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -24,7 +24,7 @@ steps: - mkdir /build - chown -R build:build . /build - sudo -u build --preserve-env=PGP_KEY,PGP_PWD,PGP_ID sh -c 'mkdir ~/.gnupg && echo -e "default-cache-ttl 3600\nallow-preset-passphrase" > ~/.gnupg/gpg-agent.conf && echo "$PGP_KEY" | gpg --import --no-tty --batch --yes && echo "$PGP_PWD" | /usr/lib/gnupg/gpg-preset-passphrase --preset $PGP_ID' - - sudo -u build --preserve-env=CI_REPO_CLONE_URL,CI_COMMIT_BRANCH,CI_PREV_COMMIT_SHA,GIT_USER,GIT_TOKEN sh -c './build.sh' + - sudo -u build --preserve-env=CI_REPO_CLONE_URL,CI_COMMIT_BRANCH,CI_PREV_COMMIT_SHA,GIT_USER,GIT_TOKEN,BUILD_DIR,REPO_DIR,GIT_USER_NAME,GIT_USER_EMAIL sh -c './build.sh' environment: PGP_ID: from_secret: pgp_id @@ -36,6 +36,10 @@ steps: from_secret: git_user GIT_TOKEN: from_secret: git_token + BUILD_DIR: /build + REPO_DIR: /repo + GIT_USER_NAME: drone + GIT_USER_EMAIL: drone@nyyu.dev when: branch: master event: [ push, cron, tag, manual ] diff --git a/build.sh b/build.sh index 9308d94..cd86d6e 100755 --- a/build.sh +++ b/build.sh @@ -1,93 +1,209 @@ #!/bin/bash -# shellcheck disable=SC3044,SC3009,SC2312 + +set -euo pipefail +trap 'echo "Error on line $LINENO"' ERR . .util.sh -export BUILDDIR=/build + +# Constants +readonly REQUIRED_ENV_VARS=(BUILD_DIR REPO_DIR GIT_USER_EMAIL GIT_USER_NAME CI_REPO_CLONE_URL GIT_USER GIT_TOKEN) + +log() { + local level=$1 + shift + echo "[$(date '+%Y-%m-%d %H:%M:%S')] ${level}: $*" +} + +validate_env_vars() { + local missing_vars=() + for var in "${REQUIRED_ENV_VARS[@]}"; do + if [[ -z "${!var:-}" ]]; then + missing_vars+=("$var") + fi + done + + if [[ ${#missing_vars[@]} -gt 0 ]]; then + log "ERROR" "Missing required environment variables: ${missing_vars[*]}" + exit 1 + fi +} + +cleanup_build_dir() { + if [[ -d "${BUILD_DIR}" ]]; then + log "INFO" "Cleaning build directory" + rm -rf "${BUILD_DIR:?}"/* + else + log "INFO" "Creating build directory" + mkdir -p "${BUILD_DIR}" + fi +} build() { - local upd=$1 + local upd=${1:-false} + local retries=3 + cleanup_build_dir - rm -rf /build/* - - if grep -c 'git+' PKGBUILD >/dev/null && ! grep -c '#tag=' PKGBUILD >/dev/null; then - makepkg --noprepare --nodeps --nobuild --skippgpcheck --noconfirm - makepkg --printsrcinfo >.SRCINFO - if [[ "${upd}" = true ]]; then - update_pkg + if grep -q 'git+' PKGBUILD && ! grep -q '#tag=' PKGBUILD; then + if ! makepkg --noprepare --nodeps --nobuild --skippgpcheck --noconfirm; then + log "ERROR" "makepkg failed during preparation" + return 1 fi + makepkg --printsrcinfo >.SRCINFO + [[ "${upd}" == true ]] && update_pkg fi + + local name ver rel epoch name=$(grep -m1 'pkgname' .SRCINFO | cut -d'=' -f2 | tr -d ' ') ver=$(grep -m1 'pkgver' .SRCINFO | cut -d'=' -f2 | tr -d ' ') rel=$(grep -m1 'pkgrel' .SRCINFO | cut -d'=' -f2 | tr -d ' ') epoch=$(grep -m1 'epoch' .SRCINFO | cut -d'=' -f2 | tr -d ' ') - if [[ -n "${epoch}" ]]; then - epoch=${epoch}: + [[ -n "${epoch}" ]] && epoch=${epoch}: + + # Check if package exists in official repos + if pacman -Si "${name}" 2>/dev/null | grep -v nyyu | grep -q -E '^Repository'; then + log "WARN" "Found ${name} in arch repo" fi - if pacman -Si "${name}" 2>/dev/null | grep -v nyyu | grep -c -E '^Repository' &>/dev/null; then - echo "WARN: Found ${name} in arch repo" - fi - - if ! compgen -G "/repo/${name}-${epoch}${ver}-${rel}-*.pkg.tar.zst" >/dev/null; then - echo "Building package ${name}-${epoch}${ver}-${rel}" - if makepkg --nodeps --skippgpcheck --noconfirm --sign || makepkg -C -s --skippgpcheck --noconfirm --sign || makepkg -C -s --skippgpcheck --nocheck --noconfirm --sign; then - for pkg in *.pkg.tar.zst; do - cp "${pkg}"{,.sig} /repo/ - repo-add -R -s /repo/nyyu.db.tar.zst /repo/"${pkg}" - done - sudo pacman -Syu --noconfirm - fi + # Build package if it doesn't exist or needs updating + if ! compgen -G "${REPO_DIR}/${name}-${epoch}${ver}-${rel}-*.pkg.tar.zst" >/dev/null; then + log "INFO" "Building package ${name}-${epoch}${ver}-${rel}" + + while ((retries > 0)); do + if makepkg --nodeps --skippgpcheck --noconfirm --sign || \ + makepkg -C -s --skippgpcheck --noconfirm --sign || \ + makepkg -C -s --skippgpcheck --nocheck --noconfirm --sign; then + + # Copy and add to repo + for pkg in *.pkg.tar.zst; do + if [[ -f "${pkg}" ]]; then + cp "${pkg}"{,.sig} "${REPO_DIR}/" + repo-add -R -s "${REPO_DIR}/nyyu.db.tar.zst" "${REPO_DIR}/${pkg}" + fi + done + + if ! sudo pacman -Syu --noconfirm; then + log "WARN" "Failed to update system packages" + fi + return 0 + fi + + ((retries--)) + log "WARN" "Build failed, $retries retries remaining" + sleep 5 + done + + log "ERROR" "Failed to build package ${name}-${epoch}${ver}-${rel} after all retries" + return 1 fi } -git config --global user.email "drone@nyyu.dev" -git config --global user.name "drone" -git config --global init.defaultBranch master -git remote set-url origin "${CI_REPO_CLONE_URL}" -# shellcheck disable=SC2016 -git config credential.helper '!f() { sleep 1; echo "username=${GIT_USER}"; echo "password=${GIT_TOKEN}"; }; f' +process_directory() { + local dir=$1 + cd "${dir}" || { log "ERROR" "Failed to enter directory ${dir}"; return 1; } -for d in */; do - cd "${d}" || continue if [[ -f PKGBUILD ]]; then - echo "--> ${d}" + log "INFO" "Processing ${dir}" if [[ -f update.sh ]]; then + chmod +x update.sh ./update.sh fi - if ! grep -c 'pkgver()' PKGBUILD >/dev/null; then - repo=$(grep -oPm 1 'github\.com\/\K(\w|-)+\/(\w|-)+' .SRCINFO) - if [[ -n "${repo}" ]]; then - update_github_tag "${repo}" - fi - repo=$(grep -oPm 1 'gitea\.com\/\K(\w|-)+\/(\w|-)+' .SRCINFO) - if [[ -n "${repo}" ]]; then - update_gitea_tag "${repo}" - fi + if ! grep -q 'pkgver()' PKGBUILD; then + update_repo_tags fi update_pkg build true fi cd .. -done +} -while read -r p; do - git clone https://aur.archlinux.org/"${p}".git --depth 1 || echo "ERR: Package ${p} not found in AUR" - cd "${p}" || continue - build false - cd .. -done /dev/null; then + last_commit=${CI_PREV_COMMIT_SHA} + else + last_commit=$(git --no-pager log --oneline | grep -v 'CI SKIP' | cut -d' ' -f1 | sed -n '5p') || { + log "ERROR" "Failed to determine last commit" + return 1 + } + fi + + log "INFO" "Finding removed packages from ${last_commit}" + + mapfile -t del < <( + { + git --no-pager diff "${last_commit}"..HEAD aur.txt | tail -n +4 | grep -E '^-' | cut -c2- + git --no-pager diff --name-status "${last_commit}"..HEAD | grep -Po 'D\s+(\K.*)(?=/PKGBUILD)' + } | sort -u + ) + + if [[ ${#del[@]} -gt 0 ]]; then + for pkg in "${del[@]}"; do + log "INFO" "Removing package ${pkg}" + if ! repo-remove -s "${REPO_DIR}/nyyu.db.tar.zst" "${pkg}"; then + log "WARN" "Failed to remove ${pkg} from repo" + fi + if ! rm -vf "${REPO_DIR}/${pkg}"*; then + log "WARN" "No files found for ${pkg} in ${REPO_DIR}/" + fi + done + else + log "INFO" "No packages to remove" + fi +} + +setup_git() { + git config --global user.email "${GIT_USER_EMAIL}" + git config --global user.name "${GIT_USER_NAME}" + git config --global init.defaultBranch master + git remote set-url origin "${CI_REPO_CLONE_URL}" + # shellcheck disable=SC2016 + git config credential.helper '!f() { sleep 1; echo "username=${GIT_USER}"; echo "password=${GIT_TOKEN}"; }; f' +} + +process_aur_packages() { + if [[ ! -f aur.txt ]]; then + log "ERROR" "aur.txt not found" + exit 1 + fi + + while IFS= read -r pkg; do + [[ -z "$pkg" ]] && continue + + if ! git clone https://aur.archlinux.org/"${pkg}".git --depth 1; then + log "ERROR" "Failed to clone repository for package ${pkg}" + continue + fi + + (cd "${pkg}" && build false) || log "ERROR" "Failed to build ${pkg}" + done < aur.txt +} + +main() { + validate_env_vars + setup_git + + # Process local directories sequentially + mapfile -t dirs < <(find . -maxdepth 1 -type d ! -name ".*" -printf "%f\n") + process_directories "${dirs[@]}" || log "WARN" "Some directory processing failed" + + process_aur_packages + find_and_remove_deleted_packages +} + +main "$@"