#!/bin/sh
# TazPkg - Tiny autonomous zone packages manager, hg.slitaz.org/tazpkg
# upgrade - TazPkg module
# Check for upgrades and make system up-to-date


# Environment variables:
#   root							Root of the packages DB
#   check							Only check for upgrades
#   install							Check and install all upgraded packages


# Connect function libraries
. /lib/libtaz.sh

# Get TazPkg working environment
. @@MODULES@@/getenv

# Get TazPkg checkspace module (check_space)
. @@MODULES@@/checkspace

# Get TazPkg getall module (fetchall_pkgs)
. @@MODULES@@/getall


time="$(date +%s)"

# Recharge packages databases (if necessary) (respects already exported "root" value)
tazpkg recharge >&2

echo -n > "$UP_LIST"
blocked_counter=$(mktemp)
tmp_up_list=$(mktemp)

repo_number=1
for repo in $PRIORITY; do
	if [ "$repo" = "$PKGS_DB" ]; then
		repo_name='Main'
	else
		repo_name="$(basename "$repo")"
	fi

	[ ! -f "$repo/packages.info" ] && continue
	{
		cat "$BLOCKED" | awk '{printf "%s\t%s\n", $1, "b"}'
		# Compare the package *file* checksum (from the .$SUM lists), not
		# packages.info field #9 (which holds an unreliable "release checksum"
		# on the mirror side but the file md5 on the installed side -- they
		# never match, causing phantom "New build" upgrades). Aligned with spk.
		# md5for() matches "name-version.tazpkg" or "name-version-<arch>.tazpkg"
		# (i486/x86_64/arm/any...) like spk, so arch-tagged files still match.
		sumawk='
		function md5for(base,   k){
			if((base ".tazpkg") in s) return s[base ".tazpkg"]
			for(k in s) if(index(k, base "-")==1 && k ~ /\.tazpkg$/) return s[k]
			return ""
		}
		BEGIN{while((getline l < sumf)>0){split(l,a," ");s[a[2]]=a[1]}}
		{printf "%s\t%s\t%s\t%s\n", $1, tag, $2, md5for($1 "-" $2)}'
		awk -F$'\t' -vtag="i" -vsumf="$PKGS_DB/installed.$SUM" "$sumawk" "$PKGS_DB/installed.info"
		awk -F$'\t' -vtag="p" -vsumf="$repo/packages.$SUM" "$sumawk" "$repo/packages.info"
	} | sort -t$'\t' -k1,1 | awk -F$'\t' \
	-vnewbuild="$(_ 'New build')" -vcolornewbuild="$(emsg '<c 34>')" \
	-vnewver='→ ' -vcolornewver="$(emsg '<c 32>')" \
	-vblocked=" ($(_ 'Blocked'))" -vcolorblocked="$(emsg '<c 31>')" \
	-vcolor0="$(emsg '</c>')" \
	-vreponum="$repo_number" -vreponame="$repo_name" \
	-vuplist="$UP_LIST" -vblocked_counter="$blocked_counter" \
'{

	if ($1 != p) {
		if (vi && vp) {
			bb = (b=="") ? "i" : "b"
			if ("" vi != vp) { # important: compare as strings
				startc = (b=="") ? colornewver : colorblocked;
				printf "%s\t%s\t%s\t%s\t", p, vi, reponum, reponame;
				printf "%s%s%s%s%s\t%s\n", startc, newver, vp, b, color0, bb;
				if (b=="")
					print p >> uplist;
				else
					printf 1 >> blocked_counter;
			} else if (mi != mp) {
				startc = (b=="") ? colornewbuild : colorblocked;
				printf "%s\t%s\t%s\t%s\t", p, vi, reponum, reponame;
				printf "%s%s%s%s\t%s\n",   startc, newbuild, b, color0, bb;
				if (b=="")
					print p >> uplist;
				else
					printf 1 >> blocked_counter;
			}
		}
		p = $1; b = b1 = b2 = vi = mi = vp = mp = "";
	}
	if ($2 == "b") { b = blocked; b1 = bl1; b2 = bl2; }
	if ($2 == "i") { vi = $3; mi = $4; }
	if ($2 == "p") { vp = $3; mp = $4; }
}' >> "$tmp_up_list"

	repo_number=$((repo_number + 1))

