#!/bin/sh
#
# Author: Oliver Kurth <oliver.kurth@innominate.com>
#
# Description:
# builds an opkg package from a source tarball using opkg-build. Idea stolen
# from Debian dpkg-buildpackage.
# 
# - unpack the source tarball.
# - cd to the source distribution, change whatever you need to make the
#   package compile and work on the ipaq.
# - create a directory 'opkg'
# - put all files which go to the 'CONTROL' directory of the root of the
#   installed package into opkg.
# - the version (Version field in control) should match the version of the
#   source tarball, optionally with a digit (eg. -1) appended.
# - additionally, put a file there called 'rules' which is a shell script
#   accepting arguments 'build', 'install' and 'clean'. It can be a 
#   Makefile starting with the line '#!/usr/bin/make -f'
#   * the build target does things like ./configure and make.
#   * the install target installs to a temporary directory (make
#   DESTDIR=/tmp/package) and removes unnecessary items (eg. man pages)
#   * clean cleans ;-)
#
# You should run this with fakeroot (1) or as root.
# If all went well, you will find a diff file and an *.opk file in the
# directory above.

set -e

SCRIPTDIR=/usr/local/bin

SCRIPTNAME=`basename $0`

opkg_extract_value() {
	sed -e "s/^[^:]*:[[:space:]]*//"
}

required_field() {
	field=$1

	value=`grep "^$field:" < $CONTROL/control | opkg_extract_value`
	if [ -z "$value" ]; then
		echo "opkg-build: Error: $CONTROL/control is missing field $field" ;
		PKG_ERROR=1
	fi
	echo $value
}

pkg_appears_sane_control() {
	local pkg_dir=$1

	local owd=`pwd`
	cd $pkg_dir

	if [ ! -f "$CONTROL/control" ]; then
		echo "opkg-build: Error: Control file $pkg_dir/$CONTROL/control not found."
		cd $owd
		return 1
	fi

	pkg=`required_field Package`
	version=`required_field Version | sed 's/.*://;'`
	arch=`required_field Architecture`
	required_field Maintainer >/dev/null
	required_field Description >/dev/null

	if echo $pkg | grep '[^a-z0-9.+-]'; then
		echo "opkg-build: Error: Package name $pkg contains illegal characters, (other than [a-z0-9.+-])"
		PKG_ERROR=1;
	fi

	local bad_fields=`sed -ne 's/^\([^[:space:]][^:[:space:]]\+[[:space:]]\+\)[^:].*/\1/p' < $CONTROL/control | sed -e 's/\\n//'`
	if [ -n "$bad_fields" ]; then
		bad_fields=`echo $bad_fields`
		echo "opkg-build: Error: The following fields in $CONTROL/control are missing a ':'"
		echo "	$bad_fields"
		echo "opkg-build: This may be due to a missing initial space for a multi-line field value"
		PKG_ERROR=1
	fi

	cd $owd
	return $PKG_ERROR
}

pkg_appears_sane_scripts() {
	local pkg_dir=$1

	local owd=`pwd`
	cd $pkg_dir

	for script in $CONTROL/preinst $CONTROL/postinst $CONTROL/prerm $CONTROL/postrm; do
		if [ -f $script -a ! -x $script ]; then
			echo "opkg-build: Error: package script $script is not executable"
			PKG_ERROR=1
		fi
	done

	cd $owd
	return $PKG_ERROR
}

pkg_dir_abs=`pwd`
pkg_dir_base=`basename ${pkg_dir_abs}`

pkg_dir=.

[ -d ./CONTROL ] && CONTROL=./CONTROL
[ -d ./opkg ] && CONTROL=./opkg
if [ -z "$CONTROL" ]; then
        echo "${SCRIPT_NAME}: Error: Directory $pkg_dir has no opkg or CONTROL subdirectory."
        exit 1
fi

if ! pkg_appears_sane_control $pkg_dir && pkg_appears_sane_control $pkg_dir; then
        echo "Please fix the above errors and try again."
        exit 1
fi

echo "Package = $pkg"
echo "Version = $version"
version_up=`echo ${version} | sed "s/\-[0-9]\+//"`
echo "Upstream Version = $version_up"
pkg_upname=${pkg}-${version_up}
echo "Package Name = $pkg_upname"
pkg_tarball=${pkg_upname}.tar.gz
echo "Tarball Name = $pkg_tarball"

if [ ! -x ${CONTROL}/rules ]; then
	echo "${CONTROL}/rules not found or not executable."
	exit 1
fi

#
# unpack upstream tarball and make diff
#
if [ -e ../${pkg_tarball} ] ; then
	(
	set +e

	cd ..

	rm -rf ${pkg_upname}.tmp
	rm -rf ${pkg_upname}.orig

	mkdir ${pkg_upname}.tmp
	cd ${pkg_upname}.tmp
	echo "unpacking source tarball ${pkg_tarball}"
	tar zxf ${pkg_dir_abs}/../${pkg_tarball}
	dir=`find . -maxdepth 1 -name "*" -type d`
	cnt=`echo $dir | wc -l`
	if [ ${cnt} != 1 ] ; then
		echo "Arrghh !!!!"
		echo "upstream package contains more than one top level directory"
		echo "giving up..."
		exit 1
	fi
	mv ${dir} ${pkg_upname}.orig
	mv ${pkg_upname}.orig ..
	cd ..
	echo "creating diff"
	diff -uNr  ${pkg_upname}.orig ${pkg_dir_base} > ${pkg}-${version}.diff
	rm -f ${pkg}-${version}.diff.gz
	echo "gzipping ${pkg}-${version}.diff"
	gzip ${pkg}-${version}.diff

	echo "Removing temporary source directorys"
	rm -rf ${pkg_upname}.tmp
	rm -rf ${pkg_upname}.orig
	)
fi

# build package
if ! ${CONTROL}/rules build; then
	echo "Build failed"
	exit 1
fi

# install it to tmp directory
if ! ${CONTROL}/rules install; then
	echo "Install failed"
	exit 1
fi

# copy contents of control directory
mkdir /tmp/${pkg}/CONTROL

files_required="control"
files_optional="preinst postinst prerm postrm"

for i in ${files_required} ; do
	file=${CONTROL}/$i
	
	if [ -e ${file} ] ; then
		cp $file /tmp/${pkg}/CONTROL
	else
		echo "required file ${file} missing"
	fi
done

for i in ${files_optional} ; do
	file=${CONTROL}/$i
	
	if [ -e ${file} ] ; then
		cp $file /tmp/${pkg}/CONTROL
	fi
done

# build the opk package
owd=`pwd`
cd ..
opkg-build /tmp/${pkg} || exit 1

rm -rf /tmp/${pkg}

cd $owd
if ! ${CONTROL}/rules clean; then
	echo "Clean failed"
	exit 1
fi

# Yep. That's it!
exit 0
