#!/usr/bin/sudo /bin/sh RPMS_FROM="$HOME/rpm/cleanRPMS.repo" DEST="th" SRC="-n th-x86_64-test" SUFFIX="" CACHEDIR="$PWD/poldekcache" RPMMACROS="" BUILDERRC="" IGNORE="" ignore() { IGNORE="$IGNORE $*"; } NODEBUG=true CLEANAFTER=false FORCE_UMOUNT=false REBUILDDB=false [ -r .cleanbuildrc ] && . ./.cleanbuildrc [ -z "$USER" ] && echo "USER not defined" && exit 1 [ "$USER" == "root" ] && echo "USER must not be root" && exit 1 export LC_ALL=C unset LANGUAGE unset LANG usage() { [ $# -gt 0 ] && echo "$*" echo "Usage:" echo " ./cleanbuild [cleanbuild options] specname [builder options]" echo " ./build [cleanbuild options] specname [builder options]" echo " ./clean [cleanbuild options]" echo " ./create [cleanbuild options]" echo " ./install [cleanbuild options] packages" echo "" echo "cleanbuild options:" echo " -32, -64, -th-i486 - select architecture" echo " --cleanafter | -ca - clean after build" echo " --forceumount | -fu - force umount tmpfs" echo " --debug - enable debug" echo " -a, -b, -c, -d, -e - select alternative chroot directory" exit 1 } FETCH=false CLEAN=false CREATE=false BUILD=false INSTALL=false case "$0" in *clean) CLEAN=exit_after ;; *cleanbuild) FETCH=true CLEAN=true CREATE=true BUILD=true ;; *build) CREATE=true BUILD=true ;; *create) CLEAN=true CREATE=exit_after ;; *install) CREATE=true INSTALL=exit_after ;; *) usage ;; esac while [ $# -gt 0 ]; do OPT="${1}" case "$OPT" in -32) OPT="-th-i686" ;; -64) OPT="-th-x86_64" ;; -th-32) OPT="-th-i686" ;; -th-64) OPT="-th-x86_64" ;; -ti-32) OPT="-ti-i686" ;; -ti-64) OPT="-ti-x86_64" ;; -ac) OPT="-ac-amd64" ;; -ac-32) OPT="-ac-i586" ;; -ac-64) OPT="-ac-amd64" ;; esac V="${OPT#-}" case "$OPT" in -th-i[46]86 | -th-x86_64) DEST="$V" SRC="-n $V-ready" ;; -th-i[46]86-test | -th-x86_64-test) DEST="$V" SRC="-n $V" ;; -ti-i[56]86 | -ti-x86_64) DEST="$V" SRC="-n $V-ready" ;; -ti-i[56]86-test | -ti-x86_64-test) DEST="$V" SRC="-n $V" ;; -ac-amd64 | -ac-i[356]86 | -ac-athlon) DEST="$V" SRC="-n $V-ready" ;; --cleanafter | -ca) CLEANAFTER=true ;; --debug) NODEBUG=false ;; --forceumount | -fu) FORCE_UMOUNT=true ;; -[a-e]) SUFFIX="$OPT" ;; -~*) SUFFIX="$V" ;; *) break ;; esac shift done if $BUILD; then [ $# -ne 0 ] || usage build_pkg="${1}" shift builder_options="$*" fi $NODEBUG || set -x CHNAME="chroot-$DEST$SUFFIX" CHDIR="$PWD/$CHNAME" CHHOME="/home/users/$USER" warn() { echo -n -e "\033[31;1m" >&2 echo -n "$*" >&2 echo -e "\033[0m" >&2 } die() { code=$1 shift warn "$*" exit $code } info() { echo -n -e "\033[32m" echo -n "$*" echo -e "\033[0m" } title() { [ -t 1 ] || return 0 local msg="$CHNAME: $build_pkg: $*" case "$TERM" in cygwin|xterm*) echo -ne "\033]1;$msg\007\033]2;$msg\007" >&2 ;; screen*) echo -ne "\033]0;$msg\007" >&2 ;; esac return 0 } exit_after() { return 0; } check_running() { [ -r "$CHDIR/.pid" ] || return PID=$(< "$CHDIR/.pid") if [ -d /proc/$PID ]; then die 10 "Another process ($PID) already running in $CHNAME" fi } for D in installed buildlogs $CACHEDIR; do if [ ! -d "$D" ]; then info "mkdir $D" su $USER -c "mkdir -p $D" || die 13 "Cannot create work directories" fi done ignore \ vserver-packages \ upstart\* \ xorg-driver-video-fglrx\* xorg-driver-video-nvidia\* xorg-xserver-xgl-libGL \ xorg-data-xbitmaps \ compat-gcc\* \ libpng1\* \ anacron fcron hc-cron \ masqmail msmtp-sendmail omta postfix sendmail ssmtp nail-mail nullmailer \ ghostscript-esp \ \*-multilib-\* \ gnome-speech-driver-festival gnome-speech-driver-speech-dispatcher rebuilddb() { $REBUILDDB && rpm --root=$CHDIR --rebuilddb } poldek() { $NODEBUG || set -x rebuilddb /usr/bin/poldek $SRC -s "$RPMS_FROM" -r "$CHDIR" "--cachedir=$CACHEDIR" --conf=$PWD/poldekconf/poldek.conf "$@" } build_umount() { for DIR in $CHHOME/rpm $CHHOME dev proc sys; do [ -d $CHDIR/$DIR ] && umount $CHDIR/$DIR done } build_remove_root() { $NODEBUG || set -x if $FORCE_UMOUNT; then # safety checks. [ "$CHDIR" ] || exit 1 [ -d "$CHDIR" ] || exit 1 rm -rf $CHDIR/* umount -l $CHDIR else umount $CHDIR fi rmdir $CHDIR } clean() { info "Cleaning $CHNAME" title "cleaning chroot" build_umount build_remove_root } build_prepare_root() { title "preparing chroot" set -e $NODEBUG || set -x mkdir $CHDIR mount -t tmpfs -o size=8G,relatime /dev/null $CHDIR echo $$ > $CHDIR/.pid rpm --root=$CHDIR --initdb poldek --up || : poldek -O "ignore=$IGNORE" -u rpm-build pwdutils coreutils for DIR in dev proc sys; do # We need to create these directories manually, because they are marked # as netsharedpath in cleanbuild poldek.conf mkdir $CHDIR/$DIR mount -o bind /$DIR $CHDIR/$DIR done chroot $CHDIR useradd -m $USER -u$(id $USER -u) # replicate files which already belong to $USER # so they will have correct owner and permissions cp -a $CHDIR/$CHHOME/{tmp,rpm} cp -a $CHDIR/$CHHOME/tmp $CHDIR/BUILD cp -a $CHDIR/$CHHOME/{.bashrc,.rpmmacros} cat <<-'EOM' > $CHDIR/$CHHOME/.rpmmacros %_builddir /BUILD %buildroot %{_builddir}/%{name}-%{version}-root-%(id -u -n) %_rpmdirname cleanRPMS %_rpmdir %{expand:%%global _rpmdir %([ -d %{_topdir}/../%{_rpmdirname} ] && (cd %{_topdir}/../%{_rpmdirname}; pwd) || echo %{_topdir}/%{_rpmdirname})}%_rpmdir %distribution CleanPLD %_binary_payload w1.gzdio EOM [ -z "$RPMMACROS" ] || echo "$RPMMACROS" >> $CHDIR/$CHHOME/.rpmmacros cp -a $CHDIR/$CHHOME/{.bashrc,.builderrc} cat <<-'EORC' > $CHDIR/$CHHOME/.builderrc TITLECHANGE=no EORC [ -z "$BUILDERRC" ] || echo "$BUILDERRC" >> $CHDIR/$CHHOME/.builderrc set +e } build_mount_home() { $NODEBUG || set -x mount -o bind $HOME/rpm $CHDIR/$CHHOME/rpm } print_installed() { echo=$1 if [ -r installed/$build_pkg ]; then $echo "$(cat installed/$build_pkg | awk '{print $1}' | sort -u \ | awk '{br=br ", " $1} END{gsub(/^, /, "- BR: ", br ); print br}')" cat installed/$build_pkg fi } addlist() { LIST="$1" print_installed info return echo "*** $build_pkg $(date --rfc-3339=seconds) ***" >> $LIST print_installed echo >> $LIST } builddie() { LIST="$1"; shift CODE="$1"; shift MSG="$*" rm -f $CHDIR/.pid $CLEANAFTER && clean title "failed !" addlist "ERROR_$LIST" die $CODE "$MSG" } LAST_INSTALL="" poldek_install() { I="$1"; # Nothing to install [ -n "$I" ] || return 1 # Installing same packets second time [ "$LAST_INSTALL" != "$I" ] || return 1 LAST_INSTALL="$I" info "Installing" $I poldek -O "ignore=$IGNORE" -u $I | tee $$.poldek_install ret= if grep -q "Preparing... ##################################################" $$.poldek_install \ && ! grep -q "file .* from install of .* conflicts with file from package" $$.poldek_install then info "Poldek:" $I "installed" ret=0 elif grep -q "Nothing to do" $$.poldek_install; then warn "Poldek:" $I "installed already" ret=1 fi rm $$.poldek_install [ -n "$ret" ] && return $ret # try harder poldek -u $I && return 0 poldek -u $I && return 0 warn "Poldek:" "Could not install" $I return 1 } maybe_call() { local cond="$1"; shift local func="$1"; shift [ $cond == "false" ] && return $func "$@" [ $cond == "exit_after" ] && exit } fetch() { info "Fetching $build_pkg" title "fetch" $NODEBUG || set -x su $USER -c "$HOME/rpm/packages/builder -g $build_pkg $builder_options" \ || die 11 "Fetch failed" } create() { $NODEBUG || set -x su $USER -c "poldek -s $RPMS_FROM --mkidx" if [ ! -d $CHDIR ]; then info "Preparing $CHNAME" build_prepare_root build_mount_home fi } maybe_call $FETCH fetch check_running maybe_call $CLEAN clean maybe_call $CREATE create echo $$ > $CHDIR/.pid maybe_call $INSTALL poldek_install "$*" $BUILD || exit if [ -p /tmp/fixfreq ]; then echo $$ > /tmp/fixfreq fi while true; do info "Building $build_pkg in $CHNAME" rebuilddb buildlog="buildlogs/$build_pkg" if [ -r $buildlog ]; then i=1 while [ -r $buildlog.$i ]; do i=$((i+1)) done info "moving $buildlog to $buildlog.$i" mv $buildlog $buildlog.$i fi ./findunusedbr -c $CHDIR $HOME/rpm/packages/$build_pkg/$build_pkg.spec title "building" { chroot $CHDIR su $USER -c "$CHHOME/rpm/packages/builder -nn -bb $build_pkg $builder_options" < /dev/null 2>&1; echo $? > ecode; } | tee $buildlog ECODE=$(< ecode) rm -f ecode if grep -q "error: Failed build dependencies:" $buildlog; then SEARCH=$(cat $buildlog | awk '/^Error:/ { p = 0 }; { if ( p ) { f="p"; if ( $1 ~ /^\// ) f="f"; printf "search -%c %s; ", f, $1; } }; /error: Failed build dependencies:/ { p = 1 }') INSTALL=$(poldek -O "ignore=$IGNORE" --shcmd="$SEARCH" | awk '{ if ( p ) { print; p = 0; } } / package\(s\) found:$/ { p = 1 }' | sed 's/^\(.*\)-.*-.*$/\1/' | sort -u) if poldek_install "$INSTALL"; then info "Deps installed" continue else addlist ERROR_BRINSTALL die 4 "Cannot install BRs" fi fi ./findbr $CHDIR/BUILD $buildlog > $$.installed installed_something=false while read pkg msg; do if poldek_install $pkg; then info "findbr:" $pkg "installed" echo "$pkg $msg" >> installed/$build_pkg ./addbr $build_pkg "$pkg" "$msg" installed_something=true else warn "findbr:" $pkg "not installed" fi done < $$.installed rm -f $$.installed $installed_something && continue if [ $ECODE -eq 0 ]; then $CLEANAFTER && clean addlist BUILT_OK ./findunusedbr $CHDIR $HOME/rpm/packages/$build_pkg/$build_pkg.spec info "$build_pkg built OK !" title "OK !" exit 0 else builddie UNKNOWN 1 "Got error but dunno what to do !" fi done # vim: ts=4 sw=4 filetype=sh