done

case "$output" in
	html)
		cat <<EOT
<table class="wide zebra">
	<thead>
		<tr><td>$(_ 'Package')</td><td>$(_ 'Repository')</td><td>$(_ 'Version')</td><td>$(_ 'Status')</td></tr>
	</thead>
	<tbody>
EOT
		sort -t$'\t' -k1,3 "$tmp_up_list" | awk -F$'\t' '{
			if($4=="Main"){repo_icon="@slitaz@"}else{repo_icon="@web@"}
			if($6=="b"){data_icon="@pkgib@"}else{data_icon="@pkgi@"}

			printf "<tr><td><input type=\"checkbox\" name=\"pkg\" value=\"%s\"/>", $1;
			printf "<a data-icon=\"%s\" href=\"?info=%s\">%s</a></td>", data_icon, $1, $1;
			printf "<td><span data-icon=\"%s\">%s</span></td>", repo_icon, $4;
			printf "<td>%s</td>", $2;
			printf "<td>%s</td></tr>\n", $5;
			}'
		echo '</tbody></table>' ;;
	*)
		emsg "<n>$(_ 'Package')<i 26>$(_ 'Repository')<i 38>$(_ 'Version')<i 49>$(_ 'Status')<->"
		sort -t$'\t' -k1,3 "$tmp_up_list" | awk -F$'\t' \
			'{printf "%-24s %-11s %-10s %s\n", $1, $4, $2, $5}';;
esac

sed -i /^$/d "$UP_LIST"
upnb=$(wc -l < "$UP_LIST")
pkgs=$(wc -l < "$PKGS_DB/installed.info")
time=$(($(date +%s) - $time))
if [ "$upnb" -eq 0 ]; then
	install="n"
	_ 'System is up-to-date...'
else
	spaceneed=$(check_space)
	blocked_count=$(wc -m < "$blocked_counter")

	blocked=$(_p \
		'%s blocked' \
		'%s blocked' "$blocked_count" \
		"$blocked_count")

	footer "$(_p \
		'You have %s available upgrade (%s)' \
		'You have %s available upgrades (%s)' "$upnb" \
		"$upnb" "$blocked")"

	emsg "$(_p \
		'You need %s free space.' \
		'You need %s free space.' "$spaceneed" \
		"<c 32>$spaceneed</c>")"
fi
emsg "$(_p \
	'%s installed package scanned in %ds' \
	'%s installed packages scanned in %ds' "$pkgs" \
	"<c 32>$pkgs</c>" "$time")"


# Clean
rm "$blocked_counter" "$tmp_up_list"

# Pkgs to upgrade ? Skip, lets install them all, or ask user
[ -n "$check" ] && exit 0

if [ "$upnb" -gt 0 ]; then
	if [ -n "$install" ]; then
		answer=0
	else
		confirm "$(_ 'Do you wish to install them now? (y/N)')"
		answer=$?
	fi
	case "$answer" in
		0)
			# Pre-fetch all updates (and missing deps) into the cache
			_ 'Fetch all updates :'
			fetchall_pkgs
			# Upgrade tazpkg first: a new tazpkg may handle new package
			# formats/features. Then other essentials, then the rest.
			# Each "tazpkg -gi" re-execs the freshly installed tazpkg, so
			# the rest of the list is processed by the new version.
			# glibc-base/gcc-lib-base must come before busybox: busybox is
			# dynamically linked against glibc and a new build may require a
			# newer libc, so the C library has to be updated first.
			essential='tazpkg glibc-base gcc-lib-base busybox-pam busybox slitaz-base-files'
			for pkg in $essential \
				$(grep -vxE "$(echo "$essential" | tr ' ' '|')" "$UP_LIST"); do
				grep -qx "$pkg" "$UP_LIST" || continue
				echo 'y' | tazpkg -gi "$pkg" --forced		#--reason="upgrade"
			done
			# List is generated each time and must be cleaned so
			# tazpkg-notify doesn't find upgrades anymore.
			rm "$UP_LIST"; touch "$UP_LIST" ;;
		*)
			_ 'Leaving without any upgrades installed.'
			newline
			exit 0 ;;
	esac
fi
newline
