#!/bin/bash set -e # ch build ... build the current package for multiple chroots # ch build-single [ remove all working copies of this chroot # ch clean-single remove only this specific working copy # ch cbuild ... clean-single then build # ch install ... # install the package files in the chroot # ch kill remove a chroot (including master chroot) # ch kill all remove all chroots (including master chroot) # ch update ... update a chroot # ch update update all chroots # ch list lists all existing master chroots # ch shell [command ...] # spawn a shell/run command in a chroot # ch shell-bind [command ...] # spawn a shell/run command in a chroot and bind $PWD from the host to /pwd in the chroot # ch rshell [command ...] # spawn a shell/run command in the master chroot # ch repack ... repack (makepkg -R) # IDs work like this: # 64 = 64bit extra # 64t = 64bit testing # 64ml = 64bit multilib # 64mlt = 64bit multilib testing # # 64+foo = 64 extra, but different working copy # functions for building chroots CHROOTS="/mnt/chroots/arch" shopt -s nullglob umask 022 if [[ ! -d "$CHROOTS" ]]; then echo "chroot base directory '$CHROOTS' does not exist or is not readable" echo "directory permissions are:" namei -l "$CHROOTS" return 1 fi # Always build official packages reproducibly if [[ ! -v SOURCE_DATE_EPOCH ]]; then export SOURCE_DATE_EPOCH=$(date +%s) fi __genchroot() { sudo btrfs subvolume snapshot "$chrootdir/root" "$copydir" } __chrootalias_resolve() { chroot="" chroot_arch="" arg_arch=${1%%+*} arg_copy="$USER+$1" arg_copy=${arg_copy//+/-} case $arg_arch in 32*) chroot_arch=32 case $arg_arch in 32) chroot=extra-i686;; 32t) chroot=testing-i686;; 32s) chroot=staging-i686;; esac ;; 64*) chroot_arch=64; case $arg_arch in 64) chroot=extra-x86_64;; 64t) chroot=testing-x86_64;; 64s) chroot=staging-x86_64;; 64ml) chroot=multilib-x86_64;; 64mlt) chroot=multilib-testing-x86_64;; 64mls) chroot=multilib-staging-x86_64;; esac ;; *) chroot=$arg_arch case $arg_arch in *-i686) chroot_arch=32;; *-x86_64|multilib*) chroot_arch=64;; esac esac if [[ -z $chroot || -z $chroot_arch ]]; then echo "failed to determine chroot for \"$arg_arch\"" return 1 fi chrootdir="$CHROOTS/$chroot" copydir="$chrootdir/$arg_copy" } __chrootalias_resolve_create() { __chrootalias_resolve "$1" local -a packages=(base-devel) local chroot_repo=${chroot%-*} if [[ $chroot = multilib* ]]; then packages+=(multilib-devel) fi local arch case "$chroot_arch" in 32) arch=i686;; 64) arch=x86_64;; esac # create chroot if necessary if [[ ! -d "$chrootdir/root" ]]; then echo "chroot not found, creating..." # from archbuild (devtools) sudo mkdir -p "$chrootdir" setarch "${arch}" mkarchroot \ -C "/usr/share/devtools/pacman-${chroot_repo}.conf" \ -M "/usr/share/devtools/makepkg-${arch}.conf" \ "$chrootdir/root" \ "${packages[@]}" fi } __cleanup_logs() { mkdir -p "$1/logs" mv "$1/"*.log "$1/"*.log.* "$1/logs/" || return gzip -f "$1/logs/"*.log "$1/logs/"*.log.{1,2,3,4,5,6,7,8,9} } chkill() { if [[ $1 = all ]]; then for chrootdir in "$CHROOTS/"*/; do chkill "$(basename "$chrootdir")" done return fi __chrootalias_resolve "$1" || return for dir in "$CHROOTS/$chroot/"*/; do sudo btrfs subvolume delete "$dir/var/lib/portables" || true sudo btrfs subvolume delete "$dir/var/lib/machines" || true sudo btrfs subvolume delete "$dir" done sudo rm -rf "$CHROOTS/$chroot" } chshell() { __chrootalias_resolve_create "$1" || return [ -d "$copydir" ] || __genchroot sudo arch-nspawn "$copydir" "${2:-/bin/bash}" "${@:3}" } chbuild() { __chrootalias_resolve_create "$1" || return linux${chroot_arch} sudo makechrootpkg -l "${copydir##*/}" -r "$chrootdir" -n -- -f "${@:2}" || return chshell "$1" pacman --noconfirm -Rcs namcap __cleanup_logs "$PWD" } chinstall() { __chrootalias_resolve_create "$1" || return; shift for file in "$@"; do files+=(-I "$(readlink -f "$file")") done cd /var/empty linux${chroot_arch} sudo makechrootpkg -l "${copydir##*/}" -r "$chrootdir" "${files[@]}" } chclean() { __chrootalias_resolve_create "$1" || return for copy in $chrootdir/*/; do if [[ $copy = */root/ ]]; then continue fi sudo btrfs subvolume delete "$copy/var/lib/portables" || true sudo btrfs subvolume delete "$copy/var/lib/machines" || true sudo btrfs subvolume delete "$copy" sudo rm -f "${copy%/}.lock" done } chclean-single() { __chrootalias_resolve_create "$1" || return if [[ -e $copydir ]]; then sudo btrfs subvolume delete "$copydir/var/lib/machines" || true sudo btrfs subvolume delete "$copydir" sudo rm -f "${copydir%/}.lock" fi } chrshell() { __chrootalias_resolve_create "$1" || return sudo arch-nspawn "$chrootdir/root" "${2:-/bin/bash}" "${@:3}" } chupdate() { __chrootalias_resolve_create "$1" || return echo ":: Updating $chroot" sudo arch-nspawn "$chrootdir/root" pacman -Syu --noconfirm echo ":: Cleaning up ..." chclean "$1" } command=$1; shift case $command in repack) for arg; do chbuild "$arg" -R done ;; cbuild) for arg; do chclean-single "$arg" chbuild "$arg" done ;; build) for arg; do chbuild "$arg" done ;; build-single) chbuild "$@" ;; update) if [[ $# = 0 ]]; then for chrootdir in "$CHROOTS/"*/; do chupdate "$(basename "$chrootdir")" done else for arg; do chupdate "$arg" done fi ;; clean) if [[ $# = 0 ]]; then for chrootdir in "$CHROOTS/"*/; do chclean "$(basename "$chrootdir")" done else for arg; do chclean "$arg" done fi ;; clean-single) for arg; do chclean-single "$arg" done ;; kill) for arg; do chkill "$arg" done ;; shell) chshell "$@";; shell-bind) chshell "$@" --bind-ro="$PWD:/pwd";; rshell) chrshell "$@";; install) chinstall "$@";; list) for chrootdir in "$CHROOTS/"*/; do basename "$chrootdir" for copydir in "$chrootdir/"*/; do dirname=$(basename "$copydir") if [[ $dirname != "root" ]]; then printf " %s\n" "$dirname" fi done done ;; *) printf "Unknown command %s\n" "$command";; esac