#!/bin/sh
#
# cook-wok - SliTaz cook: read-only queries against the wok and the
# cook activity log. Lists packages, searches by name, checks for
# uncooked packages, prints cooker tasks driven by WANTED /
# BUILD_DEPENDS, and tails the activity log.
#
# Usage:
#   cook-wok list                    # list all packages in the wok
#   cook-wok search <query>          # grep package names
#   cook-wok uncook                  # list packages without a tazpkg
#   cook-wok wanted [<pkg-prefix>]   # cooker tasks driven by WANTED
#   cook-wok build_depends [<prefix>]
#   cook-wok build_loop [<prefix>]   # list packages without a dependancy loop
#   cook-wok activity                # cat $cache/activity
#
# Copyright (C) SliTaz GNU/Linux - GNU GPL v3
#

. /usr/lib/slitaz/libcook.sh


#
# Functions
#

usage() {
	cat <<EOT

$(boldify "$(_ 'Usage:')") cook-wok <command> [args]

$(boldify "$(_ 'Commands:')")
  usage|help|--help|-h $(_ 'Display this short usage.')
  list                 $(_ 'List packages in the wok (filtered by ARCH).')
  search <query>       $(_ 'Grep package names.')
  uncook               $(_ 'Full inventory of packages with no tazpkg.')
  wanted [<prefix>]    $(_ 'Incremental: receipts whose WANTED was recooked.')
  build_depends [<prefix>]
                       $(_ 'Incremental: receipts whose BUILD_DEPENDS was recooked.')
  build_loop [<prefix>]
                       $(_ 'Incremental: receipts whose BUILD_DEPENDS have a loop.')

$(boldify "$(_ 'Examples:')")
  cook-wok list                $(_ 'show all ARCH packages in the wok')
  cook-wok search lib          $(_ 'find packages whose name contains "lib"')
  cook-wok uncook              $(_ 'what still needs to be cooked (inventory)')
  cook-wok wanted gtk          $(_ 'gtk* receipts to recook (gtk+ is newer)')
  cook-wok build_depends       $(_ 'every receipt whose bdeps were recooked')
  cook-wok build_loop          $(_ "every receipt you can't cook from scratch (slow)")

$(boldify "$(_ 'About wanted / build_depends:')")
  Both are **incremental rebuild** helpers, not inventories. They emit
  cooker tasks only for receipts whose WANTED / BUILD_DEPENDS chain
  has been recooked more recently than the receipt's own taz/. On a
  vierge wok (nothing cooked yet) they print nothing — use 'uncook'
  for a full inventory of what to build.

$(boldify "$(_ 'About <prefix>:')")
  Scope the wanted/build_depends/build_loop scan to a directory-name prefix,
  e.g. "lib" -> \$WOK/lib*/receipt. Speeds up scans on large woks.
  Omit to scan the whole wok.

EOT
	exit 0
}


# Display cooker tasks for receipts whose $1 field (WANTED or
# BUILD_DEPENDS) points to a package whose taz/ is newer than the
# caller's taz/. $2 is an optional package-name prefix to filter the
# search.

show_cooklist() {
	grep -l ^$1= $WOK/$2*/receipt | sed 's|/receipt||' | while read pkg ; do
	(
		. $pkg/receipt
		eval deps=\$$1
		for i in $deps ; do
			[ $WOK/$i/taz -nt $pkg/taz ] || continue
			grep -qs "^$i$" $broken && echo -n "# $i is broken. "
			echo "cooker pkg $(basename $pkg) # because $i is newer" && break
		done
	)
	done
}

# Scan $pkg build dependancy tree for a loop i.e. the $pkg package can't be built
# from scratch. Display the first loop found, not the shortest. Many packages
# can share the same loop. And many loops can share the same shortest loop...
scan_bdeps()
{
	local i	# recursive function
	for i in $(. $1/receipt ; echo $WANTED $BUILD_DEPENDS); do
		if [ "$pkg" = "$i" ]; then
			echo "Loop: $ALL_BUILD_DEPENDS$i"
			# break callers for loop on first bdeps loop found
			return 1
		fi
		case "$ALL_BUILD_DEPENDS" in
		*\ $i\ *)
			continue ;;	# already scanned
		*)	
			ALL_BUILD_DEPENDS="$ALL_BUILD_DEPENDS$i "
			scan_bdeps $i || break
		esac
	done
	# do not break caller for loop: continue scanning
	return 0
}


#
# Dispatch
#

case "$1" in

	usage|help|--help|-h)
		usage
		;;

	list)
		title 'List of %s packages in "%s"' "$ARCH" "$WOK"
		cd $WOK
		if [ "$ARCH" != 'i486' ]; then
			count=0
			for pkg in $(fgrep 'HOST_ARCH=' */receipt | egrep "$ARCH|any" | cut -d: -f1)
			do
				unset HOST_ARCH
				. ./$pkg
				count=$(($count + 1))
				colorize 34 "$PACKAGE"
			done
		else
			count=$(ls | wc -l)
			ls -1
		fi
		footer "$(_p '%s package' '%s packages' "$count" "$(colorize 32 "$count")")"
		;;

	search)
		query="$2"
		title 'Search results for "%s"' "$query"
		cd $WOK; ls -1 | grep "$query"
		footer
		;;

	uncook)
		cd $WOK
		count=0
		title 'Checking for uncooked packages'

		for i in *; do
			unset HOST_ARCH EXTRAVERSION
			[ ! -e $i/receipt ] && continue
			. ./$i/receipt
			# Source cooked pkg receipt to get EXTRAVERSION
			if [ -d "$WOK/$i/taz" ]; then
				cd $WOK/$i/taz/$(ls $WOK/$i/taz/ | head -n1)
				. ./receipt; cd $WOK
			fi
			case "$ARCH" in
				i486)
					debug "$(_ 'Package "%s"' "$PKGS/$PACKAGE-$VERSION$EXTRAVERSION.tazpkg")"
					if [ ! -f "$PKGS/$PACKAGE-$VERSION$EXTRAVERSION.tazpkg" ]; then
						count=$(($count + 1))
						colorize 34 "$i"
					fi ;;
				x86_64)
					# Like i486: x86_64 is a primary arch, scan all
					# receipts. tazpkg may be either -x86_64 or -any.
					if [ ! -f "$PKGS/$PACKAGE-$VERSION$EXTRAVERSION-$ARCH.tazpkg" ] && \
					   [ ! -f "$PKGS/$PACKAGE-$VERSION$EXTRAVERSION-any.tazpkg" ]; then
						count=$(($count + 1))
						colorize 34 "$i"
					fi ;;
				arm*)
					# Check only packages included in arch
					if echo "$HOST_ARCH" | egrep -q "$ARCH|any"; then
						if [ ! -f "$PKGS/$PACKAGE-$VERSION$EXTRAVERSION-$ARCH.tazpkg" ]; then
							count=$(($count + 1))
							colorize 34 "$i"
						fi
					fi ;;
			esac
		done

		if [ "$count" -gt 0 ]; then
			footer "$(_p '%s uncooked package' '%s uncooked packages' "$count" "$(colorize 31 "$count")")"
		else
			_ 'All packages are cooked :-)'
			newline
		fi
		;;

	wanted)
		show_cooklist WANTED "$2"
		;;

	build_depends)
		show_cooklist BUILD_DEPENDS "$2"
		;;

	build_loop)
		for pkg in "$2"* ; do
			ALL_BUILD_DEPENDS="$pkg "
			scan_bdeps $pkg
		done
		;;

	'')
		usage
		;;

	*)
		_ 'Unknown command: %s' "$1" >&2
		usage
		;;

esac
