#!/bin/bash basedir=$(cd $(dirname $0); pwd) chroot=$basedir/chroot if [ `whoami` == 'root' ]; then echo "Must not be run as root." exit 1; fi exe() { echo "\$ $@" ; "$@" ; } create_chroot() { ( set -e if [ ! -d $chroot ]; then echo "## Creating arch chroot ..." exe mkdir $chroot exe mkarchroot $chroot/root base-devel # install cower: gpg --recv-keys --keyserver hkp://pgp.mit.edu 1EB2638FF56C0C53 TMP_BUILD=`mktemp -d` exe cd $TMP_BUILD curl https://aur.archlinux.org/cgit/aur.git/snapshot/cower.tar.gz | tar xz exe cd cower exe makechrootpkg -r $chroot -l root -- -i exe rm -rf $TMP_BUILD echo "## Root chroot build complete." fi ) } install_system_deps() { ( set -e pkg_dep() { if !(pacman -Q $1 > /dev/null 2>&1); then echo "Installing $1..." exe sudo pacman -S --noconfirm $1 fi } pkg_dep devtools pkg_dep git ) } package_build() { # Build a package in a container. $1=container $2=package # PKGBUILD must already exist in src/ # If package has dependencies we also maintain in src/, recursively build those first. ( set -e if [ "$#" -ne 2 ]; then echo "package_build takes two args: repo_name and package_name" return 1 fi repo_name=$1 package_name=$2 setup pkgdir=$basedir/src/$package_name if [ ! -d $pkgdir ]; then echo "Package $package_name not found in $pkgdir" echo "Try running: package_add $package_name" return 1 fi if [ ! -f $pkgdir/PKGBUILD ]; then echo "Cannot find PKGBUILD in $pkgdir" return 1 fi if (arch-nspawn $chroot/$repo_name pacman -Q $package_name > /dev/null 2>&1); then echo "Package $package_name already built" return fi # Find and build dependencies: find_deps $package_name | while read dep; do # Build the dep if we haven't already yet: if !(arch-nspawn $chroot/$repo_name pacman -Q $dep > /dev/null 2>&1); then package_build $repo_name $dep fi done # Build package: cd $pkgdir rm -f *.pkg.tar.xz mkdir -p $basedir/$repo_name exe makechrootpkg -r $chroot -l $repo_name -- -i exe mv *.pkg.tar.xz $basedir/$repo_name ) } sign_packages() { if [ "$#" -lt 1 ]; then echo "sign_packages requires specifying the list of packages to sign" return 1 fi ( set -e cd $(dirname $1) for pkg in "$@"; do gpg --detach-sign --use-agent $pkg done ) } find_deps() { # Inspect package srcinfo and pull out the dependencies that we maintain in src ( set -e setup cat $basedir/src/$1/.SRCINFO | sed -nr 's/^\W*depends = ([-a-zA-Z0-9]+).*$/\1/p' | while read dep; do if [ -d $basedir/src/$dep ]; then echo $dep fi done ) } add() { # Add packages and their AUR dependencies to src ( set -e if [ "$#" -lt 1 ]; then echo "Must specify package(s) to add" return 1 fi setup if [ ! -d $basedir/src ]; then mkdir $basedir/src fi for pkg in "$@"; do arch-nspawn $chroot/root --bind=$basedir/src:/src cower -q -t /src -d -d $pkg done sudo chown $USER -R $basedir/src echo "## All requested packages added" ) } update() { # Update a package and it's dependencies from the AUR ( set -e if [ ! -d $basedir/src/$1 ]; then echo "No package called $1 found in src" return 1 fi for pkg in "$@"; do check_in_git() { ( cd $basedir if (! git ls-files $1 --error-unmatch >/dev/null 2>&1); then echo "$1 is not under git control yet. Add and commit it before updating." return 1 fi ) } check_in_git $basedir/src check_in_git $basedir/src/$pkg find_deps $pkg | while read dep; do check_in_git $basedir/src/$dep done # Check if package has uncommited changes if [ $(git -C $basedir diff HEAD $basedir/src/$pkg | wc -l) -gt 0 ]; then echo "Package $pkg has uncommited changes. Commit or discard those changes first." return 1 fi # Use a temporary dir to download all PKGBUILDS atomically [ -z "$tmp_dl" ] && tmp_dl=`mktemp -d` cd $tmp_dl arch-nspawn $chroot/root --bind=$tmp_dl:/src cower -q -t /src -d -d $pkg >/dev/null 2>&1 cp -a * $basedir/src done git -C $basedir diff --name-status $basedir/src/ ) } list() { if [ "$#" -ne 1 ]; then echo "Must specify repository name to list" return 1 fi setup arch-nspawn $chroot/$1 pacman -Qm } setup() { mkdir -p $basedir/src install_system_deps create_chroot } clean() { ( set -e if [ "$#" -lt 1 ]; then echo "Must specify repository names to clean" return 1 fi for repo in "$@"; do # Clean repository and chroot if [ -d $basedir/chroot/$repo ]; then exe sudo rm -rf $basedir/chroot/$repo $basedir/chroot/$repo.lock fi if [ -d $basedir/$repo ]; then exe rm -rf $basedir/$repo fi done ) } build() { ( set -e if [ "$#" -lt 1 ]; then echo "Must specify repository name to build (and optional package list to include)" return 1 fi setup repo_name=$1 mkdir -p $basedir/$repo_name shift if [ "$#" -gt 0 ]; then # Build only requested packages for pkg in "$@"; do package_build $repo_name $pkg done echo "## All requested packages built" else # Build all packages: cd $basedir/src find -type d | sed 's/\.\///' | tail -n +2 | while read pkg; do package_build $repo_name $pkg done echo "## All packages built" fi echo "## Updating repository database" cd $basedir/$repo_name if [ `ls *.pkg.tar.xz 2> /dev/null | wc -l` -lt 1 ]; then echo "No packages found in $basedir/$repo_name" return 1; fi sign_packages *.pkg.tar.xz repo-add $repo_name.db.tar.gz *.pkg.tar.xz sign_packages $repo_name.db ) } if [ "$#" -gt 0 ]; then $* else echo "Must specify a command, eg: add, build, list, clean" exit 1 fi