#!/bin/sh -e
#
# Copyright (C) 2003-2005  Dmitry V. Levin <ldv@altlinux.org>
# Copyright (C) 2005  Anton D. Kachalov <mouse@altlinux.org>
# Copyright (C) 2006-2007  Konstantin A. Lepikhov <lakostis@altlinux.org>
# Copyright (C) 2006-2007  Alexey S. Gladkov <legion@altlinux.org>
# 
# This file defines functions used by spt scripts.
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#

PROG="${0##*/}"

Info()
{
	printf %s\\n "$PROG: $*" >&2
}

verbose=
Verbose()
{
	[ -n "$verbose" ] || return 0
	Info "$*"
}

Fatal()
{
	printf %s\\n "$PROG: Fatal $*" >&2
	exit 1
}

print_version()
{
	local prog="$1" && shift
	cat <<EOF
$prog version 0.6.0
Written by Anton D. Kachalov <mouse@altlinux.org>
Modified by Konstantin A. Lepikhov <lakostis@altlinux.org>
Modified by Alexey S. Gladkov <legion@altlinux.org>

Copyright (C) 2005  Anton D. Kachalov <mouse@altlinux.org>
Copyright (C) 2006-2007  Konstantin A. Lepikhov <lakostis@altlinux.org>
Copyright (C) 2006-2007  Alexey S. Gladkov <legion@altlinux.org>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
	exit
}

show_usage()
{
	[ -z "$*" ] || Info "$*"
	printf %s\\n "Try \`$PROG --help' for more information." >&2
	exit 1
}

remkdir()
{
	rm -rf -- "$1"
	mkdir -- "$1"
}

workdir=
chroot_run()
{
		local out
		if ! out="$(hsh-run $verbose $quiet ${number:+--number="$number"} --rooter "$workdir" -- "$@" 2>&1)"; then
				printf %s\\n "$out" >&2
				Fatal 'failed to run cmd in chroot.'
		fi
}

workdir=
chroot_exec()
{
		local out
		local script="$1"
		if ! out="$(hsh-run $verbose $quiet ${number:+--number="$number"} --rooter --execute="$script" "$workdir" 2>&1)"; then
				printf %s\\n "$out" >&2
		fi
}

workdir=
chroot_mkdev()
{
		# Create essential tty devices.
		echo "\
600 /dev/console c 5 1
600 /dev/tty0 c 4 0
666 /dev/tty c 5 0
666 /dev/ptmx c 5 2" |
		while read mode name type major minor ; do
			hsh-fakedev $verbose $quiet ${number:+--number="$number"} -o root -m "$mode" "$workdir" "$name" "$type" "$major" "$minor" ||
				Fatal 'Failed to create tty devices.'
		done
}

quiet=
verbose=
workdir=
init_chroot_progs()
{
    # These directories may confuse users. We need to help them.
    rm -rf -- "$workdir/repo"

    hsh "$workdir" $quiet $verbose $excludedocs \
         ${ARCH:+--target="$ARCH"} \
         ${LANGS:+--install-langs="$LANGS"} \
         ${apt_config:+--apt-config=$apt_config} \
         ${apt_prefix:+--apt-prefix=$apt_prefix} \
	 ${number:+--number="$number"} \
         --initroot-only \
         --save-fakeroot \
	 --without-stuff \
         --pkg-init-list="setup filesystem rpm fakeroot>=0:0.7.3 findutils tar sed awk $*" \
         --pkg-build-list=',' ||
	 	Fatal 'Failed to initialize boot.'
    rm -rf -- "$workdir/repo"
}

workdir=
gen_aptbox()
{
	local dir
	[ "$#" -eq 0 ] &&
		dir="$workdir" ||
		dir="$1"
	rm -rf -- "$dir/aptbox"
	mkaptbox "$dir" $quiet $verbose \
	     ${target:+--target="$ARCH"} \
	     ${apt_config:+--apt-config="$apt_config"} \
	     ${apt_prefix:+--apt-prefix="$apt_prefix"}
}

chroot=
postinstall()
{
	local script scrname identdir
	identdir="$1" && shift
	[ -d "$identdir/hooks.d" ] || return 0

	chroot_run chown root:root /
	chroot_run chmod 755 /

	for script in "$identdir/hooks.d"/*; do
		[ "$script" != "$identdir/hooks.d/*" ] || break
		[ -x "$script" ] || continue
		scrname=${script##*/}

		cp -aL -- "$script" "$chroot/.host/$scrname-run"
		cat >"$chroot/.host/spt-hook"<<EOF
