#!/bin/bash set -e # empdebuild : emdebian version of pdebuild. # # Emdebian chroot builder - initially supporting the creation of a # chroot capable of running emdebian-tools to reduce the number of # cross dependencies that need to be installed on the build system. # # Copyright (C) 2006-2008 Neil Williams # # This package 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; either version 3 of the License, or # (at your option) any later version. # # 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Note 1: Most configuration values are calculated, not taken from the command line # or an rc file. # Note 2: emdebuild creates a build log for us - just the output of dpkg-buildpackage, # not the rest of the chroot operations. . /usr/share/emdebian-tools/empbuilderlib SUITE=unstable function usagehelp () { # print out help message cat < updating apt-cross cache" chroot $BUILDPLACE /usr/bin/apt-cross -a $ARCH -S $SUITE -u echo " -> Attempting to parse the cross-build dependencies" # read debian/xcontrol for INSTALLPKGMULTI in $(cat ${DEBIAN_XCONTROL} | \ awk ' BEGIN{source=1} /^$/ {source=0} /^Source:/ {source=1} /^[^ ]*:/ {p=0} tolower($0) ~ /^'"${BD_REGEXP}"':/ {p=1} {if(p && source) {print $0}}' | \ sed 's/^[^: ]*://' | \ tr " " "/" | \ awk 'BEGIN{RS=","} {print}'); do echo " -> Considering cross-build-dep$(echo "$INSTALLPKGMULTI" | tr "/" " " )" # parse the list - removing commas etc. for INSTALLPKG in $(echo "$INSTALLPKGMULTI" | \ awk 'BEGIN{RS="|"} {print}'); do CURRENTREALPKGNAME=$(echo "$INSTALLPKG" | sed -e 's/^[/]*//' -e 's/[[/(].*//') #)# syntax hack INSTALLPKGLIST="${INSTALLPKGLIST} ${CURRENTREALPKGNAME}" done; # end parse list done; # end parse debian/xcontrol if [ -n "${INSTALLPKGLIST}" ]; then echo " -> Installing ${INSTALLPKGLIST}" chroot $BUILDPLACE /usr/bin/apt-cross -q -k -a $ARCH --install ${INSTALLPKGLIST} save_aptcrosscache fi echo " -> Finished parsing the cross build-deps" } function update_emchroot () { if [ $SUITE == testing ]; then BASETGZ="${WORKDIR}/emdebian-testing.tgz" SUITE=testing echo "Updating the embootstrap testing chroot" else BASETGZ="$WORKDIR/emdebian.tgz" fi extractembuildplace echo "File extracted to: $BUILDPLACE" echo "" echo " -> upgrading packages" disable_apt_recommends # force the sources list - a bit of a hack really. # TODO this should be configurable - emdebian-tools will add a primary later. cp /usr/share/emdebian-tools/emsources.$SUITE $BUILDPLACE/etc/apt/sources.list if echo "/usr/bin/apt-get update" | chroot $BUILDPLACE /bin/sh; then : else # if apt failed (maybe update needs to be run), save so far and exit cleanly save_aptcache # copy out the failed build here first. umountproc cleanbuildplace exit 1; fi echo " -> updating apt-cross cache for $SUITE" if echo "/usr/bin/apt-cross -a $ARCH -S $SUITE -u" | chroot $BUILDPLACE /bin/sh; then : else # if apt failed (maybe update needs to be run), save so far and exit cleanly save_aptcache umountproc cleanbuildplace exit 1; fi recover_aptcache # TODO persistent problems with the toolchains mean this needs to be optional. if echo "DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get $OPTIONS -y --force-yes upgrade" | chroot $BUILDPLACE /bin/sh; then : else # if apt failed (maybe update needs to be run), save so far and exit cleanly save_aptcache umountproc cleanbuildplace exit 1; fi if echo "DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get $OPTIONS -y --force-yes dist-upgrade" | chroot $BUILDPLACE /bin/sh; then : else # if apt failed (maybe update needs to be run), save so far and exit cleanly save_aptcache umountproc cleanbuildplace exit 1; fi chroot $BUILDPLACE /usr/bin/apt-get $OPTIONS -y --force-yes install emdebian-tools || true chroot $BUILDPLACE /usr/bin/apt-get $OPTIONS --purge -y --force-yes autoremove || true autoclean_aptcache save_aptcache echo " -> updating devscripts configuration" if [ -f /home/$SUDO_USER/.devscripts ]; then cp /home/$SUDO_USER/.devscripts $BUILDPLACE/home/$SUDO_USER/.devscripts fi VAL=`chroot $BUILDPLACE hostname -f 2>&1` if [ "$VAL" != "" ]; then echo " -> updating /etc/hosts" cp /etc/hosts $BUILDPLACE/etc/hosts fi # sometimes this returns non-zero if echo "$COLOUR ARCH=$ARCH /usr/bin/emsetup --arch $ARCH --yes" | chroot $BUILDPLACE /bin/sh; then : fi umountproc || true chroot $BUILDPLACE /usr/bin/apt-get clean || true create_emdebiantgz } # very similar to emchrootbuild but calls emsource inside the # chroot instead of copying the source in from outside. # i.e. autobuilder mode (so it tries to be quiet). function empautobuild() { if [ $SUITE == testing ]; then BASETGZ="${WORKDIR}/emdebian-testing.tgz" SUITE=testing echo "Building in the embootstrap testing chroot" else BASETGZ="$WORKDIR/emdebian.tgz" fi . /usr/lib/pbuilder/pbuilder-buildpackage-funcs PACKAGE=$1 BUILDRESULTUID="${BUILDRESULTUID:-${SUDO_UID:-0}}" BUILDRESULTGID="${BUILDRESULTGID:-${SUDO_GID:-0}}" INITIAL=`echo $PACKAGE | cut -b1` TRUNK="$INITIAL/${PACKAGE}/trunk" echobacktime extractembuildplace echo "File extracted to: $BUILDPLACE" echo "" recover_aptcache createbuilduser if [ -f "/etc/devscripts.conf" ]; then cp /etc/devscripts.conf $BUILDPLACE/etc/devscripts.conf fi if [ -f "/home/$SUDO_USER/.devscripts" ]; then mkdir -p $BUILDPLACE/home/$SUDO_USER/ cp /home/$SUDO_USER/.devscripts $BUILDPLACE/home/$SUDO_USER/.devscripts fi COLOUR= if [ $ANSI_COLORS_DISABLED ]; then COLOUR=ANSI_COLORS_DISABLED=1 fi echo "Checking the Emdebian toolchain" # fails with non-zero if no toolchain is found if echo "$COLOUR /usr/bin/emsetup -q --arch $ARCH --report" | chroot $BUILDPLACE /bin/sh; then : else umountproc cleanbuildplace exit 1; fi if echo "$COLOUR ARCH=$ARCH emsource -q -a $ARCH -b --build-dep $PACKAGE $EM_DPKG_OPTS" | chroot $BUILDPLACE /bin/sh; then : else echo " -> emsource -b failed" if [ "${LOGIN_AFTER_FAIL}" = "yes" ]; then echo " -> Logging into the chroot" echobacktime chroot $BUILDPLACE /bin/sh save_aptcache umountproc cleanbuildplace exit 1; fi save_aptcache umountproc cleanbuildplace exit 1; fi if [ $? -ne 0 ]; then echo " -> emsource -b failed" if [ "${LOGIN_AFTER_FAIL}" = "yes" ]; then echo " -> Logging into the chroot" echobacktime chroot $BUILDPLACE /bin/sh save_aptcache umountproc cleanbuildplace exit 1; fi fi FULLPATH="$BUILDPLACE/trunk/$TRUNK/" FULLPATH=`echo $FULLPATH | tr -s \/` PKGRESULT="${BUILDRESULT}${INITIAL}/${PACKAGE}/trunk" echo "Copying build results to ${PKGRESULT}" mkdir -p "$PKGRESULT" if [ -d "${PKGRESULT}" ]; then chown -R "${BUILDRESULTUID}:${BUILDRESULTGID}" "${BUILDRESULT}/"* cp -p "${FULLPATH}"/* "${PKGRESULT}" 2>/dev/null || true chown -R "${BUILDRESULTUID}:${BUILDRESULTGID}" "${BUILDRESULT}/"* else echo "E: BUILDRESULT=[$BUILDRESULT] is not a directory." >&2 fi save_aptcache umountproc cleanbuildplace echobacktime } function emchrootbuild() { if [ $SUITE == testing ]; then BASETGZ="${WORKDIR}/emdebian-testing.tgz" SUITE=testing echo "Building in the embootstrap testing chroot" else BASETGZ="$WORKDIR/emdebian.tgz" fi . /usr/lib/pbuilder/pbuilder-buildpackage-funcs BUILDRESULTUID="${BUILDRESULTUID:-${SUDO_UID:-0}}" BUILDRESULTGID="${BUILDRESULTGID:-${SUDO_GID:-0}}" while ! test -d ./debian -o "$(pwd)" = "$WORKDIR" ; do cd ..; done if test ! -d ./debian; then echo "Cannot find ./debian dir" cleanbuildplace exit 1 fi; PKG_SOURCENAME=`dpkg-parsechangelog|sed -n 's/^Source: //p'` PKG_VERSION=`dpkg-parsechangelog|sed -n 's/^Version: \(.*:\|\)//p'` HOST_ARCH=`dpkg-architecture -qDEB_HOST_ARCH` echo "Building ${PKG_SOURCENAME} ${PKG_VERSION} on ${HOST_ARCH} for $ARCH" INITIAL=`echo $PKG_SOURCENAME | cut -b1` PKG=`basename \$PWD`; TRUNK="$INITIAL/${PKG_SOURCENAME}/trunk" SVN="$TRUNK/${PKG}" if [ "$LOGIN_AFTER_FAIL" == "yes" ]; then echo " -> will attempt to login after build failure" fi echo " -> source location: trunk/$SVN" # get the Debian .dsc DEB_VER=`echo $PKG_VERSION | sed -n 's/em[0-9]*$//p'` if [ "$DEB_VER" == "" ]; then echo "$PKG_VERSION is not an Emdebian version string." cleanbuildplace exit 1; fi DSC="${PKG_SOURCENAME}_${DEB_VER}.dsc" if [ ! -f "../$DSC" ]; then echo "Cannot find ../$DSC" cleanbuildplace exit 1; fi echo " -> using $DSC" # don't duplicate the downloads made by emsource DIFFS=`find ../ -name emdebian-*\.patch` DEBDIFFS=`find ../ -maxdepth 1 -name debian-patch*` OLDSRC="$PKG_SOURCENAME.old" echobacktime extractembuildplace echo "File extracted to: $BUILDPLACE" echo "" recover_aptcache createbuilduser if [ -f "/etc/devscripts.conf" ]; then cp /etc/devscripts.conf $BUILDPLACE/etc/devscripts.conf fi if [ -f "/home/$SUDO_USER/.devscripts" ]; then mkdir -p $BUILDPLACE/home/$SUDO_USER/ cp /home/$SUDO_USER/.devscripts $BUILDPLACE/home/$SUDO_USER/.devscripts fi COLOUR= if [ $ANSI_COLORS_DISABLED ]; then COLOUR=ANSI_COLORS_DISABLED=1 fi echo "Checking the Emdebian toolchain" # fails with non-zero if no toolchain is found if echo "$COLOUR /usr/bin/emsetup --arch $ARCH --report" | chroot $BUILDPLACE /bin/sh; then : else umountproc cleanbuildplace exit 1; fi echo "Copying Debian source" chroot $BUILDPLACE mkdir -p trunk/$TRUNK copydsc "../$DSC" "$BUILDPLACE/trunk/${TRUNK}/" chroot $BUILDPLACE /usr/bin/dpkg-source -x trunk/${TRUNK}/$DSC trunk/$SVN echo "Applying Emdebian changes" for PATCH in $DEBDIFFS do if [ ! -d /trunk/$SVN/debian/patches/ ]; then echo "Creating debian/patches directory" mkdir -p $BUILDPLACE/trunk/$SVN/debian/patches/ fi NAME=`echo $PATCH | sed -e 's/..\/debian-patch-//'` echo "Copying $PATCH to /trunk/$SVN/debian/patches/$NAME" cp "$PATCH" "$BUILDPLACE/trunk/$SVN/debian/patches/$NAME" done for PATCH in $DIFFS do cp "$PATCH" "$BUILDPLACE/trunk/$TRUNK" if echo "cd /trunk/$SVN; patch -p1 < $PATCH" | chroot $BUILDPLACE /bin/sh; then : else umountproc cleanbuildplace exit 1; fi done # only check for dependencies AFTER debian/control has been patched for Emdebian. echo " -> installing build dependencies for $PKG_SOURCENAME" checkembuilddep # new function to parse and install cross-depends. # read debian/xcontrol, pass Build-Cross-Depends to apt-cross -i get_cross_depends save_aptcache echo " -> copying ../$OLDSRC" cp -r "../$OLDSRC" "$BUILDPLACE/trunk/$TRUNK" echo "Running emdebuild -a $ARCH $EM_DPKG_OPTS " COLOUR= if [ $ANSI_COLORS_DISABLED ]; then COLOUR=ANSI_COLORS_DISABLED=1 fi if echo "cd /trunk/$SVN; $COLOUR ARCH=$ARCH emdebuild -a $ARCH $EM_DPKG_OPTS" | chroot $BUILDPLACE /bin/sh; then : else echo " -> emdebuild failed" if [ "${LOGIN_AFTER_FAIL}" = "yes" ]; then echo " -> Logging into the chroot" echo " -> Build directory: /trunk/$SVN" echobacktime chroot $BUILDPLACE /bin/sh save_aptcache umountproc cleanbuildplace exit 1; fi save_aptcache umountproc cleanbuildplace exit 1; fi if [ $? -ne 0 ]; then echo " -> emdebuild failed" if [ "${LOGIN_AFTER_FAIL}" = "yes" ]; then echo " -> Logging into the chroot" echo " -> Build directory: /trunk/$SVN" echobacktime chroot $BUILDPLACE /bin/sh save_aptcache umountproc cleanbuildplace exit 1; fi fi FULLPATH="$BUILDPLACE/trunk/$TRUNK/" FULLPATH=`echo $FULLPATH | tr -s \/` PKGRESULT="${BUILDRESULT}${INITIAL}/${PKG_SOURCENAME}/trunk" echo "Copying build results to ${PKGRESULT}" mkdir -p "$PKGRESULT" if [ -d "${PKGRESULT}" ]; then chown -R "${BUILDRESULTUID}:${BUILDRESULTGID}" "${BUILDRESULT}/"* cp -p "${FULLPATH}"/* "${PKGRESULT}" 2>/dev/null || true chown -R "${BUILDRESULTUID}:${BUILDRESULTGID}" "${BUILDRESULT}/"* else echo "E: BUILDRESULT=[$BUILDRESULT] is not a directory." >&2 fi CHANGES=`find $PKGRESULT -name \*${PKG_VERSION}_${ARCH}.changes` echo " -> .changes file : ${CHANGES}" EMDSC=`find $PKGRESULT -name \*${PKG_VERSION}.dsc` echo " -> .dsc file : ${EMDSC}" EMDEBS=`find $PKGRESULT -name \*${PKG_VERSION}*deb | grep -c deb` echo " -> ${EMDEBS} packages built." save_aptcache umountproc cleanbuildplace echobacktime } function emlogin() { if [ $SUITE == testing ]; then BASETGZ="${WORKDIR}/emdebian-testing.tgz" echo "Logging into the embootstrap testing chroot" else BASETGZ="$WORKDIR/emdebian.tgz" fi extractembuildplace recover_aptcache echo " -> entering the shell" echo "File extracted to: $BUILDPLACE" # login should be as close to failsafe as possible so do v.little else. chroot $BUILDPLACE /bin/sh || true save_aptcache umountproc # saving the buildplace afterwards if [ "${SAVE_AFTER_LOGIN}" = "yes" ]; then echo " -> Saving the results, modifications to this session will persist" chroot $BUILDPLACE /usr/bin/apt-get clean || true create_emdebiantgz fi cleanbuildplace } # test for sudo - normally empdebuild is installed in /usr/sbin so this # test is really only for SVN users. # make sure sudo is in use. # bash cannot seem to do this when set -e is enabled # because grep returns non-zero on a non-match # so I use perl. :-) ISSUDOSET=`perl -e '$e=\`printenv\`; ($e =~ /SUDO_USER/) ? print "yes" : print "no";'` if [ $ISSUDOSET == "no" ] ; then AREWEROOT=`perl -e '$e=\`printenv\`; ($e =~ /LOGNAME=root/) ? print "yes" : print "no";'` if [ $AREWEROOT == "no" ]; then echo "empdebuild needs to be run under sudo or as root." exit 2 fi fi if [ ! $1 ];then usagehelp exit; fi USEDEVPTS="yes" USEPROC="yes" while [ -n "$1" ]; do case "$1" in --help|-h|-?|--version) usagehelp exit; ;; -a|--arch) shift ARCH=$1 # chomp the argument to --arch shift ;; --testing) shift SUITE=testing ;; --create|create) shift; checkarch createemchroot exit; ;; --update|update) shift; checkarch update_emchroot exit; ;; --build|build) shift; checkarch emchrootbuild exit; ;; --autobuild|autobuild) shift; PACKAGE=$1 shift; checkarch empautobuild $PACKAGE exit; ;; --save-after-login) shift SAVE_AFTER_LOGIN="yes" ;; --login-after-fail) shift LOGIN_AFTER_FAIL="yes" ;; --login|login) shift checkarch emlogin exit; ;; --clean|clean) shift echo "Trying to ensure crashed chroots are unmounted" CRASH=`mount | grep "$WORKDIR" | cut -d' ' -f3` if [ "$CRASH" ]; then echo "Trying to ensure crashed chroots are unmounted" mount | grep "$WORKDIR" | cut -d' ' -f3 | xargs umount || true fi echo "Cleaning $BASEBUILDPLACE" clean_subdirectories $BASEBUILDPLACE # if debootstrap fails, we start again so remove the stamp. if [ -f $WORKDIR/stamp-debootstrap ]; then rm $WORKDIR/stamp-debootstrap fi exit; ;; --) while [ -n "$1" ] do EM_DPKG_OPTS+="$1 " shift done break ;; *) echo "Unrecognised option: $1" echo usagehelp exit; ;; esac done