You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

620 lines
18 KiB
Bash

#!/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 <codehelp@debian.org>
#
# 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 <http://www.gnu.org/licenses/>.
#
# 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 <<EOF
empdebuild - cross-building chroot Emdebian package builder
version $OURVERSION
Syntax: sudo empdebuild [OPTIONS] [COMMAND]
Only one command can be actioned at any one time.
Options must precede the command to take effect.
Commands:
-?|-h|--help|-version: print this help message and exit
--create|create: create a cross-building base .tgz for unstable
--update|update: update the base .tgz and save changes
--build|build: build the current package in the chroot
(needs to be run in the top source directory)
--autobuild|autobuild PACKAGE: build the specified package in the chroot
(used by the autobuilder)
--login|login: Login to the chroot to run tests or fix problems.
--clean|clean: Clean up all build sub directories.
Options:
--arch: Override the default cross-build architecture (from dpkg-cross).
--testing: Override the default suite (unstable) to use testing
instead. This is a fallback option for use during
toolchain transitions in unstable.
--save-after-login: Allow changes made within the chroot login to persist.
--login-after-fail: In case of error, try to log in to the new chroot.
-- OPTIONS dpkg-buildpackage options
(except: -uc -us [default] -a [ignored])
Although based on pbuilder, empdebuild cannot support the full range of
pbuilder commands or options. In addition, creating a cross-building chroot for
testing involves a variety of changes to the creation of a similar chroot for
unstable so testing is only supported as an override, rather than using the
pbuilder method of a --distribution option.
When testing local changes made with emdebuild, use 'empdebuild --build' which
will use the .diff.gz from the current working directory.
Once the local changes are complete and are committed to Emdebian SVN, you
can use 'empdebuild --autobuild PACKAGE' to ensure that the patches are
usable for the autobuilder.
Options to dpkg-buildpackage can be specified after the -- option.
Note that '-uc' and '-us' are set by default and '-a' will be ignored
(because arch is controlled separately). Options are passed down to
emdebuild unchanged.
EOF
}
function get_cross_depends ()
{
# derived from checkbuilddep_internal
# Use this function to fulfill the cross-dependencies
DEBIAN_XCONTROL=debian/xcontrol
BD_REGEXP="build-depends"
local INSTALLPKG
local INSTALLPKGLIST
local INSTALLPKGMULTI
local CURRENTREALPKGNAME
if [ ! -f ${DEBIAN_XCONTROL} ]; then
return
fi
echo " -> 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