#!/bin/sh
# TazPkg - Tiny autonomous zone packages manager, hg.slitaz.org/tazpkg
# remove - TazPkg module
# Remove packages


# Connect function libraries
. /lib/libtaz.sh

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




# Log activity

log_pkg() {
	[ -w "$LOG" ] &&
	echo "$(date +'%F %T') - $1 - $PACKAGE ($VERSION$EXTRAVERSION)" >> "$LOG"
}


# Block of receipt function callers
# Why? "Bad" receipt sourcing can redefine some vital TazPkg variables.
# Few receipts functions should be patched now.

# Input: $1 = path to the receipt to be processed

call_pre_remove() {
	local tmp
	if grep -q '^pre_remove()' "$1"; then
		action 'Execute pre-remove commands...'
		tmp="$(mktemp)"
		cp "$1" "$tmp"
		sed -i 's|$1/*$INSTALLED|$INSTALLED|g' "$tmp"
		( . "$tmp"; pre_remove "$root" )
		status
		rm "$tmp"
	fi
}

call_post_remove() {
	local tmp
	if grep -q '^post_remove()' "$1"; then
		action 'Execute post-remove commands...'
		tmp="$(mktemp)"
		cp "$1" "$tmp"
		sed -i 's|$1/*$INSTALLED|$INSTALLED|g' "$tmp"
		( . "$tmp"; post_remove "$root" )
		status
		rm "$tmp"
	fi
}


# return possible name for a virtual package name

