#!/bin/sh
#---------------------------------------------------------------
# Project         : Mandriva Linux
# Module          : rpm-rebuilder
# File            : rpm-rebuilder
# Version         : $Id: rpm-rebuilder,v 1.29 2005/08/30 21:02:35 gbeauchesne Exp $
# Author          : Frederic Lepied
# Created On      : Wed Feb  2 05:20:56 2000
#---------------------------------------------------------------

exec 3>&1
exec 4>&2

# load global config file
RB_GLOBAL_CONFIG=${RB_GLOBAL_CONFIG=/etc/rpm-rebuilder.conf}
if [ -r "$RB_GLOBAL_CONFIG" ]; then
    . $RB_GLOBAL_CONFIG
fi

# load user config file
RB_USER_CONFIG=${RB_USER_CONFIG=$HOME/.rpm-rebuilder}
if [ -r "$RB_USER_CONFIG" ]; then
    . $RB_USER_CONFIG
fi

## Variables
RPM_REBUILDER_LIB=${RPM_REBUILDER_LIB=/usr/share/rpm-rebuilder}

# modify PYTHON lib path to point to our lib
PYTHONPATH=$RPM_REBUILDER_LIB
export PYTHONPATH

RB_LABORATORY=${RB_LABORATORY=$HOME/rpm-rebuilder}

LOCAL_ARCH=${LOCAL_ARCH:-`uname -m | sed -e "s/\(i.86\|athlon\|k6\)/i386/"`}

# all dirs used in the lab
TODO=${TODO=$RB_LABORATORY/todo}
ORDERED=${ORDERED=$TODO/ordered}
UNORDERED=${UNORDERED=$TODO/unordered}
FAILURE=${FAILURE=$RB_LABORATORY/failure}
SUCCESS=${SUCCESS=$RB_LABORATORY/success}

if [ -n "$CHROOT" ]; then
    RPM_TOP_DIR=${RPM_TOP_DIR=$RB_LABORATORY/RPM}
    CHROOT_DIR=$RB_LABORATORY/root
else
    RPM_TOP_DIR=${RPM_TOP_DIR=/home/builder/rpm}
fi

LAB_DIRS="$TODO $ORDERED $UNORDERED $FAILURE $SUCCESS/log $CHROOT_DIR$RPM_TOP_DIR/SOURCES $CHROOT_DIR$RPM_TOP_DIR/SPECS $CHROOT_DIR$RPM_TOP_DIR/BUILD $CHROOT_DIR$RPM_TOP_DIR/RPMS $CHROOT_DIR$RPM_TOP_DIR/SRPMS"
DONE=$SUCCESS/log

MEDIA=${MEDIA=cooker}
MEDIA_DIR=${MEDIA_DIR=/main}

## Mandriva Linux version specific bits

if [[ -f "/etc/mandrake-release" ]]; then
MDK_VERSION=`perl -ne '/(\d+)\.(\d)\.?(\d)?/ and print $1 * 10000 + $2 * 100 + ($3||0)' /etc/mandrake-release`
fi

if [[ "$MDK_VERSION" -ge "90000" ]]; then
# Force reinstallation of automake 1.4 once we are finished with automake1.6
AUTOMAKE_DEP=${AUTOMAKE_DEP:-"automake-1.4"}
fi

## Functions
## Steps:
#	setup
#	link srpms
#	remove double, already done and exclusive archs
#	build compile order
#	compile
#	move to destination
#	install rpms if requested

## usage

usage() {
    echo "usage: rpm-rebuilder (-c|-C|-j|-l|-o|-x|-d)"
    echo "	-c create the lab"
    echo "	-C clean the lab"
    echo "	-j only compilation phase"
    echo "	-l only link tree phase"
    echo "	-o only order phase"
    echo "	-d only double removal phase"
    echo "	-x abort on compilation failure"
    echo "	-h print this help message"
}

## Step 1: setup
create_dirs() {
    for d in $*; do
	if [ ! -d $d ]; then
	    mkdir -p $d
	fi
    done
}

check_dirs() {
    for d in $*; do
	if [ ! -d $d ]; then
	    echo "$d is not present" 1>&2
	    return 0
	fi
    done
    return 1
}

