#!/bin/sh
set -e
. /usr/share/debconf/confmodule

# Avoid perl warnings in any of the chroot calls below
export LANG=C

REMOUNT_CD=""

DIVERTS=""
for divert in /usr/bin/fc-cache /usr/sbin/update-initramfs; do
	if ! chroot /target dpkg-divert --listpackage $divert | grep -q .; then
		DIVERTS="$DIVERTS $divert"
	fi
done

log() {
	logger -t pkgsel "$@"
}
warning() {
	log "warning: $@"
}

cleanup() {
	for divert in $DIVERTS; do
		rm -f "/target$divert"
		log-output -t pkgsel chroot /target dpkg-divert \
			--package pkgsel --rename --quiet --remove "$divert"
	done
}

aptfailed() {
	ret=$?
	if [ "$ret" != 0 ]; then
		# In case packages failed to install, try to clean up.
		in-target dpkg --configure -a || true

		# TODO useful error message here (for ret != 30)
		db_progress INFO pkgsel/progress/cleanup
		if ! cleanup; then
			log "cleanup failed"
		fi
		db_progress STOP
		load_install_cd
		exit $ret
	fi
}

load_install_cd() {
	if [ "$REMOUNT_CD" ]; then
		load-install-cd "/target" || true
	fi
}

check_language_support=false

langsupport_on_cd() {
	if $check_language_support; then
		for l; do
			if [ -z "$(chroot /target check-language-support -l "$l" || true)" ]; then
				return 1
			fi
		done
	else
		for l; do
			if ! [ "$(chroot /target apt-cache -n search "^language-support-$l\$")" ]; then
				return 1
			fi
		done
	fi
	return 0
}

have_networking() {
	# This is a nasty way to check whether we ought to have a network
	# connection; if we don't, it isn't worthwhile to ask whether to
	# download language support. We should really change netcfg to write
	# out a flag somewhere.
	! db_get netcfg/dhcp_options || [ "${RET#Do not configure}" = "$RET" ]
}

db_progress START 0 1000 debian-installer/pkgsel/title
db_progress INFO pkgsel/progress/init

# d-i debconf variables used by packages
debconf-copydb -p \
	"^(debian-installer/language|debian-installer/country|debian-installer/keymap|passwd/username)$" \
	configdb target_configdb

# temporarily divert programs that take a long time
for divert in $DIVERTS; do
	log-output -t pkgsel chroot /target dpkg-divert --package pkgsel \
		--rename --quiet --add "$divert"
	ln -sf /bin/true "/target$divert"
done

# get debconf-apt-progress config, which will make it run properly later
config=$(chroot /target debconf-apt-progress --config| sed "s/$/;/")

db_progress STEP 10

# We only want to ask this at high priority on server or netboot
# installations. Gross ...
if [ ! -d /cdrom/.disk ] || grep -iq server /cdrom/.disk/info; then
	update_priority=high
else
	update_priority=medium
fi

# Unmount the installation CD to allow CD changing; as it may be needed
# again after pkgsel, make sure it is reloaded before exiting
if [ -e /var/lib/install-cd.id ]; then
	log-output -t pkgsel umount /cdrom || true
	REMOUNT_CD=1
fi

# Install tasksel itself.  This isn't part of the base system because then
# we'd have to include it on live CDs that don't otherwise need it.
in-target sh -c "debconf-apt-progress --from 10 --to 50 --logstderr -- apt-get -q -y install tasksel" || ret=$?
if [ "$ret" != 0 ]; then
	# In case packages failed to install, try to clean up.
	in-target dpkg --configure -a || true
fi


db_get pkgsel/upgrade
if [ "$RET" = none ]; then
	tasksel_start=50
else
	upgrade_type="$RET"
	# Convert to apt-get command names.
	case "$RET" in
	safe-upgrade) upgrade_type=upgrade;;
	full-upgrade) upgrade_type=dist-upgrade;;
	esac
	db_progress INFO pkgsel/progress/upgrade
	sleep 2 # allow the message to be seen

	log "checking for (security) updates to the base system"
	# Exclude Recommends to avoid installing new packages as part of
        # an upgrade.
	in-target sh -c "debconf-apt-progress --from 50 --to 100 --logstderr -- apt-get -q --no-install-recommends -y -o DPkg::options=--force-confnew '$upgrade_type'" || aptfailed
	tasksel_start=100