virtual_pkg() {
	# input:  $1 virtual package name
	#         $2 repository db directory
	# output: display possible package name

	debug "\nvirtual_pkg('$1', '$2')"
	local i
	unset IFS
	for i in $(grep -hs "^$(reesc "$1")=" "$2/packages.equiv" | sed "s/^$(reesc "$1")=//"); do
		if echo $i | fgrep -q : ; then
			# format 'alternative:newname'
			# if alternative is installed then substitute newname
			if [ -f $INSTALLED/${i%:*}/receipt ]; then
				# substitute package dependency
				echo ${i#*:}
				return
			fi
		elif ! grep -q "^$(reesc "$1")	" "$2/packages.info" || [ -f "$INSTALLED/$i/receipt" ]; then
			# unconditional substitution
			echo $i
			return
		fi
	done
	# the real package name
	echo $1
}




for rep in $PRIORITY; do
	[ ! -f "$rep/packages.info" ] && continue
	PACKAGE="$(virtual_pkg "$1" "$rep")"
	[ "$PACKAGE" != "$1" ] && break
done

if [ ! -f "$INSTALLED/$PACKAGE/receipt" ]; then
	newline; _ 'Package "%s" is not installed.' "$PACKAGE"
	exit 1
fi

. "$INSTALLED/$PACKAGE/receipt"

# Info #1: dependent packages (to be processed later)
ALTERED="$(awk -F$'\t' -vp=" $PACKAGE " 'index(" " $8 " ", p) { printf "  %s\n", $1 }' "$PKGS_DB/installed.info")"

if [ -n "$ALTERED" ]; then
	_ 'The following packages depend on package "%s":' "$PACKAGE"
	echo "$ALTERED"
fi

# Info #2: changed packages (to be processed later)
REFRESH=$(cd "$INSTALLED"; grep -sl "^$(reesc "$PACKAGE")$" */modifiers)

if [ -n "$REFRESH" ]; then
	_ 'The following packages have been modified by package "%s":' "$PACKAGE"
	for i in $REFRESH; do
		echo "  ${i%/modifiers}"
	done
fi

# Confirmation
if [ -n "$noconfirm" ] || im && [ -z "$auto" ]; then
	confirm "$(_ 'Remove package "%s" (%s)? (y/N)' "$PACKAGE" "$VERSION$EXTRAVERSION")"
	if [ "$?" -ne 0 ]; then
		newline; _ 'Uninstallation of package "%s" cancelled.' "$PACKAGE"
		exit 0
	fi
fi
# We are here: non-interactive mode, or --auto, or --yes, or answer 'y'

# Removing package
title 'Removing package "%s"' "$PACKAGE"

# Unblock package quietly; otherwise:
# 1. We can no longer install the package one more time - because it is blocked
# 2. We can no longer unblock the package - because it is not installed
tazpkg -u "$PACKAGE" --nowarning | grep -v '^$'

# [1/5] Pre-remove commands
call_pre_remove "$INSTALLED/$PACKAGE/receipt"


# [2/5] Removing files
action 'Removing all files installed...'

# NOTE: package 'faenza-icon-theme' install time: 12s; removing time ~ 11min on my system  o_O
# After optimization: 3s! (Long) for-loops are (big) evil ;)

# NOTE: many packages contains filenames with spaces:
#   lzcat /var/lib/tazpkg/files.list.lzma | awk -F" " '{if(NF>2)print $1}' | sed 's|:$||' | uniq
# Redefine IFS to only-new-line field separator:
IFS=$'\n'

files2remove="$(mktemp)"

debug '\nDetermine which files to remove...'
# Never delete a file co-owned by another still-installed package. Two
# directions, both recorded at install time:
#   - packages that modified THIS one        ($PACKAGE/modifiers)
#   - owners THIS one modified, still around  ($REFRESH = */modifiers listing us)
# Without the second direction, removing a *modifier* sweeps the owner's shared
# files (uuid.pc, /usr/include/linux/*, /usr/bin/python3, ...) even though the
# owner is still installed.
keep="$(mktemp)"
for mod in $(cat "$INSTALLED/$PACKAGE/modifiers" 2>/dev/null) $REFRESH; do
	mod="${mod%/modifiers}"
	[ "$mod" = "$PACKAGE" ] && continue
	cat "$INSTALLED/$mod/files.list" >> "$keep" 2>/dev/null
done

if [ -s "$keep" ]; then
	debug '  (co-owned files protected)'

	awk -vroot="$root" -vfl="$INSTALLED/$PACKAGE/files.list" '
	{
		if (FILENAME == fl)
			f[$0] = 1;
		else
			f[$0] = "";
	}
	END {
		for (i in f) {
			if (f[i] == 1) printf "%s%s\n", root, i;
		}
	}' "$INSTALLED/$PACKAGE/files.list" "$keep" > "$files2remove"
else
	debug '  (no co-owned files)'

	awk -vroot="$root" '{ printf "%s%s\n", root, $0; }' \
		"$INSTALLED/$PACKAGE/files.list" > "$files2remove"
fi
rm "$keep"

debug 'Removing files...'
xargs rm -f < "$files2remove"

debug 'Removing folders...'
awk '
BEGIN {
	FS = "/"; OFS = "/";
}
{
	# removing filename beyond the last "/"
	$NF = "";
	if (! a[$0]) {
		a[$0] = 1; print;
	}
}' "$files2remove" | xargs rmdir -p 2>/dev/null

rm "$files2remove"
unset IFS

status

# [3/5] Post-remove commands
call_post_remove "$INSTALLED/$PACKAGE/receipt"
# restore Busybox applets
. @@MODULES@@/bb restore


# [4/5] Update system databases
fl="$INSTALLED/$PACKAGE/files.list"; upd=0

fgrep    /usr/share/applications/    "$fl" | fgrep -q .desktop && udesk='yes'
fgrep -q /usr/share/mime             "$fl" && umime='yes'
fgrep -q /usr/share/icon/hicolor     "$fl" && uicon='yes'
fgrep    /usr/share/glib-2.0/schemas "$fl" | fgrep -q .xml && uschm='yes'
fgrep    /usr/lib/gdk-pixbuf         "$fl" | fgrep -q .so && upixb='yes'
if fgrep -q /lib/modules             "$fl"; then
	ukrnl='yes'
	if fgrep -q /kernel/fs/ "$fl"; then
		ukrnlfs='yes'
	fi
fi

if [ -n "$udesk$umime$uicon$uschm$upixb$ukrnl" ]; then
	action 'Update system databases...'
	upd=1
fi

# package 'desktop-file-utils'
[ -n "$udesk" ] && chroot "$root/" /usr/bin/update-desktop-database /usr/share/applications 2>/dev/null
# package 'shared-mime-info'
[ -n "$umime" ] && chroot "$root/" /usr/bin/update-mime-database /usr/share/mime
# packages 'gtk+', 'gtk+3'
[ -n "$uicon" ] && chroot "$root/" /usr/bin/gtk-update-icon-cache /usr/share/icons/hicolor
# package 'glib'
# hide messages like next because they are unresolved (we may to patch glib to hide them, almost the same)
# warning: Schema '*' has path '*'.  Paths starting with '/apps/', '/desktop/' or '/system/' are deprecated.
[ -n "$uschm" ] && chroot "$root/" /usr/bin/glib-compile-schemas /usr/share/glib-2.0/schemas 2>&1 | fgrep -v '/apps/'
# package 'gdk-pixbuf'
[ -n "$upixb" ] && chroot "$root/" /usr/bin/gdk-pixbuf-query-loaders --update-cache

if [ -n "$ukrnlfs" ]; then
	for i in $(awk -F/ '{if($6=="fs" && $8~$7)print $7}' "$fl" | sort -u); do
		grep -i "/^$i\$/d" "$root/etc/filesystems"
	done
fi
# packages 'busybox', 'kmod', 'depmod'
[ -n "$ukrnl" ] && grep '/lib/modules' "$fl" | cut -d'/' -f4 | uniq | xargs chroot "$root/" /sbin/depmod -a

[ "$upd" -eq 1 ] && status


# [5/5] Remove package receipt and remove it from databases
action 'Removing package receipt...'
rm -rf "$INSTALLED/$PACKAGE"
# We no longer overload any owner's files: drop our now-stale entry from each
# owner's modifiers list (and the list itself once empty) to keep the db sane.
for mod in $REFRESH; do
	mod="$INSTALLED/${mod%/modifiers}/modifiers"
	[ -f "$mod" ] || continue
	sed -i "/^$(reesc "$PACKAGE")\$/d" "$mod"
	[ -s "$mod" ] || rm -f "$mod"
done
sed -i "/ $(reesc "$PACKAGE-$VERSION$EXTRAVERSION.tazpkg")$/d" "$PKGS_DB/installed.$SUM"
sed -i "/^$(reesc "$PACKAGE")	/d" "$PKGS_DB/installed.info"
status

footer "$(_ 'Package "%s" (%s) removed.' "$PACKAGE" "$VERSION$EXTRAVERSION")"

# Log this activity
log_pkg Removed

# Stop if non-interactive mode and no --auto option
if ! im && [ -z "$auto" ]; then exit 0; fi

# Process dependent packages
if [ -n "$ALTERED" ]; then
	if [ -n "$auto" ]; then
		answer=0
	else
		confirm "$(_ 'Remove packages depending on package "%s"? (y/N)' "$PACKAGE")"
		answer=$?
	fi
	if [ "$answer" -eq 0 ]; then
		for i in $ALTERED; do
			if [ -d "$INSTALLED/$i" ]; then
				tazpkg remove $i
			fi
		done
	fi
fi

# Process changed packages
if [ -n "$REFRESH" ]; then
	if [ -n "$auto" ]; then
		answer=0
	else
		confirm "$(_ 'Reinstall packages modified by package "%s"? (y/N)' "$PACKAGE")"
		answer=$?
	fi
	if [ "$answer" -eq 0 ]; then
		for i in $REFRESH; do
			if [ "$(wc -l < "$INSTALLED/$i")" -gt 1 ]; then
				_ 'Package "%s" was modified by "%s" and other packages. It will not be reinstalled.' \
					"${i%/modifiers}" "$PACKAGE"
				_ 'Check "%s" for reinstallation.' "$INSTALLED/$i"

				continue
			fi
			rm -r "$INSTALLED/$i"
			tazpkg get-install ${i%/modifiers} --forced
		done
	fi
fi