check_lab() {
    check_dirs $LAB_DIRS

    if [ $? = 0 ]; then
	return 0
    fi
    
    if [ -z "$SRPMS_DIRS" -o ! -d $SRPMS_DIRS ]; then
	echo "no SRPMS_DIRS environment variable or not a dir" 1>&2
	echo "use $RB_USER_CONFIG or $RB_GLOBAL_CONFIG to add locations" 1>&2
	return 0
    fi

    if [ -z "$RPMS_DIRS" ]; then
	echo "no RPMS_DIRS environment variable" 1>&2
	echo "use $RB_USER_CONFIG or $RB_GLOBAL_CONFIG to add locations" 1>&2
	return 0
    fi

    if [ -z "$RPM_TOP_DIR" -o ! -d $CHROOT_DIR$RPM_TOP_DIR ]; then
	echo "no RPM_TOP_DIR environment variable or not a dir" 1>&2
	echo "use $RB_USER_CONFIG or $RB_GLOBAL_CONFIG to add locations" 1>&2
	return 0
    fi
    
    if [ -z "$RPM_DEST_DIR" -o ! -d $RPM_DEST_DIR ]; then
	echo "no RPM_DEST_DIR environment variable or not a dir" 1>&2
	echo "use $RB_USER_CONFIG or $RB_GLOBAL_CONFIG to add locations" 1>&2
	return 0
    fi
    
    return 1
}

create_lab() {
    create_dirs $LAB_DIRS
}