fi

partsdir="/usr/lib/pre-pkgsel.d"
if [ -d "$partsdir" ]; then
	log "running pre-pkgsel hook scripts"

	scriptcount=$(ls "$partsdir"/* 2>/dev/null | wc -l)
	if [ $scriptcount -lt 10 ]; then
		scripts_range=$(($scriptcount * 10))
	else
		scripts_range=100
	fi
	scripts_start=$tasksel_start
	tasksel_start=$(($scripts_start + $scripts_range))

	scriptcur=0
	for script in $(ls "$partsdir"/* 2>/dev/null); do
		base=$(basename $script | sed 's/[0-9]*//')
		if ! db_progress INFO pkgsel/progress/$base; then
			db_subst pkgsel/progress/fallback SCRIPT "$base"
			db_progress INFO pkgsel/progress/fallback
		fi
		if [ -x "$script" ]; then
			# be careful to preserve exit code
			if log-output -t pkgsel "$script"; then
				:
			else
				warning "$script returned error code $?"
			fi
		else
			error "Unable to execute $script"
		fi

		# Advance progress bar
		scriptcur=$(($scriptcur + 1))
		db_progress SET $(($scripts_start + $scripts_range * $scriptcur / $scriptcount))
	done
fi

# Work out what we need to install.

db_input "$update_priority" pkgsel/update-policy || true
db_go || true
db_get pkgsel/update-policy
if [ "$RET" = unattended-upgrades ]; then
	echo 'unattended-upgrades unattended-upgrades/enable_auto_updates boolean true' | \
		log-output -t pkgsel chroot /target debconf-set-selections || \
		true
	apt-install unattended-upgrades || true
elif [ "$RET" = landscape ]; then
	echo 'landscape-client landscape-client/register_system boolean true' | \
		log-output -t pkgsel chroot /target debconf-set-selections || \
		true
	apt-install landscape-client || true
fi

locale_to_language_pack () {
	local lang="${1%%.*}"
	case $lang in
	    zh_CN)	echo zh-hans ;;
	    zh_TW)	echo zh-hant ;;
	    *)		echo "${lang%%_*}" ;;
	esac
}

if (db_fget pkgsel/language-packs seen && [ "$RET" = true ]) || \
   (db_get pkgsel/language-packs && [ "$RET" ]); then
	db_get pkgsel/language-packs
	if [ "$RET" = ALL ]; then
		langpacks="$(chroot /target apt-cache -n search '^language-pack-[^-][^-]*$' | sed 's/^language-pack-//; s/ .*//')"
	else
		langpacks="$(echo "$RET" | sed 's/,//g')"
	fi
else
	supported=
	if db_get localechooser/supported-locales; then
		supported="$RET"
	fi
	db_get debian-installer/locale
	langpacks="$(for loc in $(echo "$RET $supported" | sed 's/,//g'); do
		locale_to_language_pack "$loc"
	done | sort -u)"
fi

if db_fget pkgsel/install-language-support seen && [ "$RET" = true ] && \
   db_get pkgsel/install-language-support && [ "$RET" = false ]; then
	check_language_support=:
	langsupport=false
else
	# Get check-language-support installed
	apt-install language-selector-common || true
	if chroot /target which check-language-support >/dev/null 2>&1; then
		check_language_support=:
	fi

	if [ -f /cdrom/.disk/base_installable ] && \
	   ! langsupport_on_cd $langpacks; then
		log "language-support packages not available on CD"
		if have_networking; then
			db_capb
			db_input high pkgsel/install-language-support || true
			db_go || true
			db_capb backup
		else
			log "... but no network is available"
		fi
	fi
	db_get pkgsel/install-language-support
	langsupport="$RET"
fi

