#!/bin/bash

y2pmbuildconfdir=/etc/y2pmbuild
create_package_descr=/opt/kde3/share/apps/krpmview/create_package_descr

: ${builduser:=compiler}
: ${builddebugsolve:=0}

ccache=0
icecream=0
bjobs=1
quilt=0
doinit=1
rpmbuild=rpmbuild
rpmbuildstage=a
target=

success=0;

if [ -z "$BUILD_DIST" ]; then
    have_repo=0;
elif ! . "$y2pmbuildconfdir/dists/$BUILD_DIST" ; then
    have_repo=0
else
    have_repo=1
fi

if [ -z "$buildroot" ]; then
    user=`id -un`
    [ "$user" = root -a -n "$SUDO_USER" -a "$SUDO_USER" != root ] && user="$SUDO_USER"
    buildroot="/var/tmp/build-root.$user"
    [ -n "$BUILD_DIST" ] && buildroot="$buildroot.$BUILD_DIST"
fi

if [ -z "$defaultpackages" ]; then
    defaultpackages="fillup attr acl aaa_base filesystem autoconf automake bash binutils bison bzip2 cpio cpp cracklib cyrus-sasl db devs diffutils e2fsprogs file findutils flex gawk gcc gdbm gdbm-devel gettext glibc glibc-devel glibc-locale gpm grep groff gzip kbd less libgcc libstdc++ libtool libxcrypt zlib m4 make man mktemp modutils ncurses ncurses-devel net-tools netcfg pam pam-devel pam-modules patch perl permissions ps rcs readline rpm sed sendmail shadow strace syslogd sysvinit tar texinfo timezone unzip util-linux vim zlib-devel pwdutils"
fi

neededpackages=

cleanup()
{
    set +e
    trap EXIT
    if [ "$buildroot" != / ]; then
	umount -n $buildroot/proc 2> /dev/null
	umount -n $buildroot/mnt 2> /dev/null
	umount -n $buildroot/dev/pts 2> /dev/null
    fi

    rm -f "$buildroot/.locked"

    if [ "$success" = 0 ]; then
	echo -n "FAILED $spec at " >> "$buildroot/.build.packages"
	date >> "$buildroot/.build.packages"
    fi
}

regenrepository()
{
    [ "$have_repo" != 1 ] && return 0

    local do_regen
    do_regen=1
    [ "$1" = "--init" ] && do_regen=0
    
    install -m 755 -d "$repository"

    [ -z "`echo $repository/*`" ] && do_regen=1

    [ "$do_regen" = "0" ] && return 0
    
    if [ "$regen_repository" = plain ]; then
	pushd .
	cd "$repository"
	genIS_PLAINcache -f -r "$repository"
	popd
    elif [ "$regen_repository" = ul ]; then
	pushd .
	cd "$repository"
	$create_package_descr
	popd
    fi
}

addsourcesfromrepository()
{
    [ "$have_repo" != 1 ] && return 0

    echo "set cachetodisk false"
    echo "_deletemediaatexit"
    echo "set autosource false"

    if [ -n "$url_repository" ]; then
	# doesn't work yet, can't add plainsources with cachetodisk false
	echo "source -a $url_repository"
    fi

    for s in $add_sources; do
	eval src=\$url_$s
	echo "source -a $src"
    done
}