clean_lab() {
    rm -f $ORDERED/* $UNORDERED/* $DONE/* $FAILURE/*
}

## Step2: create link tree
create_link_tree() {
    cd $UNORDERED
    for d in $SRPMS_DIRS; do
	for f in $d/*.src.rpm; do
	    ln -sf $f .
	done
    done
}

## Step3: remove double
remove_dobles() {
    $RPM_REBUILDER_LIB/rpmold $UNORDERED/*.rpm | xargs rm -f
}

remove_done() {
    for d in $RPMS_DIRS; do
	echo "Checking already compiled rpm in $d"
	for f in $d/*.rpm; do
	    if [ ! -f $f ]; then
		echo "$f no more present"
		rm -f $f
		continue
	    fi
	    src=`rpm -qp --queryformat %{SOURCERPM} $f`
	    #echo "checking $f $src"
	    if [ -f $UNORDERED/$src ]; then
		echo "$src already done"
		rm -f $UNORDERED/$src
	    fi
	done
    done
}

remove_arch() {
    for f in $UNORDERED/*.rpm; do
	if [ ! -f "$f" ]; then
	    rm -f "$f"
	    continue
	fi
	archs=`$RPM_REBUILDER_LIB/rpmheader $f EXCLUSIVEARCH|grep -v None`
	echo $archs | grep -q "$LOCAL_ARCH"
	if [ $? -eq 0 -o -z "$archs" ]; then
	    if [ -e $f -a -e $DONE/$f.log ]; then
		echo "`basename $f` done locally"
		rm $f
		continue
	    fi
	else
	    echo "`basename $f` not local arch : `echo $archs|xargs echo`"
	    rm $f
	    continue
	fi
	archs=`$RPM_REBUILDER_LIB/rpmheader $f EXCLUDEARCH|grep -v None`
	echo $archs | grep -q "$LOCAL_ARCH"
	if [ $? = 0 ]; then
	    echo "`basename $f` excludes $LOCAL_ARCH"
	    rm $f
	    continue
	fi
    done
}

## Step3: compile order
# has to be done
BASE_PKGS=""

compile_order() {
    for f in $ORDERED/*.rpm; do
	rm -f $f
    done
    for f in $UNORDERED/*.rpm; do
	# remove dandling symlink
	if [ ! -f $f ]; then
	    echo "$f points to nowhere"
	    rm -f $f
	    continue
	fi
    done
    if [ -n "$ORDERER" ]; then
	# let the external orderer do its job
	$ORDERER $UNORDERED $ORDERED
    else
	for f in $UNORDERED/*.rpm; do
	    # order in 2 groups: base or other
	    name=`rpm -qp --queryformat '%{NAME}' $f`
	    case $name in
		binutils|gcc|egcs) ln -s $f $ORDERED/0base_`basename $f`; echo "$name in base";;
		make|tar|gzip|bzip2|spec-helper|glib|gtk+|qt|glibc|setup|filesystem|basesystem|sed|initscripts|console-tools|utempter|ldconfig|chkconfig|ntsysv|SysVinit|bdflush|crontabs|dev|e2fsprogs|etcskel|fileutils|findutils|getty_ps|grep|gzip|hdparm|info|kernel|less|ldconfig|logrotate|losetup|man|mingetty|modutils|mount|net-tools|passwd|procmail|procps|psmisc|mandrake-release|rootfiles|rpm|sash|ash|setserial|shadow-utils|sh-utils|stat|sysklogd|tar|termcap|textutils|time|tmpwatch|util-linux|vim|vixie-cron|which|perl|msec|lilo|grub|mkbootdisk|isapnptools|aboot|isapnptools|silo|mkbootdisk|kernel-pmac|pdisk|hfsutils) ln -s $f $ORDERED/base_`basename $f`; echo "$name in base";;
		*) ln -s $f $ORDERED/other_`basename $f`;;
	    esac
	done
    fi
}

## Step4: compile all

compile_all() {
    # rebuild the source only if we modify it
    if [ -n "$PKG_MODIFIER" ]; then
	RPM_BUILD_OPT=-ba
    else
	RPM_BUILD_OPT=-bb
    fi
    if [ -n "$CHROOT" ]; then
	CHROOT_ARGS="--root $CHROOT_DIR"
	CHROOT_CMD="sudo $RPM_REBUILDER_LIB/install-chroot-tar.sh $MEDIA $MEDIA_DIR $RB_LABORATORY/root.tar $CHROOT_DIR $UID basesystem rpm-build gcc-c++ urpmi"
    else
	CHROOT_CMD=true
    fi
    for p in $ORDERED/*.src.rpm; do
	NAME=`basename $p`

	# check if a log doesn't already exist
	if [ -e $DONE/$NAME.log ]; then
	    echo "$NAME already compiled"
	    rm -f $p
	    continue
	fi

	# check if source is there
	if [ ! -r $p ]; then
	    continue
	fi

	# check if failure is there
	if [ -r $FAILURE/$NAME.log ]; then
	    echo "$NAME has already failed to compile"
	    continue
	fi
	
	echo -n "processing `basename $p`..."

	$CHROOT_CMD || exit 1

	exec 1> "$CHROOT_DIR$RPM_TOP_DIR/log"
	exec 2>&1

	if [ -z "$CHROOT" ]; then
	    # clean the build area
	    chmod -R +rwx $RPM_TOP_DIR/BUILD/* $RPM_TOP_DIR/SOURCES/* > /dev/null 2>&1
	    rm -rf $RPM_TOP_DIR/BUILD/* $RPM_TOP_DIR/SOURCES/* $RPM_TOP_DIR/SPECS/*
	fi
	
	# install deps and remove conflicts
	if [ -z "$NO_URPMI_DEP" ]; then
	    sudo /usr/sbin/urpmi.update -a < /dev/zero
	    conflicts=""
	    for f in `rpm -qp --qf '[%{CONFLICTNAME}\n]' $p`; do
		[[ -n "$conflicts" ]] && conflicts="$conflicts "
		conflicts="$conflicts$f"
	    done
	    [[ -n $conflicts ]] && {
	        # don't use urpmf as urpmf returns also packages not installed
		conflicts=`rpm -q --whatprovides $conflicts | grep -v 'no package provides' | cut -d':' -f1 | uniq`
		echo "removing $conflicts"
		sudo /usr/sbin/urpme $CHROOT_ARGS --auto $conflicts < /dev/zero
	    }
	    for dep in $AUTOMAKE_DEP `rpm -qp --qf '[%{REQUIRENAME}\n]' $p | fgrep -v 'rpmlib('`; do
		echo "using urpmi to install $dep" < /dev/zero
		sudo /usr/sbin/urpmi $CHROOT_ARGS --auto $dep < /dev/zero
	    done
	fi
	
	# use  --define  "_rpmdir $RPM_DEST_DIR" to put directly the RPMS to the dest dir.
	set -x
	$FAKEROOT $FAKEARCH rpm $CHROOT_ARGS -i --define  "_topdir $RPM_TOP_DIR"  $p < /dev/zero
	status=0
	set +x
	if [ -n "$PKG_MODIFIER" ]; then
	    set -x
	    $PKG_MODIFIER ${CHROOT_DIR}$RPM_TOP_DIR/SPECS/*.spec < /dev/zero
	    status=$?
	    set +x
	fi
	if [ $status -eq 0 ]; then
	    set -x
	    if [ -n "$CHROOT" ]; then
		sudo chroot $CHROOT_DIR su - builder -c "LC_ALL=en $FAKEROOT $FAKEARCH rpm $RPM_BUILD_OPT --clean --rmspec --rmsource --define  \"_topdir $RPM_TOP_DIR\" $RPM_TOP_DIR/SPECS/*.spec" < /dev/zero
	    else
		LC_ALL=en $FAKEROOT $FAKEARCH rpm $RPM_BUILD_OPT --clean --rmspec --rmsource --define  "_topdir $RPM_TOP_DIR" $RPM_TOP_DIR/SPECS/*.spec < /dev/zero
	    fi
	    status=$?
	    set +x
	fi
	if [ $status -eq 0 ]; then
	    echo done 1>&3
	    test -x /usr/bin/rpmlint && rpmlint $CHROOT_DIR$RPM_TOP_DIR/RPMS/*/*.rpm
	    if [ -n "$INSTALL_RPMS" -a -x /usr/bin/sudo ]; then
		if [ -n "$INSTALLER" ]; then
		    $INSTALLER $CHROOT_DIR$RPM_TOP_DIR/RPMS/*/*.rpm
		else
		    echo "Freshing $NAME"
		    sudo /bin/rpm --freshen -vh $CHROOT_DIR$RPM_TOP_DIR/RPMS/*/*.rpm
		fi
	    fi
	    if [ -n "$SAVE_SRPM" -a -d "$SRPM_DEST_DIR" ]; then
		if [ -n "$PKG_MODIFIER" ]; then
		    mv -f $CHROOT_DIR$RPM_TOP_DIR/SRPMS/*.src.rpm $SRPM_DEST_DIR/
		else
		    cp -p $p $SRPM_DEST_DIR/`basename $p|sed -e 's%[^_]*_%%'`
		fi
		$RPM_REBUILDER_LIB/doble -g "$SRPM_DEST_DIR/*.src.rpm" | xargs rm -f
	    fi
	    if [ -n "$REMOVE_MODE" ]; then
		rm -f $CHROOT_DIR$RPM_TOP_DIR/RPMS/*/*
	    else
		if [ -n "$RPM_DEBUG_DEST_DIR" ]; then
		    for f in $CHROOT_DIR$RPM_TOP_DIR/RPMS/*/*-debug-*.rpm; do
			[ -f $f ] && mv -f $f $RPM_DEBUG_DEST_DIR/
		    done
		    $RPM_REBUILDER_LIB/doble -g "$RPM_DEBUG_DEST_DIR/*.rpm" | xargs rm -f
		fi
		if [ -n "$GROUP_RPM" ]; then
		    mkdir $RPM_DEST_DIR/$NAME
		    mv -f $CHROOT_DIR$RPM_TOP_DIR/RPMS/*/* $RPM_DEST_DIR/$NAME/
		else
		    mv -f $CHROOT_DIR$RPM_TOP_DIR/RPMS/*/* $RPM_DEST_DIR
		    $RPM_REBUILDER_LIB/doble -g "$RPM_DEST_DIR/*.rpm" | xargs rm -f
		fi
	    fi
	    mv -f "$CHROOT_DIR$RPM_TOP_DIR/log" "$SUCCESS/log/$NAME.log"
	    $RPM_REBUILDER_LIB/doble -g "$SUCCESS/log/*.log" | xargs rm -f
	    rm -f $p
	else
	    echo failed 1>&3
	    mv -f "$CHROOT_DIR$RPM_TOP_DIR/log" "$FAILURE/$NAME.log"
	    $RPM_REBUILDER_LIB/doble -g "$FAILURE/*.log" | xargs rm -f
	    if [ -n "$ABORT_ON_FAILURE" ]; then
		exit
	    fi
	fi
	exec 1>&3
	exec 2>&4
    done
}

## Process command line options
for arg in $*; do
    case $arg in
	-c) create_lab; exit 0;;
	-C) clean_lab; exit 0;;
	-l) create_link_tree; exit $?;;
	-d) remove_dobles && remove_done && remove_arch; exit $?;;
	-o) compile_order; exit $?;;
	-j) check_lab $LAB_DIRS || compile_all; exit $?;;
	-x) ABORT_ON_FAILURE=1;;
	-h) usage; exit 0;;
	*) usage; exit 1;;
    esac
done

if check_lab $LAB_DIRS; then
    echo "Invalid laboratory. use `basename $0` -c to create one under $RB_LABORATORY" 2>&1
    exit 1
fi

echo "Building link tree"
create_link_tree

echo "Removing dobles"
remove_dobles

echo "Removing already compiled packages"
remove_done

echo "Removing exclusive arch packages"
remove_arch

echo "Building compile order"
compile_order

echo "Compiling all"
compile_all

# rpm-rebuilder ends here