if [ "$langpacks" ]; then
	db_get pkgsel/language-pack-patterns
	lppatterns="$RET"
	numpacks="$(set -- $langpacks; echo $#)"
	numpatterns="$(set -- $lppatterns; echo $#)"
	numpatterns="$(($numpatterns + 1))" # for basic language packs
	if [ "$langsupport" = true ]; then
		numpatterns="$(($numpatterns + 1))"
	fi
	numlangs="$(($numpacks * $numpatterns))"
fi

# Install basic language packs, required to get localisation working at all.
# We install these almost unconditionally; if you want to get rid of even
# these, you can preseed pkgsel/language-packs to the empty string.
curlang=0
for lp in $langpacks; do
	min="$(($tasksel_start + 10 * $curlang / $numpacks))"
	curlang="$(($curlang + 1))"
	max="$(($tasksel_start + 10 * $curlang / $numpacks))"
	ret=0
	in-target sh -c "$config debconf-apt-progress --from $min --to $max --logstderr -- apt-get -o APT::Install-Recommends=false -q -y install 'language-pack-$lp'" || ret=$?
	if [ "$ret" != 0 ]; then
		# In case packages failed to install, try to clean up.
		in-target dpkg --configure -a || true
	fi
done
if [ "$langpacks" ]; then
	tasksel_start="$(($tasksel_start + 10))"
fi

db_get pkgsel/include
if [ "$RET" ]; then
	tasksel_end=800
else
	tasksel_end=850
fi

log "starting tasksel"
db_progress INFO pkgsel/progress/tasksel
in-target sh -c "tasksel --new-install --debconf-apt-progress='--from $tasksel_start --to $tasksel_end --logstderr'" || aptfailed

# Move final sources.list into place, if necessary, so that language packs
# and pkgsel/include items that aren't on the CD can be installed.
if [ -f /target/etc/apt/sources.list.apt-setup ]; then
	mv -f /target/etc/apt/sources.list.apt-setup \
		/target/etc/apt/sources.list
	in-target apt-get -o APT::Get::Download=false update || true
fi

if db_get pkgsel/include/install-recommends; then
	log "The template pkgsel/include/install-recommends is no longer used; please use base-installer/install-recommends instead"
fi

db_get pkgsel/include
if [ "$RET" ]; then
	log "installing additional packages"

	# Allow comma-separation so that this can more easily be preseeded
	# at the kernel command line.
	RET="$(printf '%s' "$RET" | sed 's/,/ /g')"
	in-target sh -c "$config debconf-apt-progress --from 800 --to 850 --logstderr -- apt-get -q -y install -- $RET" || aptfailed
fi

curlang=0
allpackages=
for lp in $langpacks; do
	# Install basic language packs again if they weren't installed the
	# first time, now that we've put the final sources.list in place. Don't
	# install them if they're already installed, as the extra network
	# bandwidth used during installation may be annoying.
	min="$((850 + 100 * $curlang / $numlangs))"
	curlang="$(($curlang + 1))"
	max="$((850 + 100 * $curlang / $numlangs))"
	allpackages="${allpackages:+$allpackages }language-pack-$lp"
	# TODO: This is a layering violation, but, since we might have to
	# install quite a number of language packs, most other methods are too
	# slow.
	if [ -f "/target/var/lib/dpkg/info/language-pack-$lp.list" ]; then
		# Already installed; just step the progress bar.
		db_progress SET "$max"
	else
		ret=0
		in-target sh -c "$config debconf-apt-progress --from $min --to $max --logstderr -- apt-get -o APT::Install-Recommends=false -q -y install 'language-pack-$lp'" || ret=$?
		if [ "$ret" != 0 ]; then
			# In case packages failed to install, try to clean up.
			in-target dpkg --configure -a || true
		fi
	fi

	for pattern in $lppatterns; do
		min="$((850 + 100 * $curlang / $numlangs))"
		curlang="$(($curlang + 1))"
		max="$((850 + 100 * $curlang / $numlangs))"
		pack="$(echo "$pattern" | sed "s/\\\$LL/$lp/g")"
		allpackages="${allpackages:+$allpackages }$pack"
		ret=0
		in-target sh -c "$config debconf-apt-progress --from $min --to $max --logstderr -- apt-get -o APT::Install-Recommends=false -q -y install '$pack'" || ret=$?
		if [ "$ret" != 0 ]; then
			# In case packages failed to install, try to clean up.
			in-target dpkg --configure -a || true
		fi
	done

	if [ "$langsupport" = true ]; then
		min="$((850 + 100 * $curlang / $numlangs))"
		curlang="$(($curlang + 1))"
		max="$((850 + 100 * $curlang / $numlangs))"
		if $check_language_support; then
			packs="$(chroot /target check-language-support -l "$lp" || true)"
		else
			packs="language-support-$lp"
		fi
		if [ "$packs" ]; then
			for pack in $packs; do
				if [ "${pack#gimp-help-}" != "$pack" ]; then
					# gimp-help-common is far too big to
					# fit on CDs, so don't worry about
					# it.
					continue
				fi
				allpackages="${allpackages:+$allpackages }$pack"
			done
			quotedpacks=
			for p in $packs; do
				quotedpacks="${quotedpacks:+$quotedpacks }'$p'"
			done
			ret=0
			in-target sh -c "$config debconf-apt-progress --from $min --to $max --logstderr -- apt-get -o APT::Install-Recommends=false -q -y install $quotedpacks" || ret=$?
			if [ "$ret" != 0 ]; then
				# In case packages failed to install, try to clean up.
				in-target dpkg --configure -a || true
			fi
		fi
	fi
