#!/bin/bash # Copyright 2011-2012 The Arch Linux Development Team # Copyright 2012 Luke Shumaker # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # Because of how we pull changes from devtools.git, some of the function # bodies are not indented. I appologize for my sins against the reader. # Any function beginning with "_makechrootpkg_" is basically a multiline # comment to minimize the diff. These functions may use different variable # names. # Otherwise, a function may be affected by the variables: # makepkg.conf # - PKGDEST # - SRCDEST # chroot.conf (and derived) # - CHROOT # - CHROOTCOPY # - rootdir # = $CHROOTDIR/$CHROOT/root # - copydir # = $CHROOTDIR/$CHROOT/$CHROOTCOPY # environment # - LIBREUSER # conf.sh # - LIBREHOME # conf.sh # - INCHROOT # libremakepkg # invocation # - repack [[ -n ${repack:-} ]] || repack=false _makechrootpkg_init() { m4_include(lib/common.sh) shopt -s nullglob makepkg_args='-s --noconfirm -L' repack=false update_first=false clean_first=false install_pkg= add_to_db=false run_namcap=false chrootdir= passeddir= default_copy=$USER [[ -n $SUDO_USER ]] && default_copy=$SUDO_USER [[ -z $default_copy || $default_copy = root ]] && default_copy=copy src_owner=${SUDO_USER:-$USER} } _makechrootpkg_usage() { echo "Usage: ${0##*/} [options] -r [--] [makepkg args]" echo ' Run this script in a PKGBUILD dir to build a package inside a' echo ' clean chroot. All unrecognized arguments passed to this script' echo ' will be passed to makepkg.' echo '' echo ' The chroot dir consists of the following directories:' echo ' /{root, copy} but only "root" is required' echo ' by default. The working copy will be created as needed' echo '' echo 'The chroot "root" directory must be created via the following' echo 'command:' echo ' mkarchroot /root base base-devel sudo' echo '' echo "Default makepkg args: $makepkg_args" echo '' echo 'Flags:' echo '-h This help' echo '-c Clean the chroot before building' echo '-u Update the working copy of the chroot before building' echo ' This is useful for rebuilds without dirtying the pristine' echo ' chroot' echo '-d Add the package to a local db at /repo after building' echo '-r The chroot dir to use' echo '-I Install a package into the working copy of the chroot' echo '-l The directory to use as the working copy of the chroot' echo ' Useful for maintaining multiple copies.' echo " Default: $default_copy" echo '-n Run namcap on the package' exit 1 } _makechrootpkg_parse_options_init() { while getopts 'hcudr:I:l:n' arg; do case "$arg" in h) usage ;; c) clean_first=true ;; u) update_first=true ;; d) add_to_db=true ;; r) passeddir="$OPTARG" ;; I) install_pkg="$OPTARG" ;; l) copy="$OPTARG" ;; n) run_namcap=true; makepkg_args="$makepkg_args -i" ;; *) makepkg_args="$makepkg_args -$arg $OPTARG" ;; esac done # Canonicalize chrootdir, getting rid of trailing / chrootdir=$(readlink -e "$passeddir") if [[ ${copy:0:1} = / ]]; then copydir=$copy else [[ -z $copy ]] && copy=$default_copy copydir="$chrootdir/$copy" fi # Pass all arguments after -- right to makepkg makepkg_args="$makepkg_args ${*:$OPTIND}" # See if -R was passed to makepkg for arg in ${*:$OPTIND}; do if [[ $arg = -R ]]; then repack=true break fi done if (( EUID )); then die 'This script must be run as root.' fi if [[ ! -f PKGBUILD && -z $install_pkg ]]; then die 'This must be run in a directory containing a PKGBUILD.' fi if [[ ! -d $chrootdir ]]; then die "No chroot dir defined, or invalid path '$passeddir'" fi if [[ ! -d $chrootdir/root ]]; then die "Missing chroot dir root directory. Try using: mkarchroot $chrootdir/root base base-devel sudo" fi umask 0022 # Lock the chroot we want to use. We'll keep this lock until we exit. # Note this is the same FD number as in mkarchroot lock_open_write 9 "$copydir.lock" "Locking chroot copy '$copy'" } chroot_sync() { if [[ $CHROOTCOPY = root ]]; then error "Cannot sync the root copy with itself" exit 1 fi # Get a read lock on the root chroot to make # sure we don't clone a half-updated chroot lock_open_read 8 "$rootdir" \ "Waiting for existing lock on \`$rootdir' to be released" stat_busy 'Creating clean working copy' local use_rsync=false if type -P btrfs >/dev/null; then [[ -d $copydir ]] && btrfs subvolume delete "$copydir" &>/dev/null btrfs subvolume snapshot "$rootdir" "$copydir" &>/dev/null || use_rsync=true else use_rsync=true fi if $use_rsync; then mkdir -p "$copydir" rsync -a --delete -q -W -x "$rootdir/" "$copydir" fi stat_done # Drop the read lock again lock_close 8 } _makechrootpkg_install_pkg() { pkgname="${install_pkg##*/}" cp "$install_pkg" "$copydir/$pkgname" mkarchroot -r "pacman -U /$pkgname --noconfirm" "$copydir" ret=$? rm "$copydir/$pkgname" # Exit early, we've done all we need to exit $ret } chroot_init() { # make sure the chroot exists librechroot -n "$CHROOT" -l "$CHROOTCOPY" -m mkdir -p "$copydir/build" mkdir -p "$copydir/pkgdest" mkdir -p "$copydir/srcdest" # Remove anything in there UNLESS -R (repack) was passed to makepkg $repack || rm -rf "$copydir"/build/* if [[ -r "$LIBREHOME/.gnupg/pubring.gpg" ]]; then install -D "$LIBREHOME/.gnupg/pubring.gpg" "$copydir/build/.gnupg/pubring.gpg" fi rm -f "$copydir/build/.makepkg.conf" MAKEPKG_CONF="$copydir/etc/makepkg.conf" set_conf_makepkg PKGDEST /pkgdest MAKEPKG_CONF="$copydir/etc/makepkg.conf" set_conf_makepkg SRCDEST /srcdest if grep -q '^\[repo\]' "$copydir/etc/pacman.conf"; then cat >> "$copydir/etc/makepkg.conf" < "$copydir/etc/sudoers.d/nobody-pacman" <"$copydir/chrootexec" </dev/null cp "$pkgfile" . repo-add repo.db.tar.gz "${pkgfile##*/}" popd >/dev/null fi done } _chroot_copy_out_pkgs() { for pkgfile in "$copydir"/pkgdest/*.pkg.tar*; do chown "$LIBREUSER" "$pkgfile" mv "$pkgfile" "$PKGDEST" if [[ $PKGDEST != . ]]; then ln -s "$PKGDEST/${pkgfile##*/}" . fi done } _chroot_copy_out_logs() { for l in "$copydir"/build/*.log; do chown "$LIBREUSER" "$l" [[ -f $l ]] && mv "$l" . done } _chroot_copy_out_srcs() { for f in "$copydir"/srcdest/*; do chown "$LIBREUSER" "$f" mv "$f" "$SRCDEST" done } chroot_copy_out() { _chroot_copy_out_pkgs _chroot_copy_out_logs _chroot_copy_out_srcs }