#!/bin/sh -e
#
# $Id: rebuild,v 1.67 2005/08/01 12:33:55 ldv Exp $
# Copyright (C) 2003-2005  Dmitry V. Levin <ldv@altlinux.org>
# 
# The rebuild utility for the hasher project
#
# This file 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

if [ "$0" = ./rebuild ]; then
	. ./functions
	hasher_dir="$(/bin/pwd)"
else
	. /usr/share/hasher/functions
fi

show_help()
{
	cat <<EOF
rebuild - rebuild source packages.

Usage: $PROG [options] <path-to-workdir> <source-package>

<path-to-workdir> must be valid writable directory.

Valid options are:
  --args=ARGS                       extra arguments for rpmbuild;
  --excludedocs                     do not install documentation files;
  --hasher-priv-dir=DIR             hasher-priv directory;
  --mountpoints=LIST                comma-separated list of known mount points;
  --nodeps                          ignore package dependencies (dangerous);
  --no-sisyphus-check-in[=LIST]     do not run sisyphus_check input tests [specified in LIST];
  --no-sisyphus-check[=LIST]        do not run sisyphus_check tests [specified in LIST];
  --no-sisyphus-check-out[=LIST]    do not run sisyphus_check output tests [specified in LIST];
  --number=NUMBER                   subconfig identifier;
  --query-repackage                 repackage the source before query for requirements;
  --query-req-prog=FILE             program to run to query for requirements instead of autogenerated script;
  --rebuild-prog=FILE               program to run for rebuild instead of autogenerated script;
  --repo=DIR                        repository directory;
  --save-fakeroot                   save fakeroot state;
  --target=ARCH                     target architecture;
  --without-stuff                   do not generate apt index files;
  --with-stuff                      generate apt index files;
  -q, --quiet                       try to be more quiet;
  -v, --verbose                     print a message for each action;
  -V, --version                     print program version and exit;
  -h, --help                        show this text and exit.
    
Report bugs to http://bugs.altlinux.ru/

EOF
	exit
}

TEMP=`getopt -n $PROG -o h,q,v,V -l args:,excludedocs,hasher-priv-dir:,mountpoints:,nodeps,no-sisyphus-check::,no-sisyphus-check-in::,no-sisyphus-check-out::,no-stuff,number:,query-repackage,query-req-prog:,rebuild-prog:,repo:,save-fakeroot,target:,without-stuff,with-stuff,help,quiet,verbose,version -- "$@"` ||
	show_usage
eval set -- "$TEMP"

known_mountpoints=
nodeps=
prog_query_req=
prog_rebuild=
query_repackage=
required_mountpoints=
rpmargs=
while :; do
	case "$1" in
		--args) shift; rpmargs="$1"
			;;
		--excludedocs) exclude_docs=--excludedocs
			;;
		--hasher-priv-dir)
			hasher_priv_dir="$(opt_check_dir "$1" "$2")"
			shift
			;;
		--mountpoints) shift; known_mountpoints="$1"
			;;
		--nodeps) nodeps=--nodeps
			;;
		--no-sisyphus-check) shift
			[ -n "$1" ] && no_sisyphus_check="$1" || no_sisyphus_check=all
			;;
		--no-sisyphus-check-in) shift
			[ -n "$1" ] && no_sisyphus_check_in="$1" || no_sisyphus_check_in=all
			;;
		--no-sisyphus-check-out) shift
			[ -n "$1" ] && no_sisyphus_check_out="$1" || no_sisyphus_check_out=all
			;;
		--number)
			number="$(opt_check_number "$1" "$2")"
			shift
			;;
		--query-repackage) query_repackage=1
			;;
		--query-req-prog)
			prog_query_req="$(opt_check_read "$1" "$2")"
			shift
			;;
		--rebuild-prog)
			prog_rebuild="$(opt_check_read "$1" "$2")"
			shift
			;;
		--repo) shift; repo="$1"
			;;
		--save-fakeroot) save_fakeroot=1
			;;
		--target) shift; target="$1"
			[ -z "${target##[A-Za-z]*}" ] ||
				Fatal "--target: $target: invalid architecture."
			;;
		--without-stuff|--no-stuff) no_stuff=1
			;;
		--with-stuff) no_stuff=
			;;
		--) shift; break
			;;
		*) parse_common_options rebuild "$1"
			;;
	esac
	shift
done

