#!/bin/sh
# Tazwok - SliTaz source compiler and binary packages generator/cooker.
#
# Tazwok can compile source package and creat binary packages suitable for
# Tazpkg (Tiny Autonomus zone package manager). You can build individuals
# package or a list a packages with one command, rebuild the full distro,
# generate a packages repository and also list and get info about packages.
#
# (C) 2007 SliTaz - GNU General Public License.
# Author : <pankso@slitaz.org>
#
VERSION=20071008

####################
# Tazwok variables #
####################

# Packages categories.
CATEGORIES="base-system base-apps x-window extra"

# Use words rater than numbers in the code.
COMMAND=$1
PACKAGE=$2
LIST=$2

# Include config file or exit if any file found.
if [ -f "/etc/tazwok.conf" ] ; then
	. /etc/tazwok.conf
else
	echo "Unable to find the configuration file : /etc/tazwok.conf"
	echo "Please read the Tazwok documentation."
	exit 0
fi

# Creat Taz wok needed directories if user is root.
if test $(id -u) = 0 ; then
	# Check for the wok directory.
	if [ ! -d "$WOK" ] ; then
		echo -n "Creating the wok directory..."
		mkdir -p $WOK
	fi
	# Check for the packages repository.
	if [ ! -d "$PACKAGES_REPOSITORY" ] ; then
		echo -n "Creating the packages repository..."
		mkdir -p $PACKAGES_REPOSITORY
	fi
fi

# The path to the most important file used by Tazwok.
# The receipt is used to compile the source code and
# gen suitables packages for Tazpkg.
RECEIPT="$WOK/$PACKAGE/receipt"

# The path to the process log file.
LOG="$WOK/$PACKAGE/process.log"

####################
# Tazwok functions #
####################

