devtools/makechrootpkg.in

298 lines
7.9 KiB
Plaintext
Raw Normal View History

#!/bin/bash
# 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.
shopt -s nullglob
makepkg_args='-s --noconfirm'
repack=false
update_first=false
clean_first=false
install_pkg=
add_to_db=false
chrootdir=
default_copy=$USER
[[ -n $SUDO_USER ]] && default_copy=$SUDO_USER
[[ -z $default_copy || $default_copy = root ]] && default_copy=copy
2010-02-13 19:47:16 +01:00
usage() {
echo "usage ${0##*/} [options] -r <chrootdir> [--] [makepkg args]"
2010-02-13 19:47:16 +01:00
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 ' <chrootdir>/{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 <chrootdir>/root base base-devel sudo'
echo ''
echo "Default makepkg args: $makepkg_args"
2010-02-13 19:47:16 +01:00
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 <dir> The chroot dir to use'
echo '-I <pkg> Install a package into the working copy of the chroot'
echo '-l <copy> The directory to use as the working copy of the chroot'
echo ' Useful for maintaining multiple copies.'
echo " Default: $default_copy"
2010-02-13 19:47:16 +01:00
exit 1
}
while getopts 'hcudr:I:l:' arg; do
case "$arg" in
2010-02-13 19:47:16 +01:00
h) usage ;;
c) clean_first=true ;;
u) update_first=true ;;
d) add_to_db=true ;;
2010-02-13 19:47:16 +01:00
r) chrootdir="$OPTARG" ;;
I) install_pkg="$OPTARG" ;;
l) copy="$OPTARG" ;;
*) makepkg_args="$makepkg_args -$arg $OPTARG" ;;
2010-02-13 19:47:16 +01:00
esac
done
# Canonicalize chrootdir, getting rid of trailing /
chrootdir=$(readlink -e "$chrootdir")
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=1
break
2010-02-13 19:47:16 +01:00
fi
done
if (( EUID )); then
2010-02-13 19:47:16 +01:00
echo 'This script must be run as root.'
exit 1
fi
if [[ ! -f PKGBUILD && -z $install_pkg ]]; then
2010-02-13 19:47:16 +01:00
echo 'This must be run in a directory containing a PKGBUILD.'
exit 1
fi
if [[ ! -d $chrootdir ]]; then
2010-02-13 19:47:16 +01:00
echo "No chroot dir defined, or invalid path '$chrootdir'"
exit 1
fi
if [[ ! -d $chrootdir/root ]]; then
2010-02-13 19:47:16 +01:00
echo 'Missing chroot dir root directory.'
echo "Try using: mkarchroot $chrootdir/root base base-devel sudo"
usage
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
exec 9>"$copydir.lock"
if ! flock -n 9; then
echo -n "locking chroot copy '$copy'..."
flock 9
echo "done"
fi
if [[ ! -d $copydir ]] || $clean_first; then
# Get a read lock on the root chroot to make
# sure we don't clone a half-updated chroot
exec 8>"$chrootdir/root.lock"
if ! flock -sn 8; then
echo -n "locking clean chroot..."
flock -s 8
echo "done"
fi
2010-02-13 19:47:16 +01:00
echo -n 'creating clean working copy...'
use_rsync=false
if type -P btrfs >/dev/null; then
[[ -d $copydir ]] && btrfs subvolume delete "$copydir" &>/dev/null
btrfs subvolume snapshot "$chrootdir/root" "$copydir" &>/dev/null ||
use_rsync=true
else
use_rsync=true
fi
if $use_rsync; then
mkdir -p "$copydir"
rsync -a --delete -q -W -x "$chrootdir/root/" "$copydir"
fi
2010-02-13 19:47:16 +01:00
echo 'done'
# Drop the read lock again
exec 8>&-
fi
if [[ -n $install_pkg ]]; then
pkgname="${install_pkg##*/}"
2010-02-13 19:47:16 +01:00
cp "$install_pkg" "$copydir/$pkgname"
mkarchroot -r "pacman -U /$pkgname --noconfirm" "$copydir"
2010-02-13 19:47:16 +01:00
ret=$?
2010-02-13 19:47:16 +01:00
rm "$copydir/$pkgname"
# Exit early, we've done all we need to
2010-02-13 19:47:16 +01:00
exit $ret
fi
$update_first && mkarchroot -u "$copydir"
mkdir -p "$copydir/build"
# Remove anything in there UNLESS -R (repack) was passed to makepkg
$repack || rm -rf "$copydir"/build/*
# Read .makepkg.conf even if called via sudo
if [[ -n $SUDO_USER ]]; then
makepkg_conf="$(eval echo ~$SUDO_USER)/.makepkg.conf"
else
makepkg_conf="$HOME/.makepkg.conf"
fi
# Get SRC/PKGDEST from makepkg.conf
if [[ -f $makepkg_conf ]]; then
eval $(grep '^SRCDEST=' "$makepkg_conf")
eval $(grep '^PKGDEST=' "$makepkg_conf")
eval $(grep '^MAKEFLAGS=' "$makepkg_conf")
eval $(grep '^PACKAGER=' "$makepkg_conf")
fi
[[ -z $SRCDEST ]] && eval $(grep '^SRCDEST=' /etc/makepkg.conf)
[[ -z $PKGDEST ]] && eval $(grep '^PKGDEST=' /etc/makepkg.conf)
[[ -z $MAKEFLAGS ]] && eval $(grep '^MAKEFLAGS=' /etc/makepkg.conf)
[[ -z $PACKAGER ]] && eval $(grep '^PACKAGER=' /etc/makepkg.conf)
# Use PKGBUILD directory if PKGDEST or SRCDEST don't exist
[[ -d $PKGDEST ]] || PKGDEST=.
[[ -d $SRCDEST ]] || SRCDEST=.
mkdir -p "$copydir/pkgdest"
if ! grep -q 'PKGDEST="/pkgdest"' "$copydir/etc/makepkg.conf"; then
echo 'PKGDEST="/pkgdest"' >> "$copydir/etc/makepkg.conf"
fi
mkdir -p "$copydir/srcdest"
if ! grep -q 'SRCDEST="/srcdest"' "$copydir/etc/makepkg.conf"; then
echo 'SRCDEST="/srcdest"' >> "$copydir/etc/makepkg.conf"
fi
if [[ -n $MAKEFLAGS ]]; then
sed -i '/^MAKEFLAGS=/d' "$copydir/etc/makepkg.conf"
echo "MAKEFLAGS='${MAKEFLAGS}'" >> "$copydir/etc/makepkg.conf"
fi
if [[ -n $PACKAGER ]]; then
sed -i '/^PACKAGER=/d' "$copydir/etc/makepkg.conf"
echo "PACKAGER='${PACKAGER}'" >> "$copydir/etc/makepkg.conf"
fi
# Set target CARCH as it might be used within the PKGBUILD to select correct sources
eval $(grep '^CARCH=' "$copydir/etc/makepkg.conf")
export CARCH
# Copy PKGBUILD and sources
source=( $(source PKGBUILD; echo ${source[@]}) )
cp PKGBUILD "$copydir/build/"
for file in "${source[@]}"; do
file="${file%%::*}"
file="${file##*://*/}"
if [[ -f $file ]]; then
cp "$file" "$copydir/srcdest/"
elif [[ -f $SRCDEST/$file ]]; then
cp "$SRCDEST/$file" "$copydir/srcdest/"
2010-02-13 19:47:16 +01:00
fi
done
(
source PKGBUILD
for i in changelog install; do
sed -n "s/^[[:space:]]*$i=//p" PKGBUILD | while IFS= read -r file; do
# evaluate any bash variables used
eval file="$file"
[[ -f $file ]] && cp "$file" "$copydir/build/"
done
done
)
chown -R nobody "$copydir"/{build,pkgdest,srcdest}
echo 'nobody ALL = NOPASSWD: /usr/bin/pacman' > "$copydir/etc/sudoers.d/nobody-pacman"
chmod 440 "$copydir/etc/sudoers.d/nobody-pacman"
# This is a little gross, but this way the script is recreated every time in the
# working copy
cat >"$copydir/chrootbuild" <<EOF
#!/bin/bash
export LANG=C
export HOME=/build
cd /build
sudo -u nobody makepkg $makepkg_args || touch BUILD_FAILED
[[ -f BUILD_FAILED ]] && exit 1
2010-05-02 15:42:29 +02:00
which namcap &>/dev/null && namcap /build/PKGBUILD /pkgdest/*.pkg.tar.* > /build/namcap.log
exit 0
EOF
chmod +x "$copydir/chrootbuild"
if mkarchroot -r "/chrootbuild" "$copydir"; then
for pkgfile in "$copydir"/pkgdest/*.pkg.tar.*; do
if $add_to_db; then
mkdir -p "$copydir/repo"
pushd "$copydir/repo" >/dev/null
2010-02-13 19:47:16 +01:00
cp "$pkgfile" .
repo-add repo.db.tar.gz "${pkgfile##*/}"
2010-02-13 19:47:16 +01:00
popd >/dev/null
fi
mv "$pkgfile" "$PKGDEST"
2010-02-13 19:47:16 +01:00
done
for l in "$copydir"/build/{namcap,*-{build,check,package,package_*}}.log; do
[[ -f $l ]] && mv "$l" .
2010-02-13 19:47:16 +01:00
done
else
# Just in case. We returned 1, make sure we fail
touch "$copydir/build/BUILD_FAILED"
fi
for f in "$copydir"/srcdest/*; do
mv "$f" "$SRCDEST"
done
if [[ -e $copydir/build/BUILD_FAILED ]]; then
2010-02-13 19:47:16 +01:00
echo "Build failed, check $copydir/build"
rm "$copydir/build/BUILD_FAILED"
2010-05-02 15:16:53 +02:00
exit 1
2010-02-13 19:47:16 +01:00
fi