if [ -n "$prog_query_req" -a -n "$query_repackage" ]; then
	show_usage '--query-req-prog and --query-repackage are mutually exclusive options.'
fi

# Exactly two arguments, please.
[ "$#" -ge 2 ] || show_usage 'Insufficient arguments.'
[ "$#" -le 2 ] || show_usage 'Too many arguments.'

set_workdir "$1"
shift

source="$1"
[ -z "${source##/*}" ] || source="$saved_cwd/$source"

sname="${source##*/}"
shift

[ -d "$chroot" ] || Fatal "$chroot: cannot find chroot."

check_helpers

# Create rebuild script.
if [ -n "$prog_rebuild" ]; then
	install -p -m755 $verbose "$prog_rebuild" chroot/.host/rebuild
else
	cat >"chroot/.host/rebuild" <<__EOF__
#!/bin/sh -le
exec nice time rpmbuild --rebuild $nodeps --target="$(quote_arg "${target:-$def_target}")" $rpmargs "\$@"
__EOF__
	chmod 755 "chroot/.host/rebuild"
	Verbose 'Created rebuild script.'
fi

# Copy source to chroot.
copy_chroot_incoming "$source"

# Execute sisyphus_check.
[ -n "$no_sisyphus_check_in" ] ||
	no_sisyphus_check_in="$no_sisyphus_check"
if [ "$no_sisyphus_check_in" != all ]; then
	[ -n "$no_sisyphus_check_in" ] ||
		no_sisyphus_check_in=gpg

	create_entry_header
	cat >>"$entry" <<__EOF__
mkdir -p $verbose -m700 -- "\$TMPDIR"
sisyphus_check --no-check="$(quote_arg "$no_sisyphus_check_in")" /.in
__EOF__

	wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_long wlimit_bytes_written=$wlimit_bytes_out \
	    chrootuid2 &&
		Verbose "$sname: sisyphus_check passed." ||
		Fatal "$sname: sisyphus_check failed."
fi

# Calculate, check and install build dependencies.
if [ -z "$nodeps" ]; then
	# Create query script.
	if [ -n "$prog_query_req" ]; then
		install -p -m755 $verbose "$prog_query_req" chroot/.host/query_req
	elif [ -n "$query_repackage" ]; then
		cat >chroot/.host/query_req <<__EOF__