done
if [ -z "$langpacks" ]; then
	db_progress SET 950
fi

log "finishing up"
db_progress INFO pkgsel/progress/cleanup
if ! cleanup; then
	log "cleanup failed"
fi

db_progress STEP 20

# Mark any pending update notifications as seen.
if [ -d /target/var/lib/update-notifier/user.d ]; then
	mkdir -p /target/etc/update-notifier
	chroot /target find /var/lib/update-notifier/user.d/ -type f \
		-printf '%P %C@ 0\n' \
		> /target/etc/update-notifier/hooks_seen
fi

db_get pkgsel/ignore-incomplete-language-support
if ! [ "$RET" = true ] && [ "$allpackages" ]; then
	incomplete=
	if ! allstatus="$(chroot /target dpkg-query -f '${Status}\n' -W $allpackages)"; then
		log "dpkg-query -W $allpackages failed; assuming incomplete language support"
		incomplete=1
	elif echo "$allstatus" | grep -qv '^install ok installed$'; then
		log "some of $allpackages were not completely installed"
		incomplete=1
	fi
	if [ "$incomplete" ]; then
		if [ -f /target/usr/share/language-support/incomplete-language-support-gnome.note ]; then
			mkdir -p /target/var/lib/update-notifier/user.d
			cp /target/usr/share/language-support/incomplete-language-support-gnome.note /target/var/lib/update-notifier/user.d/
		elif [ -f /target/usr/share/language-support/incomplete-language-support-qt.note ]; then
			mkdir -p /target/var/lib/update-notifier/user.d
			cp /target/usr/share/language-support/incomplete-language-support-qt.note /target/var/lib/update-notifier/user.d/
		fi
	fi
fi

if [ -x /target/usr/bin/fc-cache ]; then
	chroot /target fc-cache -f -v >/target/var/log/fontconfig.log 2>&1 \
		|| true
fi
if [ -x /target/usr/sbin/update-initramfs ]; then
	# get UUIDs for any devices formatted after partitioning
	update-dev

	# make UUIDs etc. available in the target system
	mount -o bind /dev /target/dev
	mount -o bind /sys /target/sys
	mount -o bind /proc /target/proc
	
	chroot /target /usr/sbin/update-initramfs -u || true
	
	umount /target/proc
	umount /target/sys
	umount /target/dev
fi
if db_get pkgsel/updatedb && [ "$RET" = true ]; then
	for script in mlocate locate; do
		if [ -x "/target/etc/cron.daily/$script" ]; then
			chroot /target "/etc/cron.daily/$script" || true
			break
		fi
	done
fi
chroot /target apt-get clean

db_progress STEP 30
db_progress STOP

load_install_cd