# Print the usage (English).
usage ()
{
	echo -e "\nSliTaz sources compiler and packages generator - Version: $VERSION\n
\033[1mUsage: \033[0m `basename $0` [command] [package|list|category|dir] [--option]
\033[1mCommands: \033[0m\n
  usage      Print this short usage.
  stats      Print Tazwok statistics from the config file and the wok.
  list       List all packages in the wok tree or by category.
  info       Get informations about a package in the wok.
  check-log  Check the process log file of a package.
  search     Search for a package in the wok by pattern or name.
  compile    Configure and build the package using the receipt rules.
  genpkg     Generate a suitable package for Tazpkg with the rules.
  cook       Compile and generate a package directly.
  cook-list  Cook all packages specified in the list by order.
  clean      Clean all generated files in the package tree.
  new-tree   Prepare a new package tree and receipt (--interactive).
  gen-list   Generate a packages.list and md5sum for a repository.
  clean-wok  Clean all packages in the wok tree.
  remove     Remove a package from the wok.\n"
}

# Status function.
status()
{
  local CHECK=$?
	echo -en "\033[68G"
	if [ $CHECK = 0 ] ; then
	  echo -e "\033[1mOK\033[0m"
	else
	  echo -e "\033[1mFailed\033[0m"
	fi
}

# Check if user is root.
check_root()
{
	if test $(id -u) != 0 ; then
	   echo "You must be root to run `basename $0` with this option."
	   echo "Please type 'su' and root password to become super-user."
	   exit 0
	fi
}

# Check for a package name on cmdline.
check_for_package_on_cmdline()
{
	if [ -z "$PACKAGE" ] ; then
		echo "You must specify a package name on the command line."
		echo "Example : tazwok $COMMAND package"
		exit 0
	fi
}

# Check for the receipt of a package used to cook.
check_for_receipt()
{
	if [ ! -f "$RECEIPT" ] ; then
		echo "Unable to find the receipt : $RECEIPT"
		exit 0
	fi
}

# Check for a specified file list on cmdline.
check_for_list()
{
	if [ -z "$LIST" ] ; then
		echo "You must specify the path to the list of packages to cook."
		exit 0
	fi
	# Check if the list of packages exist.
	if [ -f "$LIST" ] ; then
		LIST=`cat $LIST`
	else
		echo "Unable to find $LIST packages list."
		exit 0
	fi
}

# Check for the wanted package if specified in WANTED
# receipt variable. Set the $src/$_pkg variable to help compiling
# and generating packages.
check_for_wanted()
{
	if [ ! "$WANTED" = "" ] ; then
		echo -n "Checking for the wanted package..."
		if [ ! -d "$WOK/$WANTED" ] ; then
			echo "Wanted package is missing in the work directory."
			exit 0
		fi
		status
		# Set wanted src path.
		src=$WOK/$WANTED/$WANTED-$VERSION
		_pkg=$src/_pkg
	fi
}

###################
# Tazwok commands #
###################

case "$COMMAND" in
	stats)
		# Tazwok general statistics from the config file the wok.
		#
		echo ""
		echo -e "\033[1mTazwok configuration statistics\033[0m\n
Wok directory       : $WOK
Packages repository : $PACKAGES_REPOSITORY
Sources repository  : $SOURCES_REPOSITORY
Packages in the wok : `ls -1 $WOK | wc -l`\n"
		;;
	list)
		# List packages in wok directory. User can specifiy a category
		#
		if [ "$2" = "category" ] ; then
			echo -e "\033[1m\nPackages categories :\033[0m $CATEGORIES\n"
			exit 0
		fi
		# Check for an asked category.
		if [ -n "$2" ] ; then
			ASKED_CATEGORY=$2
			echo ""
			echo -e "\033[1mPackages in category :\033[0m $ASKED_CATEGORY"
			echo "----"
			for pkg in `ls -1 $WOK`
			do
				. $WOK/$pkg/receipt
				if [ "$CATEGORY" == "$ASKED_CATEGORY" ] ; then
					echo "$PACKAGE ($VERSION)"
					packages=$(($packages+1))
				fi
			done
			echo "----"
			echo "$packages packages in category $ASKED_CATEGORY."
		else
			# By default list all packages and version.
			echo ""
			echo -e "\033[1mList of packages in the wok\033[0m"
			echo "----"
			for pkg in $WOK/*
			do
				. $pkg/receipt
				echo "$PACKAGE ($VERSION)"
				packages=$(($packages+1))
			done
			echo "----"
			echo "$packages packages installed."
		fi
		;;
	info)
		# Informations about package.
		#
		check_for_package_on_cmdline
		check_for_receipt
		. $WOK/$PACKAGE/receipt
		echo ""
		echo -e "\033[1mTazwok package informations\033[0m\n
Package	   : $PACKAGE
Version	   : $VERSION
Category   : $CATEGORY
Short desc : $SHORT_DESC
Maintainer : $MAINTAINER"
		if [ ! "$DEPENDS" = "" ] ; then
			echo -e "Depends    : $DEPENDS"
		fi
		if [ ! "$WANTED" = "" ] ; then
			echo -e "Wanted src : $WANTED"
		fi
		if [ ! "$WEB_SITE" = "" ] ; then
			echo -e "Web site   : $WEB_SITE\n"
		else
			echo ""
		fi
		;;
	check-log)
		# We just cat the file log to view process info.
		#
		if [ ! -f "$LOG" ] ; then
			echo "No process log file found."
			exit 0
		else
			echo ""
			echo -e "\033[1mPackage process log\033[0m\n"
			echo -e "Name : $PACKAGE\n"
			cat $LOG
			echo ""
		fi
		;;
	search)
		# Search for a package by pattern or name.
		#
		if [ -z "$2" ] ; then
			echo "You must specify a pattern or a package name to search."
			echo "Example : 'tazwok search gcc'."
			exit 0
		fi
		echo ""
		echo -e "\033[1mSearch result for : \033[0m $PACKAGE\n"
		echo "----"
		ls -1 $WOK | grep $PACKAGE
		echo "----"
		;;
	compile)
		# Configure and make a package with the receipt.
		#
		check_for_package_on_cmdline
		# Include the receipt to get all needed variables and functions
		# and cd into the work directory to start the work.
		check_for_receipt
		. $RECEIPT
		# Log the package name and date.
		echo "date `date +%Y%m%d\ \%H:%M:%S`" >> $LOG
		echo "package $PACKAGE (compile)" >> $LOG
		# Set $src variable to help compiling.
		if [ ! "$SOURCE" = "" ] ; then
			src=$WOK/$PACKAGE/$SOURCE-$VERSION
		else
			src=$WOK/$PACKAGE/$PACKAGE-$VERSION
		fi
		check_for_wanted
		echo "Starting to cook $PACKAGE..."
		# Check for src tarball and wget if needed.
		if [ ! "$TARBALL" = "" ] ; then
			echo "Checking for source tarball... "
			if [ ! -f "$SOURCES_REPOSITORY/$TARBALL" ] ; then
				cd $SOURCES_REPOSITORY
				wget $WGET_URL
			else
				echo -n "Source tarball exit... "
				status
			fi
			# Untaring source if necessary. We dont need to extract source if
			# the package is build with a wanted source package.
			if [ "$WANTED" = "" ] ; then
				if [ ! -d $src ] ; then
					# Log process.
					echo "untaring $TARBALL" >> $LOG
					echo -n "Untaring $TARBALL... "
					if [ "`basename $TARBALL | grep tar.bz2`" ] ; then
						tar xjf $SOURCES_REPOSITORY/$TARBALL -C $WOK/$PACKAGE
					else
						tar xzf $SOURCES_REPOSITORY/$TARBALL -C $WOK/$PACKAGE
					fi
					status
				else
					echo -n "Source direcory exit... " && status
				fi
			fi
		fi
		cd $WOK/$PACKAGE
		# Log and execute compile_rules function if it exist, to configure and
		# make the package if it exist.
		if [ `cat $RECEIPT | grep compile_rules` ] ; then
			echo "executing compile_rules" >> $LOG
			compile_rules

		else
			echo "no compile_rules" >> $LOG
			echo "No compile rules for $PACKAGE..."
		fi
		;;
	genpkg)
		# Creat a package tree and build the gziped cpio archive
		# to make a SliTaz (.tazpkg) package.
		#
		check_root
		check_for_package_on_cmdline
		check_for_receipt
		. $RECEIPT
		check_for_wanted
		cd $WOK/$PACKAGE
		# Remove old Tazwok package files.
		if [ -d "taz" ] ; then
			rm -rf taz
			rm -f $PACKAGES_REPOSITORY/$PACKAGE-$VERSION.tazpkg
		fi
		# Creat the package tree and set usful variables.
		mkdir -p taz/$PACKAGE-$VERSION/fs
		fs=taz/$PACKAGE-$VERSION/fs
		# Set $src for standards package and $_pkg variables.
		if [ "$WANTED" = "" ] ; then
			src=$WOK/$PACKAGE/$PACKAGE-$VERSION
			_pkg=$src/_pkg
		fi
		if [ ! "$SOURCE" = "" ] ; then
			src=$WOK/$PACKAGE/$SOURCE-$VERSION
			_pkg=$src/_pkg
		fi
		cd $WOK/$PACKAGE
		# Execute genpkg_rules to build the package.
		echo "Bulding $PACKAGE with the receipt..."
		echo "----"
		if [ `cat $RECEIPT | grep genpkg_rules` ] ; then
			# Log process.
			echo "executing genpkg_rules" >> $LOG
			genpkg_rules
		else
			echo "No package rules to gen $PACKAGE..."
		fi
		# Copy the receipt and description (if exist) in
		# the binary package tree.
		cd $WOK/$PACKAGE
		echo -n "Copying the receipt..."
		cp receipt taz/$PACKAGE-$VERSION
		status
		if [ -f "description.txt" ] ; then
			echo -n "Copying the description file..."
			cp description.txt taz/$PACKAGE-$VERSION
			status
		fi
		# Creat the files.list by redirecting find outpout.
		echo -n "Creating the list of files..."
		cd taz/$PACKAGE-$VERSION/fs
		find . -type f -print > ../files.list
		find . -type l -print >> ../files.list
		cd .. && sed -i s/'^.'/''/ files.list
		status
		# Build cpio archives. Find, cpio and gzip the fs, finish by
		# removing the fs tree.
		echo -n "Compressing the fs... "
		find fs -print | cpio -o -H newc > fs.cpio
		gzip fs.cpio && rm -rf fs
		echo -n "Creating full cpio archive... "
		find . -print | cpio -o -H newc > $PACKAGES_REPOSITORY/$PACKAGE-$VERSION.tazpkg
		# Restore package tree in case we want to browse it.
		echo -n "Restoring original package tree... "
		gzip -d fs.cpio.gz && cpio -id < fs.cpio
		rm fs.cpio && cd ..
		# Log process.
		echo "$PACKAGE-$VERSION.tazpkg (done)" >> $LOG
		echo "----"
		echo "Package $PACKAGE ($VERSION) generated."
		echo "Size : `du -sh $PACKAGES_REPOSITORY/$PACKAGE-$VERSION.tazpkg`"
		;;
	cook)
		# Compile and generate a package. Just execute tazwok with
		# the good commands.
		#
		check_root
		check_for_package_on_cmdline
		check_for_receipt
		tazwok compile $PACKAGE
		tazwok genpkg $PACKAGE
		;;
	cook-list)
		# Cook all packages listed in a file. The path to the cooklist must
		# be specified on the cmdline.
		#
		check_root
		check_for_list
		for pkg in $LIST
		do
			tazwok compile $pkg
			tazwok genpkg $pkg
		done
		;;
	clean)
		# Clean up a package work directory.
		#
		check_for_package_on_cmdline
		check_for_receipt
		. $RECEIPT
		cd $WOK/$PACKAGE
		echo "Cleaning $PACKAGE..."
		if [ -d "taz" ] ; then
			echo -n "* Removing taz files..."
			rm -rf taz && status
		fi
		# Remove source tree if exist.
		if [ -d "$PACKAGE-$VERSION" ] ; then
			echo -n "* Removing source files..."
			rm -rf $PACKAGE-$VERSION && status
		fi
		if [ -d "$SOURCE-$VERSION" ] ; then
			echo -n "* Removing source files..."
			rm -rf $SOURCE-$VERSION && status
		fi
		# Remove an envental $PACKAGE-build directory.
		if [ -d "$PACKAGE-build" ] ; then
			echo -n "* Removing build tree..."
			rm -rf $PACKAGE-build && status
		fi
		# Remove process log file.
		if [ -f "process.log" ] ; then
			echo -n "* Removing process log file..."
			rm process.log && status
		fi
		;;
	clean-worktree)
		# Clean all packages in the work directory
		#
		for pkg in `ls -1 $WOK`
		do
			tazwok clean $pkg
		done
		echo "----"
		echo "`ls -1 $WOK | wc -l` packages cleaned."
		;;
	gen-list)
		# cd in the directory to creat a packages.list and the md5sum file.
		# Sed is used to remove all the .tazpkg extensions from the
		# packages.list. The directory to move in by default is the repository
		# if $3 is not empty cd into $3.
		#
		if [ -z "$2" ] ; then
			PACKAGES_REPOSITORY=$PACKAGES_REPOSITORY
		else
			if [ -d "$2" ] ; then
				PACKAGES_REPOSITORY=$2
			else
				echo "Unable to find directory : $2"
				exit 0
			fi
		fi
		cd $PACKAGES_REPOSITORY
		echo "----"
		echo "Repository path : $PACKAGES_REPOSITORY"
		echo -n "Creating the packages list... "
		ls -1 > /tmp/packages.list
		sed -i s/'.tazpkg'/''/ /tmp/packages.list
		status
		echo -n "Building the md5sum for all packages... "
		md5sum * > packages.md5
		status
		mv /tmp/packages.list $PACKAGES_REPOSITORY
		echo "----"
		pkgs=`cat $PACKAGES_REPOSITORY/packages.list | wc -l`
		echo "$pkgs packages in the repository."
		;;
	new-tree)
		# Just creat a few directories and gen a empty receipt to prepare
		# the creation of a new package.
		#
		check_for_package_on_cmdline
		if [ -d $WOK/$PACKAGE ] ; then
			echo "$PACKAGE package tree already exist."
			exit 0
		fi
		echo "Creating : $WOK/$PACKAGE"
		mkdir $WOK/$PACKAGE
		cd $WOK/$PACKAGE
		echo -n "Preparing the receipt..."
		#
		# Default receipt begin.
		#
		echo "# SliTaz package receipt." > receipt
		echo "" >> receipt
		echo "PACKAGE=\"$PACKAGE\"" >> receipt
# Finish the empty receipt.
cat >> receipt << "EOF"
VERSION=""
CATEGORY=""
SHORT_DESC=""
MAINTAINER=""
DEPENDS=""
WANTED=""
TARBALL="$PACKAGE-$VERSION.tar.gz"
WEB_SITE=""
WGET_URL=""

# Rules to configure and make the package.
compile_rules()
{
	cd $src
	./configure --prefix=/usr --infodir=/usr/share/info \
	--mandir=/usr/share/man $CONFIGURE_ARGS
	make
	make DESTDIR=$PWD/_pkg install
}

# Rules to gen a SliTaz package suitable for Tazpkg.
genpkg_rules()
{
	mkdir -p $fs/usr
	cp -a $_pkg/usr/bin $fs/usr
	strip -s $fs/usr/bin/*
}

# Pre and post install commands for Tazpkg.
pre_install()
{
	echo "Processing pre-install commands..."
}
post_install()
{
	echo "Processing post-install commands..."
}
EOF
#
# Default receipt end.
#
		status
		# Interactive mode, asking and seding.
		if [ "$3" = "--interactive" ] ; then
			echo "Entering in interactive mode..."
			echo "----"
			echo "Package       : $PACKAGE"
			# Version.
			echo -n "Version       : " ; read anser
			sed -i s/'VERSION=\"\"'/"VERSION=\"$anser\""/ receipt
			# Category.
			echo -n "Category      : " ; read anser
			sed -i s/'CATEGORY=\"\"'/"CATEGORY=\"$anser\""/ receipt
			# Short description.
			echo -n "Short desc    : " ; read anser
			sed -i s/'SHORT_DESC=\"\"'/"SHORT_DESC=\"$anser\""/ receipt
			# Maintainer.
			echo -n "Maintainer    : " ; read anser
			sed -i s/'MAINTAINER=\"\"'/"MAINTAINER=\"$anser\""/ receipt
			# Web site.
			echo -n "Web site      : " ; read anser
			sed -i s#'WEB_SITE=\"\"'#"WEB_SITE=\"$anser\""# receipt
			echo "----"
			# Wget URL.
			echo "Wget URL to download source tarball."
			echo "Example  : \$GNU_MIRROR/\$PACKAGE/\$TARBALL"
			echo -n "Wget url : " ; read anser
			sed -i s#'WGET_URL=\"\"'#"WGET_URL=\"$anser\""# receipt
			# Ask for a stuff dir.
			echo -n "Do you need a stuff directory ? (y/N) : " ; read anser
			if [ "$anser" = "y" ] ; then
				echo -n "Creating the stuff directory..."
				mkdir stuff && status
			fi
			# Ask for a description file.
			echo -n "Are you going to write a description ? (y/N) : " ; read anser
			if [ "$anser" = "y" ] ; then
				echo -n "Creating the description.txt file..."
				echo "" > description.txt && status
			fi
		fi
		;;
	remove)
		# Remove a package from the wok.
		#
		check_for_package_on_cmdline
		echo -n "Removing $PACKAGE..."
		rm -rf $WOK/$PACKAGE && status
		;;
	usage|*)
		# Print usage also for all unknow commands.
		#
		usage
		;;
esac

exit 0
