From 528620be31f8b94afe84bae3c8b5226fba547445 Mon Sep 17 00:00:00 2001 From: Tharre Date: Tue, 7 Dec 2021 07:44:12 +0100 Subject: [PATCH] Add github actions to automatically build packages --- .github/workflows/aur-graph | 136 ++++++++++++++++++++++++++++++++++ .github/workflows/build.sh | 32 ++++++++ .github/workflows/main.yml | 100 +++++++++++++++++++++++++ .github/workflows/pacman.conf | 57 ++++++++++++++ 4 files changed, 325 insertions(+) create mode 100755 .github/workflows/aur-graph create mode 100755 .github/workflows/build.sh create mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/pacman.conf diff --git a/.github/workflows/aur-graph b/.github/workflows/aur-graph new file mode 100755 index 0000000..c4e5beb --- /dev/null +++ b/.github/workflows/aur-graph @@ -0,0 +1,136 @@ +#!/bin/awk -f +# Taken from https://github.com/AladW/aurutils/blob/master/lib/aur-graph +# (ISC License) +# +# aur-graph - print package/dependency pairs + +# < 0 : if ver1 < ver2 +# = 0 : if ver1 == ver2 +# > 0 : if ver1 > ver2 +function get_vercmp(ver1, ver2, op) { + command = ("vercmp " ver1 " " ver2) + + if (op == "-" || ver2 == "-") { + return "true" # dependency is unversioned + } else if (op == "=") { + return (ver1 == ver2) # common case + } else if (op == "<") { + command | getline + close(command) + return ($1 < 0) + } else if (op == ">") { + command | getline + close(command) + return ($1 > 0) + } else if (op == "<=") { + command | getline + close(command) + return ($1 <= 0) + } else if (op == ">=") { + command | getline + close(command) + return ($1 >= 0) + } else { + printf("invalid operation\n") > "/dev/stderr" + exit 1 + } +} + +/pkgbase/ { + in_split_pkg = 0 + pkgbase = $3 + pkgver = "" + + # track both the pkgbases themselves and their number of deps + dep_counts[pkgbase] = 0 +} + +/^\tpkgver/ { + if (!in_split_pkg) { + pkgver = $3 + } +} + +/^\t(make|check)?depends/ { + if (!in_split_pkg) { + # POSIX array of arrays! + pkg_deps[pkgbase, ++dep_counts[pkgbase]] = $3 # versioned + } +} + +/^$/ { + in_split_pkg = 1 +} + +/pkgname/ { + pkg_map[$3] = pkgbase # node + ver_map[$3] = pkgver # weight +} + +/^\tprovides/ { + split($3, prov, "=") + + # if provider is unversioned, use pkgver + if ("2" in prov) + ver_map[prov[1]] = prov[2] + else + ver_map[prov[1]] = pkgver + + # append node + pkg_map[prov[1]] = pkgbase +} + +END { + _vercmp_exit = 0 + + for (pkgbase in dep_counts) { + # add a loop to isolated nodes (#402) + printf("%s\t%s\n", pkgbase, pkgbase) + + for (dep = 1; dep <= dep_counts[pkgbase]; dep++) { + dep_op = "-" # unversioned / no comparison + + # valid operators (important: <= before <) + split("<=|>=|<|=|>", cmp, "|") + + # split: fourth argument is gawk extension + for (i in cmp) { + split(pkg_deps[pkgbase, dep], dep_split, cmp[i]) + + if ("2" in dep_split) { + dep_op = cmp[i] + break + } + } + + if ("1" in dep_split) + dep_pkgname = dep_split[1] + else + exit 2 + + if ("2" in dep_split) + dep_pkgver = dep_split[2] + else + dep_pkgver = "-" + + # only print dependency if it was encountered before + if (dep_pkgname in pkg_map == 0) + continue + + # run vercmp with provider and versioned dependency + if (get_vercmp(ver_map[dep_pkgname], dep_pkgver, dep_op)) { + printf("%s\t%s\n", pkgbase, pkg_map[dep_pkgname]) + } else { + printf("invalid node: %s %s (required: %s%s)\n", + dep_pkgname, ver_map[dep_pkgname], dep_op, dep_pkgver) > "/dev/stderr" + close("/dev/stderr") + + # delay mismatches to loop end + _vercmp_exit = 1 + } + } + } + + if (_vercmp_exit) + exit _vercmp_exit +} diff --git a/.github/workflows/build.sh b/.github/workflows/build.sh new file mode 100755 index 0000000..1aebcb4 --- /dev/null +++ b/.github/workflows/build.sh @@ -0,0 +1,32 @@ +#!/bin/bash -e + +CHROOT=/buildchroot + +for dir in $(aur-graph */.SRCINFO | tsort | tac); do + pushd "$dir" > /dev/null + + # directory may also reference the pkgbase, in which case test if the + # first package in pkgname is up to date + remotever="$(expac -S1 "%v" "$REPO_NAME/$dir" \ + || expac -S1 "%v" "$REPO_NAME/$(source PKGBUILD; printf %s "$pkgname")" \ + || echo NONE)" + + if [ $(vercmp "$remotever" \ + $(source PKGBUILD; printf %s "${epoch:-0}:$pkgver-$pkgrel")) -lt 0 ]; then + if [ ! -d "$CHROOT" ]; then + echo "=== Creating build chroot ===" + mkdir "$CHROOT" + mkarchroot -C /etc/pacman.conf "$CHROOT/root" base-devel + fi + + echo "=== Building $dir ===" + makechrootpkg -c -u -U build -D /repository -r "$CHROOT" + + sudo -u build SRCDEST=/tmp makepkg --packagelist | while IFS="" read -r pkg + do + repo-add -s "/repository/$REPO_NAME.db.tar.gz" "$pkg" + gpg --detach-sign "$pkg" + done + fi + popd > /dev/null +done diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..4dc97e5 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,100 @@ +name: package-build + +env: + # don't use spaces newlines or similar for these, it will not work + RELEASE_NAME: repository + REPO_NAME: custom + GPGKEY: A87E7322DD5ABA13A4099927208F3CC866C53553 + +on: + push: + branches: master + +jobs: + build: + runs-on: ubuntu-latest + container: + image: archlinux:base-devel + options: --privileged + steps: + - name: Prepare environment + run: | + systemd-machine-id-setup + pacman-key --init + pacman -Syu --noconfirm git expac devtools + + cat << EOF >> /etc/makepkg.conf + GPGKEY="$GPGKEY" + PACKAGER="Github Actions <$GITHUB_SERVER_URL/$GITHUB_REPOSITORY>" + PKGDEST=/repository + EOF + + useradd -m -G wheel -s /bin/bash build + echo "%wheel ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/00_wheel + + mkdir -p /home/build/.gnupg + echo "keyserver-options auto-key-retrieve" > /home/build/.gnupg/gpg.conf + echo "keyserver hkps://keys.openpgp.org" >> /home/build/.gnupg/gpg.conf + chown build:build /home/build/.gnupg/{,gpg.conf} + + # needed because these docker images don't have proper locale support + sed -i "s/en_US de_DE/en_US/g" /usr/bin/mkarchroot + + dbus-uuidgen --ensure=/etc/machine-id + + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + + - name: Download repository database + run: | + mkdir /repository + # makepkg complains about directory permissions, even if it's only run + # with --packagelist + chown build:root /repository + cd /repository + BASE_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$RELEASE_NAME/$REPO_NAME" + curl -fL --remote-name-all "$BASE_URL"{.db.tar.gz,.files.tar.gz} \ + || repo-add "$REPO_NAME.db.tar.gz" + ln -sf "/repository/$REPO_NAME.db.tar.gz" "/repository/$REPO_NAME.db" + ln -sf "/repository/$REPO_NAME.files.tar.gz" "/repository/$REPO_NAME.files" + + mv "$GITHUB_WORKSPACE/.github/workflows/pacman.conf" /etc/pacman.conf + mv "$GITHUB_WORKSPACE"/.github/workflows/{build.sh,aur-graph} /usr/bin/ + + cat << EOF >> /etc/pacman.conf + [$REPO_NAME] + SigLevel = Required DatabaseOptional + Server = file:///repository + Server = $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/repo + EOF + + pacman -Syu --noconfirm + + - name: Import GPG Key + run: | + printf "%s" "$repo_key" | gpg --import + printf "%s" "$repo_key" | pacman-key -a - + pacman-key --lsign-key "$GPGKEY" + env: + repo_key: ${{ secrets.REPO_KEY }} + + - name: Build Arch Linux Package(s) + run: | + chown -Rh build:build $GITHUB_WORKSPACE + cd $GITHUB_WORKSPACE + build.sh + rm -f /repository/*.old{,.sig} + + # BUG: github doesn't seem to support colons (:) in the filenames, meaning + # packages with a EPOCH will fail to download as github silently replaces + # the colon with a dot. + - name: Upload package artefact(s) + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{secrets.GITHUB_TOKEN}} + tag: ${{env.RELEASE_NAME}} + file: '/repository/*' + file_glob: true + overwrite: true diff --git a/.github/workflows/pacman.conf b/.github/workflows/pacman.conf new file mode 100644 index 0000000..1db8c80 --- /dev/null +++ b/.github/workflows/pacman.conf @@ -0,0 +1,57 @@ +# +# /etc/pacman.conf +# +# See the pacman.conf(5) manpage for option and repository directives + +# +# GENERAL OPTIONS +# +[options] +# The following paths are commented out with their default values listed. +# If you wish to use different paths, uncomment and update the paths. +#RootDir = / +#DBPath = /var/lib/pacman/ +#CacheDir = /var/cache/pacman/pkg/ +#LogFile = /var/log/pacman.log +#GPGDir = /etc/pacman.d/gnupg/ +#HookDir = /etc/pacman.d/hooks/ +HoldPkg = pacman glibc +#XferCommand = /usr/bin/curl -L -C - -f -o %o %u +#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u +#CleanMethod = KeepInstalled +Architecture = auto + +# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup +#IgnorePkg = +#IgnoreGroup = + +#NoUpgrade = +#NoExtract = + +# Misc options +#UseSyslog +#Color +#TotalDownload +# We cannot check disk space from within a chroot environment +#CheckSpace +#VerbosePkgLists +NoProgressBar + +# By default, pacman accepts packages signed by keys that its local keyring +# trusts (see pacman-key and its man page), as well as unsigned packages. +SigLevel = Required DatabaseOptional +LocalFileSigLevel = Optional +#RemoteFileSigLevel = Required + +[core] +Include = /etc/pacman.d/mirrorlist + +[extra] +Include = /etc/pacman.d/mirrorlist + +#[community-testing] +#Include = /etc/pacman.d/mirrorlist + +[community] +Include = /etc/pacman.d/mirrorlist +