#!/bin/sh
# vim: et sw=4

# TODO: srcdir!=builddir

usage()
{
    echo "usage: $self --destdir=[destination installation directory]"
    echo "usage: $self [destination installation directory]"
    exit 1
}

self=mkipkg
destdir=
strip=strip
control=
builddir=
srcdir=
prefix=
preinst=
postinst=
prerm=
postrm=
mkfsjffs2=
ipkgbuild=ipkg-build
buildversion=
subst=
user=root
group=root
filesubst=

oldpwd=

for option
do
    case "$option" in
        -*=*)
            arg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'`
            ;;
    esac

    case "$option" in
        --destdir=*)
            destdir=$arg
            ;;
        --strip=*)
            strip=$arg
            ;;
       --control=*)
            control=$arg
            ;;
       --preinst=*)
            preinst=$arg
            ;;
       --postinst=*)
            postinst=$arg
            ;;
       --prerm=*)
            prerm=$arg
            ;;
       --postrm=*)
            postrm=$arg
            ;;
       --builddir=*)
            builddir=$arg
            ;;
       --srcdir=*)
            srcdir=$arg
            ;;
       --prefix=*)
            prefix=$arg
            ;;
       --mkfsjffs2=*)
            mkfsjffs2=$arg
            ;;
       --ipkgbuild=*)
            ipkgbuild=$arg
            ;;
       --buildversion=*)
            buildversion=$arg
            ;;
       --subst=*)
            subst=$arg
            ;;
       --user=*)
            user=$arg
            ;;
       --group=*)
            group=$arg
            ;;
       --filesubst=*)
            filesubst=$arg
            ;;
       --classic)
            classic=-c
            ;;
       -*)
            usage
            ;;
       *)
            destdir=$option
            ;;
    esac
done

if [ -z "$control" ]; then
    control=$destdir/CONTROL/control
fi
if [ -z "$prerm" ]; then
    prerm=$destdir/CONTROL/prerm
fi
if [ -z "$postrm" ]; then
    postrm=$destdir/CONTROL/postrm
fi
if [ -z "$preinst" ]; then
    preinst=$destdir/CONTROL/preinst
fi
if [ -z "$postinst" ]; then
    postinst=$destdir/CONTROL/postinst
fi

# remove leading slash from prefix (to fix globbing)
if [ -n "$prefix" ]; then
    prefix=`echo $prefix | sed -e "s,/\(.*\),\\1,"`
fi

if [ -z "$destdir" ]; then
    usage
fi

if [ ! -r $control ]; then
   echo "$self: cannot find $control, exiting..."
   exit 1
fi

if [ -z "`which $ipkgbuild 2>/dev/null`" ]; then
    echo "$self: cannot find ipkg-build, exiting..."
    exit 1
fi