#!/bin/sh -efu
export IDENT="${IDENT:-}" NAME="${NAME:-}" ORIGIN="${ORIGIN:-}" LABEL="${LABEL:-}" ARCH="${ARCH:-}" VENDOR="${VENDOR:-}"
export INSTALLDIR="${INSTALLDIR:-}" IMGDIR="${imgdir:-}" ISODIR="${isodir:-}" THEME="${THEME:-}" VERSION="${VERSION:-}"
/.host/$scrname-run
EOF
		chmod +x "$chroot/.host/spt-hook"
		chroot_run "/.host/spt-hook" &&
			Verbose "$scrname done" ||
			Verbose "$scrname fail"
		rm -f -- "$chroot/.host/$scrname-run"
	done
	[ ! -f "$chroot/.host/spt-hook" ] ||
		rm -f -- "$chroot/.host/spt-postinstall"
}

# assumed: defined aptbox
APT_Get_PrintLocalFile=
print_uris()
{
	local out
	[ -d "$tmpdir/aptbox" ] || gen_aptbox "$tmpdir" >/dev/null 2>&1

	aptbox="$tmpdir/aptbox"
	if ! out="$("$aptbox/apt-get" -q -y --print-uris install -- "$@" 2>&1)"; then
		printf %s\\n "$out" >&2
		Fatal 'failed to calculate package file list.'
	fi

	local all_pattern="'\\([a-z]\\+\\):\\([^']\\+\\)' .*"
	local local_pattern="'\\(file\\|copy\\):\\([^']\\+\\)' .*"

	local all_uris
	if ! all_uris="$(printf %s "$out" |sed -ne "s/^$all_pattern/\\2/pg")"; then
		printf %s\\n "$out" >&2
		Fatal 'failed to filter package file list.'
	fi

	local local_uris cached_uris=
	if ! local_uris="$(printf %s "$out" |sed -ne "s/^$local_pattern/\\2/pg")"; then
		printf %s\\n "$out" >&2
		Fatal 'failed to filter package file list.'
	fi

	if [ "$all_uris" != "$local_uris" ]; then
		if [ -z "$APT_Get_PrintLocalFile" ]; then
			if ! out="$("$aptbox/apt-get" -o APT::Get::PrintLocalFile=yes -q -y --print-uris install -- "$@" 2>&1)"; then
				printf %s\\n "$out" >&2
				Fatal 'calculated package file list is not local and apt-get does not support APT::Get::PrintLocalFile option.'
			fi

			if ! cached_uris="$(printf %s "$out" |sed -ne "s/^$all_pattern/\\2/pg")" ||
			   [ -n "$cached_uris" ]; then
				printf %s\\n "$out" >&2
				Fatal 'calculated package file list is not local and apt-get does not support APT::Get::PrintLocalFile option.'
			fi

			APT_Get_PrintLocalFile=1
		fi

		if [ -n "$verbose" ]; then
			"$aptbox/apt-get" -y -d install -- "$@" >&2 ||
				Fatal 'failed to download packages from calculated package file list.'
		else
			if ! out="$("$aptbox/apt-get" -y -d install -- "$@" 2>&1)"; then
				printf %s\\n "$out" >&2
				Fatal 'failed to download packages from calculated package file list.'
			fi
		fi

		if ! out="$("$aptbox/apt-get" -o APT::Get::PrintLocalFile=yes -q -y --print-uris install -- "$@" 2>&1)"; then
			printf %s\\n "$out" >&2
			Fatal 'failed to calculate local package file list.'
		fi

		if ! cached_uris="$(printf %s "$out" |grep ^/)" || [ -z "$cached_uris" ]; then
			printf %s\\n "$out" >&2
			Fatal 'failed to calculate local package file list.'
		fi
	fi

	if [ -n "$cached_uris" ]; then
		[ -n "$local_uris" ] && local_uris="$local_uris
$cached_uris" || local_uris="$cached_uris"
	fi

	printf %s "$local_uris" &&
		Verbose 'calculated package file list.'
}