copyfilestorepository()
{
    find "$buildroot/usr/src/packages/RPMS" -type f -printf '\033[1m%p\033[m\n'
    find "$buildroot/usr/src/packages/SRPMS" -type f

    [ "$have_repo" != 1 -o -n "$no_copy_repo" ] && return 0

    rpmdir="$buildroot"/usr/src/packages/RPMS
    while read rpm; do
	dir="$repository"/${rpm%%/*}
	mkdir -p "$dir"
	set -- cp "$rpmdir/$rpm" "$dir"
	echo "$@"
	"$@"
    done < <(find "$rpmdir" -type f -printf '%P\n')

    rpmdir="$buildroot"/usr/src/packages/SRPMS
    while read rpm; do
	dir="$repository"/src
	mkdir -p "$dir"
	set -- cp "$rpmdir/$rpm" "$dir"
	echo "$@"
	"$@"
    done < <(find "$rpmdir" -type f -printf '%P\n')

    regenrepository
}

parse_spec()
{
    file="$1";
    [ ! -e "$file" ] && return 1
    spec_usedforbuild=`grep "^# *usedforbuild" "$file" || true`
    spec_usedforbuild="$spec_usedforbuild `grep "^BuildRequires:" "$file" || true`"
    spec_norootforbuild=`grep "^# *norootforbuild" "$file" || true`

    if [ -z "$spec_norootforbuild" ]; then
	echo -e "\e[34mWARNING: spec file misses 'norootforbuild'\e[m"
    fi
}

# $1 specfile
getneededforbuild()
{
    for i in $spec_usedforbuild; do
	case "$i" in
	\#*)
	;;
	usedforbuild|BuildRequires:)
	;;
	*)
	    neededpackages="$neededpackages $i"
	;;
	esac
    done
    if [ "$ccache" -eq 1 ]; then
	neededpackages="$neededpackages ccache"
    fi
    if [ "$icecream" -gt 0 ]; then
	neededpackages="$neededpackages icecream gcc-c++"
    fi
    if [ "$quilt" -eq 1 ]; then
	neededpackages="$neededpackages quilt"
    fi
}

installpackages()
{
    local logfile
    local instlog
    logfile="$buildroot/.y2log"
    instlog="$buildroot/.y2logRPM"
    y2pmshcmds="$buildroot/.y2pmshcmds"
    > "$logfile"
    > "$instlog"
    cat > "$y2pmshcmds" <<-EOF
	set root $buildroot
	set logfile $logfile
	set instlog $instlog
	set quitonfail 1
	set verbose 1
	EOF

    regenrepository --init

    addsourcesfromrepository >> "$y2pmshcmds"
	
    cat >> "$y2pmshcmds" <<-EOF
	source -s
	set debug $builddebugsolve
	buildsolve $neededpackages $defaultpackages
	set debug 0
	summary
	commit
	EOF

    # don't restart daemons etc.
    export YAST_IS_RUNNING=instsys

    y2pmsh < "$y2pmshcmds"
}

setuptimezone()
{
    # FIXME sucks
    if [ -e "$buildroot/usr/sbin/zic" -a -e "$buildroot/bin/su" -a -e "$buildroot/etc/passwd" ]; then
	chroot "$buildroot" su - -c "/usr/sbin/zic -l GMT"
    else
	install -m 755 -d "$buildroot/etc"
	install -m 644 /etc/localtime "$buildroot/etc/localtime"
    fi
}

runsuseconfig()
{
    echo "SuSEconfig ..."
    chroot "$buildroot" su - -c /sbin/SuSEconfig
}

runldconfig()
{
    echo "ldconfig ..."
    chroot "$buildroot" su - -c /sbin/ldconfig
}

copysourcestobuildroot()
{
    [ "$buildroot" = / ] && return 1
    
    rm -rf "$buildroot"/usr/src/packages

    for i in BUILD RPMS/`arch` RPMS/i386 RPMS/noarch SOURCES SPECS SRPMS; do
	mkdir -p "$buildroot"/usr/src/packages/$i
    done

    find . \( -type f -or -type l \) -and -not -name '.*' -maxdepth 1 \
	-print0 | \
	xargs -0 -iXX cp -p XX "$buildroot"/usr/src/packages/SOURCES/
}

addbuilduser()
{
    > "$buildroot"/etc/profile.d/build_path.sh
    if [ "$builduser" != "root" ]; then
	if ! grep $builduser "$buildroot"/etc/passwd; then
		echo adding user $builduser
		chroot "$buildroot" /usr/sbin/useradd -m $builduser
	fi
	echo adjusting permissions
	chroot "$buildroot" chown -R $builduser.root /usr/src/packages

	echo 'export PATH=/sbin:/usr/sbin:$PATH' >> "$buildroot"/etc/profile.d/build_path.sh
    fi
}

setupccache()
{
    chroot "$buildroot" su - "$builduser" -c "ls -ld ~$builduser"
    if [ "$ccache" = 1 ]; then
	if mkdir -p $buildroot/opt/ccache/bin; then
	    for i in gcc g++ cc c++; do
#		ln -sf /usr/bin/ccache $buildroot/opt/ccache/bin/$i
		rm -f $buildroot/opt/ccache/bin/$i
		test -e $buildroot/usr/bin/$i || continue
		echo '#! /bin/sh' > $buildroot/opt/ccache/bin/$i
		echo "test -e /usr/bin/$i || exit 1" > $buildroot/opt/ccache/bin/$i
	        echo 'export PATH=/opt/icecream/bin:/usr/bin:$PATH' >> $buildroot/opt/ccache/bin/$i
		echo "ccache $i \"\$@\"" >> $buildroot/opt/ccache/bin/$i
		chmod 755 $buildroot/opt/ccache/bin/$i
		echo "Installed ccache wrapper as $buildroot/opt/ccache/bin/$i"
	    done
	fi
	mkdir -p "$buildroot"/.ccache
	chroot "$buildroot" chown -R "$builduser" "/.ccache"
	echo "export CCACHE_DIR=/.ccache" > "$buildroot"/etc/profile.d/build_ccache.sh
	echo 'export PATH=/opt/ccache/bin:$PATH' >> "$buildroot"/etc/profile.d/build_ccache.sh
    else
	chroot "$buildroot" su - -c "rm -f ~$builduser/bin/{gcc,g++,cc,c++}"
	rm -f $buildroot/opt/ccache/bin/{gcc,g++,cc,c++}
    fi
    chroot "$buildroot" su - "$builduser" -c "ls -ld ~$builduser"
}

setupicecream()
{
    if [ "$icecream" -eq 0 ]; then
	rm -rf $buildroot/var/run/icecream
	return
    fi

    if ! rpm -q --root $buildroot icecream >/dev/null 2>/dev/null; then
	echo "*** icecream package not installed ***"
	false
	return
    fi
    
    echo "using icecream with $icecream jobs"

    if [ "$ccache" -ne 1 ]; then
	echo 'export PATH=/opt/icecream/bin:$PATH' >> "$buildroot"/etc/profile.d/build_path.sh
    else
	echo 'export CCACHE_PATH=/opt/icecream/bin' >> "$buildroot"/etc/profile.d/build_path.sh
    fi
    
    local icecc_vers=`cd $buildroot; ls -1 var/run/icecream/*.tar.bz2`

    # only run create-env if compiler or glibc changed
    if [ -z "$icecc_vers" \
	-o ! -e "$buildroot/$icecc_vers" \
	-o "$buildroot/usr/bin/gcc" -nt "$buildroot/$icecc_vers" \
	-o "$buildroot/usr/bin/g++" -nt "$buildroot/$icecc_vers" \
	-o "$buildroot/usr/bin/as" -nt "$buildroot/$icecc_vers" \
	-o "$buildroot/lib/libc.so.6" -nt "$buildroot/$icecc_vers" ]
    then
	rm -rf $buildroot/var/run/icecream
	mkdir -p $buildroot/var/run/icecream
	chroot $buildroot bash -c 'cd /var/run/icecream; /usr/bin/create-env'
	icecc_vers=`cd $buildroot; ls -1 var/run/icecream/*.tar.bz2`
    else
	echo "reusing existing icecream environment /$icecc_vers"
    fi
    echo "export ICECC_VERSION=/$icecc_vers" >> "$buildroot"/etc/profile.d/build_path.sh
}

determinerpmversion()
{
    local a
    local b
    local ver
    read a b ver < <(chroot "$buildroot" rpm --version)
    case "$ver" in
	3*) rpmbuild=rpm ;;
    esac
}

mountfilesystems()
{
    mkdir -p $buildroot/proc
    mkdir -p $buildroot/dev/pts
    pwd
    # -oro doesn't have the desired effect anyways ...
    mount -n -tproc proc $buildroot/proc
    mount -n -tdevpts none $buildroot/dev/pts
}

setmemorylimit()
{
    set -x
    local mem
    while read mem; do
	case "$mem" in
	    MemTotal:*)
		set -- $mem
		eval "mem=\$(($2/3*2))"
		ulimit -v $mem
		echo "Memory limit set to ${mem}KB"
		break;
	    ;;
	esac
    done < <(cat /proc/meminfo) # cat for proc stuff
    set +x
}

helpandquit()
{
    cat <<EOF
Usage: $0 [OPTIONS]

y2pmbuild rebuilds all .spec files in the current directory
    
OPTIONS:
    --ccache		use ccache to speed up rebuilds
    --icecream=N	use N parallel build jobs with icecream
    --jobs=N		use N parallel build jobs
    --quilt		install quilt
    --no-init		do not install any packages, just start compiling
    --no-copy-repo	if called with repository, don't copy to repository
    --target=X          use X as rpm target
    --stage=X           use X as build stage (default: a)
    --help		this screen

EOF
    exit 0
}

parsecmdline()
{
    shortopts=
    longopts=icecream:,jobs:,ccache,root,no-init,quilt,no-copy-repo,help,target:,stage:
    getopt_tmp=`getopt -o "$shortops" --long "$longopts" \
	 -n 'y2pmbuild' -- "$@"`

    if [ $? != 0 ] ; then echo "error parsing command line options" >&2 ; exit 1 ; fi

    eval set -- "$getopt_tmp"

    while true ; do
	case "$1" in
	    --ccache) ccache=1 ; shift ;;
	    --icecream) icecream=$2; bjobs=$icecream ; shift 2 ;;
	    --jobs) bjobs=$2 ; shift 2 ;;
	    --quilt) quilt=1 ; shift ;;
	    --root) builduser=root ; shift ;;
	    --no-init) doinit=0 ; shift ;;
	    --no-copy-repo) no_copy_repo=1 ; shift ;;
	    --help) helpandquit ;;
	    --target) target="$2"; shift 2 ;;
	    --stage) rpmbuildstage="$2"; shift 2 ;;
	    --) shift ; break ;;
	    *) echo "error parsing command line options" ; exit 1 ;;
	esac
    done
}


set -e

unset ${!LC_*}
export LANG=POSIX

parsecmdline "$@"

if [ `id -nu` != "root" ]; then
    echo "only root can build packages this way" >&2
    exit 2
fi

if [ "$buildroot" = / -o -z "$buildroot" ]; then
    echo "invalid build root: $buildroot" >&2
    exit 1
fi

mkdir -p "$buildroot"

if [ ! -e "$buildroot" ]; then
    echo "couldn't create $buildroot" >&2
    exit 1
elif [ ! -d "$buildroot" ]; then
    echo "$buildroot is no directory" >&2
    exit 1
elif [ ! -O "$buildroot" ]; then
    echo "$buildroot is not owned by `id -nu`" >&2
    exit 1
fi

if [ -e "$buildroot/.locked" ]; then
    echo -n "$buildroot already locked by pid " >&2
    cat "$buildroot/.locked" >&2
    exit 1
fi

echo $$ > "$buildroot/.locked"

trap cleanup EXIT

rm -f $buildroot/.build.log
exec > >(tee $buildroot/.build.log) 2>&1

shopt -s nullglob
specfiles=`echo *.spec`

if [ -z "$specfiles" ]; then
    echo "no spec files found" >&2
    exit 1
fi

for spec in "$specfiles"; do

    echo -n "start $spec at " >> "$buildroot/.build.packages"
    date >> "$buildroot/.build.packages"

    parse_spec $spec

    getneededforbuild

    mountfilesystems

    if [ "$doinit" -eq 1 ]; then
	setuptimezone
	installpackages
	runsuseconfig
	runldconfig
    fi

    copysourcestobuildroot

    addbuilduser

    setupicecream

    setupccache

    determinerpmversion

    setmemorylimit

    echo sync ... 
    sync
    echo -----------------------------------------------------------------
    echo "----- building $spec (user $builduser)"
    echo -----------------------------------------------------------------
    echo -----------------------------------------------------------------

    if [ -n "$target" ]; then
	target="--target $target"
    fi

    if [ "$bjobs" -gt 1 ]; then
	bjobs="-D 'jobs $bjobs'"
    else
	bjobs=""
    fi

    chroot "$buildroot" su - $builduser -c "$rpmbuild --nodeps $target $bjobs -b$rpmbuildstage /usr/src/packages/SOURCES/$spec" < /dev/null

    success=1;
    echo -n "done $spec at " >> "$buildroot/.build.packages"
    date >> "$buildroot/.build.packages"

    copyfilestorepository

done

# vim:sw=4