findFile()
{
    local path=
    if [ $# = 1 ]; then
        find $1 -type f -o -type b -o -type c -o -type l
        find $1 -type d -a -empty
    else
        find . -type f -o -type b -o -type c -o -type l | \
	    sed -e "s,\./\(.*\),\\1,g"
        find . -type d -a -empty
    fi
}

_pushd() { oldpwd=`pwd`; cd $1; }
_popd() { cd $oldpwd; }

setVar()
{
    eval "$1='$2'"
}

expandMaskToList()
{
    local _list=`echo $1`
    local _tmpFileList=
    for f in $_list; do
        if [ -d $f ]; then
            f="`findFile $f`"
        fi
        _tmpFileList="`eval echo $f` $_tmpFileList"
    done
    setVar $2 "$_tmpFileList"
}

createFileList()
{
    local excludeMask
    local includeMask
    local includemaskpresent=0
    local excludemaskpresent=0

    if (grep -q ^FileExcludeMask $1); then
        excludemaskpresent=1
        excludeMask=$(eval echo '"'$(sed -n -e "s,^FileExcludeMask: *,,p" $1)'"')
    fi
    if (grep -q ^FileIncludeMask $1); then
        includemaskpresent=1
        includeMask=$(eval echo '"'$(sed -n -e "s,^FileIncludeMask: *,,p" $1)'"')
    else
        if (grep -q ^Files: $1); then
            includemaskpresent=1
            includeMask=$(eval echo '"'$(sed -n -e "s,^Files: *,,p" $1)'"')
        fi
    fi
 
    _pushd $destdir
    
    declare -a excludeMaskArray
    excludeMaskArray=( $excludeMask )
    excludeMaskArray=( "${excludeMaskArray[@]}" "CONTROL/*" "usr/share/*" )

    if [ $includemaskpresent != 1 ]; then
        includeMask="."
    fi

    if [ -z "$includeMask" ]; then
        setVar $2 ""
        _popd
        return 0
    fi

    expandMaskToList "$includeMask" _fileList

    excludeMaskArray=( "${excludeMaskArray[@]}" "*/CVS*" "*/SCCS*" )

    local realFileList=
    local missing=0
    for file in $_fileList; do
        local containedInList=0
        for i in "${excludeMaskArray[@]}"; do
            if [[ $file == $i ]]; then
                containedInList=1
                break;
            fi
        done

        if [ $containedInList = 0 ]; then
            if ! [ -e $file -o -L $file ]; then
                echo "$self: $file not found"
                missing=1
            fi
            realFileList=$file" $realFileList"
        fi
    done

    _popd

    if [ $missing = 1 ]; then
        return 1
    fi

    setVar $2 "$realFileList"
}

stripFile()
{
    if [ ! -h $1 -a -f $1 -a -x $1 ]; then
     $strip -p --strip-all $1
    fi
}

substFile()
{
    local oldfile=$1

    if [ ! -e $2 ]; then return 1; fi

    if [ -e $oldfile -o -L $oldfile ]; then
        newfile=`echo $oldfile|sed -f $2|sed -e's,^/,,g'`
        olddir=`dirname $oldfile`
        base=`basename $oldfile`
        newdir=`dirname $newfile`

#        echo >&2 moving $oldfile to $newfile

        if [ "$newdir" = "$olddir" ]; then
            return 0
        fi

        mkdir -p $newdir
        mv $olddir/$base $newfile
        rmdir -p $olddir 2>/dev/null
    fi
}

stripFiles()
{
    for f in $1; do
        # do not strip links
        if [ ! -h ./$f ]
        then
          stripFile ./$f
        fi
    done
}

substFiles()
{
    for f in $1; do
        substFile ./$f
    done
}

substAndStripFiles()
{
    for f in $1; do
        stripFile ./$f
        substFile ./$f $2
    done
}

installScript()
{
    if [ -n "$1" -a -f "$1" ]; then
        destfile=`basename $1`
        filetype=`echo $destfile|cut -d. -f2`
        if [ -n "$filetype" ]; then destfile=$filetype; fi
        if [ -n "$subst" ]; then
            sed -f $subst < $1 > $ctrldir/$destfile
        else
            cat $1 > $ctrldir/$destfile
        fi
        chmod +x $ctrldir/$destfile
    fi
}

tempDir=/tmp/`basename $self`.$$
mkdir -p $tempDir
if [ $? != 0 ]; then
    echo "$self: cannot create $tempDir, exiting..."
    rm -rf $tempDir
    exit 1
fi

ctrldir=$tempDir/CONTROL

mkdir -p $ctrldir

if [ ! -e $subst ] || [ -z "$subst" ]; then
    cat $control > $ctrldir/control.new
else
    sed -f $subst < $control > $ctrldir/control.new
fi

createFileList $ctrldir/control.new ipkgFileList

if [ "$?" != "0" ]; then
    echo "$self: ERROR: missing files, not building $control"
    rm -rf $tempDir
    exit 1
fi


cat $ctrldir/control.new | egrep -v '^(Files|FileExcludeMask|FileIncludeMask):' > $ctrldir/control
rm -f $ctrldir/control.new

( cd $destdir && tar -cf - $ipkgFileList 2>/dev/null ) | ( cd $tempDir && tar -xf - 2>/dev/null )

if [ -z "$filesubst" ]; then
    ( cd $tempDir && stripFiles "$ipkgFileList" )
else
    if ! (echo $filesubst|grep -q '^/'); then
        filesubst="$oldpwd/$filesubst"
    fi
    ( cd $tempDir && substAndStripFiles "$ipkgFileList" $filesubst )
fi

# removing CVS directories
find $tempDir -name CVS -a -type d -print0 | xargs -0 rm -rf

path="`echo "$PATH" | sed -e "s/\:/ /g"`"
if [ -z "$mkfsjffs2" ]; then
    for i in $path; do
      if [ -x "$i/mkfs.jffs2" ]; then
        mkfsjffs2="$i/mkfs.jffs2"
        break
      fi
    done
fi

if [ -z "$mkfsjffs2" ]; then
    echo "$self: WARNING: no mkjfs.jffs2 found in path. Falling back to using du"
    echo "for size calculation. mkfs.jffs2 is recommended for size calculation"
    echo "as it calculates the real package size on the compressed file system,"
    echo "in contrast to du calculating the uncompressed size!"
    buildsize=`du -h -s $tempDir | awk '{print $1}'`
else
    buildsize=`$mkfsjffs2 -r $tempDir | wc -c`
fi

if [ "$buildsize" != "0" ]; then
    echo "Installed-Size: $buildsize" >> $ctrldir/control
fi

installScript $preinst
installScript $postinst
installScript $prerm
installScript $posrm

$ipkgbuild $classic -o $user -g $group $tempDir

rm -rf $tempDir