#!/bin/sh -e
rpmi -i -- "\$@"
cd \`rpm --eval %_specdir\`
rpmbuild -bs --nodeps $rpmargs -- *.spec >/dev/null
cd \`rpm --eval %_srcrpmdir\`
rpmquery -pR -- "\$@"
__EOF__
	else
		cat >chroot/.host/query_req <<__EOF__
#!/bin/sh -e
rpmquery -pR -- "\$@"
__EOF__
	fi
	chmod 755 chroot/.host/query_req

	create_entry_header
	cat >>"$entry" <<__EOF__
/.host/query_req "$(quote_arg "$sname")"
__EOF__

	deps="$(wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short wlimit_bytes_written=$wlimit_bytes_out \
		    chrootuid2)" &&
		Verbose "$sname: fetched build dependencies." ||
		Fatal "$sname: failed to fetch build dependencies."
	deps="$(printf %s "$deps" |grep -v '^rpmlib(' |LC_ALL=C tr -d [[:blank:]])"
	if bad_deps="$(printf %s "$deps" |LC_ALL=C grep -v '^[[:alnum:]_/]')"; then
		Fatal "$sname: invalid build dependencies: $bad_deps"
	fi
	Verbose "$sname: calculated build dependencies: $deps"

	if [ -n "$known_mountpoints" ]; then
		for file_deps in `printf %s "$deps" |LC_ALL=C grep '^/' |LC_ALL=C sort -u`; do
			for mpoint in $(printf %s "$known_mountpoints" |tr -s , ' '); do
				if [ "$mpoint" = "$file_deps" ]; then
					[ -z "$required_mountpoints" ] &&
						required_mountpoints="$mpoint" ||
						required_mountpoints="$required_mountpoints,$mpoint"
					break
				fi
			done
		done
		Verbose "$sname: calculated mount points: $required_mountpoints"
	fi

	if [ -n "$deps" ]; then
		"$hasher_dir/install" \
			${quiet:+$quiet} \
			${verbose:+$verbose} \
			${number:+--number=$number} \
			${exclude_docs:+--excludedocs} \
			${save_fakeroot:+--save-fakeroot} \
			${hasher_priv_dir:+--hasher-priv-dir="$hasher_priv_dir"} \
			-- \
			"$workdir" $deps

		copy_chroot_incoming "$source"
	fi
fi

# Calculate required mountpoints from installed file dependencies.
if [ -z "$nodeps" -a -n "$known_mountpoints" ]; then
	create_entry_header
	cat >>"$entry" <<__EOF__
rpmquery -aR |grep ^/ |sort -u
__EOF__

	deps="$(wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short wlimit_bytes_written=$wlimit_bytes_out \
		    chrootuid2)" &&
		Verbose "$sname: fetched installed file dependencies." ||
		Fatal "$sname: failed to fetch installed file dependencies."
	deps="$(printf %s "$deps" |grep ^/ |LC_ALL=C tr -d [[:blank:]])"

	for file_deps in $deps; do
		for mpoint in $(printf %s "$known_mountpoints" |tr -s , ' '); do
			if [ "$mpoint" = "$file_deps" ]; then
				[ -z "$required_mountpoints" ] &&
					required_mountpoints="$mpoint" ||
					required_mountpoints="$required_mountpoints,$mpoint"
				break
			fi
		done
	done
	required_mountpoints="$(printf %s "$required_mountpoints" |tr -s , '\n' |LC_ALL=C sort -u |tr -s '\n' ,)"
	required_mountpoints="${required_mountpoints%,}"
	Verbose "$sname: calculated mount points: $required_mountpoints"
fi

# Build the package.
purge_chroot_out

create_entry_header
cat >>"$entry" <<__EOF__
mkdir -p $verbose -m700 -- "\$TMPDIR"
cat >>/usr/src/.rpmmacros <<EOF
%packager \$(rpmquery -p --qf '%{PACKAGER}' "$(quote_arg "$sname")")
EOF

/.host/rebuild "$(quote_arg "$sname")"
find /usr/src/RPM/SRPMS/ -mindepth 1 -maxdepth 1 -type f -name \*.src.rpm -print0 |
	xargs -r0 mv --reply=yes $verbose --target-directory=/.out/ --
find /usr/src/RPM/RPMS/ -mindepth 2 -maxdepth 2 -type f -name \*.rpm -print0 |
	xargs -r0 mv --reply=yes $verbose --target-directory=/.out/ --
__EOF__

mountpoints="$required_mountpoints" \
    chrootuid2 &&
	Verbose "rebuild of \`$sname' complete." ||
	Fatal "rebuild of \`$sname' failed."

# Execute sisyphus_check.
[ -n "$no_sisyphus_check_out" ] ||
	no_sisyphus_check_out="$no_sisyphus_check"
if [ "$no_sisyphus_check_out" != all ]; then
	[ -n "$no_sisyphus_check_out" ] &&
		no_sisyphus_check_out="$no_sisyphus_check_out,gpg" ||
		no_sisyphus_check_out=gpg
	create_entry_header
	cat >>"$entry" <<__EOF__
sisyphus_check --no-check="$(quote_arg "$no_sisyphus_check_out")" /.out
__EOF__

	wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_long wlimit_bytes_written=$wlimit_bytes_out \
	    chrootuid2 &&
		Verbose "$sname: sisyphus_check passed." ||
		Fatal "$sname: sisyphus_check failed."
fi

# Copy binaries from chroot.
make_repo

case `find chroot/.out/ -mindepth 1 -maxdepth 1 -type f -name \*.src.rpm |grep -c '\.src\.rpm$'` in
	0)
		find chroot/.in/ -mindepth 1 -maxdepth 1 -type f -name \*.src.rpm -print0 |
			xargs -r0 mv --reply=yes $verbose --target-directory=${repo:-$def_repo}/SRPMS.hasher/ --
		;;
	1)
		find chroot/.out/ -mindepth 1 -maxdepth 1 -type f -name \*.src.rpm -print0 |
			xargs -r0 mv --reply=yes $verbose --target-directory=${repo:-$def_repo}/SRPMS.hasher/ --
		;;
	*)
		Fatal 'Too many src.rpm files written.'
		;;
esac
find chroot/.out/ -mindepth 1 -maxdepth 1 -type f -name \*.rpm -print0 |
	xargs -r0 mv --reply=yes $verbose --target-directory=${repo:-$def_repo}/"${target:-$def_target}"/RPMS.hasher/ --

purge_chroot_in
purge_chroot_out

update_repo
