#!/bin/sh
# makeslapt - make a slapt-get compatible slackware package
# by Eko M. Budi
#
# The original code was included in checkinstall as makepak,
# which in turn was from Slakware's makepak
#
# ----------------------------------------------------------------
# Copyright 1994, 1998  Patrick Volkerding, Moorhead, Minnesota USA 
# Copyright 2003  Slackware Linux, Inc.  Concord, CA USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Wed Mar 18 15:32:33 CST 1998
# Patched to avoid possible symlink attacks in /tmp.
#
# Sat Dec 09 2000 - Felipe Sanchez <izto@asic-linux.com.mx>
# Removed the code for the questions about symlinks and sane permissions
# They are useless to CheckInstall
#
# Fri Jul 20 2001 - Felipe Sanchez <izto@asic-linux.com.mx>
# Included the patch made to makepkg in the Slackware 8.0 release.
#
# Aug, 2004 = Eko M. Budi
# patch to simplify symlinks creation using readlink (needs coreutil 5.0 up)
# add symlinks to the preexisting doinst.sh (assume it was created by checkinstall) 
#
# Oct, 2004 = Eko M. Budi
# Add dependency tracking for slapt-get
#
# Nov, 2004 = Eko M. Budi, the Dumb Bunny revealed
# Fix tar silly ./ problem
#
# Nov, 2004 = Eko M. Budi & Jason Woodward
# Fix package name function
#
# Nov, 2004 = Eko M. Budi, the Dumber Bunny revealed
# Refix tar silly ./ problem. DOH !!!
# Her ya her ya ... Use the old tar-1.13 !!
#
# Dec, 2004 = Eko M. Budi
# Checkinstall 1.6.0beta4 out, always want to pass options ...
# So combine the original makepkg from Slackware 10
# Renamed to makeslapt, to make it clear
#
# March, 2006 = Eko M. Budi
# - Use 2 digit max dependency rule 
#   (e.g: gtk2+ >= 2.6.8 became gtk2+ >= 2.6)
# - Add lib_with_path() patch by YaP
# - support tgz, tbz, or tlz format


TAR=tar-1.13
umask 022
$TAR --help 1> /dev/null 2> /dev/null
if [ ! $? = 0 ]; then
  TAR=tar
fi
if [ ! "`LC_MESSAGES=C $TAR --version`" = "tar (GNU tar) 1.13

Copyright (C) 1988, 92,93,94,95,96,97,98, 1999 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Written by John Gilmore and Jay Fenlason." ]; then
  echo "WARNING: pkgtools are unstable with tar > 1.13."
  echo "         You should provide a \"tar-1.13\" in your \$PATH."
  sleep 5
fi

usage() {
  cat << EOF

Usage: makeslapt [options] package_name.tgz

Makes a Slackware compatible package containing the contents of the 
current and all subdirectories. If symbolic links exist, they will be 
removed and a doinst.sh script will be made to recreate them later.
It also generates dependency rules for slapt-get, named slack-required.
The default format is tgz, you may change it to tbz or tlz format
by using command line option (-g, -b, -l), or export PKGFORMAT
enviromental variable PKGFORMAT, e.g :
  export PKGFORMAT=tlz    

options:
  -s, --slapt y|n   add slapt-get dependency info, default Y
  -f, --full y|n    add full dependency info, default Y
  -l, --linkadd y|n moves symlinks into doinst.sh, default Y.
  -p, --prepend     add symlinks to the front of the existing doinst.sh.
  -c, --chown y|n   resets all permissions to root:root 755, default N
  -g, --tgz         use tgz format (default)
  -b, --tbz         use tbz format
  -l, --tlz         use tlz format

EOF
}


# Return package name, from Jason
# This is fast, but DOES NOT WORK if the package does not follow
# standard package naming, notably VERSION with -, e.g:
# xine-lib-1-rc1-i486-1 --> return xine-lib-1
# In that case, replace '-' with '_'. 
pkgname() {
    echo $1 | sed -re "s/(.*{1,})\\-(.*[\\.\\-].*[\\.\\-].*)[ ]{0,}$/\1/"
}

# return package name, orthodox way
# Not used anymore because the reg-exp way is faster
# although this Orthodox way can handle nasty name better

# put bad guy names here
KNOWN_NAMES="cdparanoia slib libjpeg"
KNOWN_ARCHS="noarch i386 i486 i586 i686 i786 i886 i986"
pkgname1() {
name=${1%%-*}
ver_rest=${1#$name-}
while [ 0 ]; do
   ## 1st rule, if known name then that's it !
   if echo "$KNOWN_NAMES " | grep -q "$name "; then
       break
   fi
   ## 2nd rule, if digits followed by . or - then stop
   if echo $ver_rest | grep -qe "^[0-9]*[\.\-_]"; then
      break
   fi
   ## 3rd, if the next segment is known architecture, stop
   extra=${ver_rest%%-*}
   ver_rest=${ver_rest#$extra-}
   if echo "$KNOWN_ARCHS " | grep -q `echo $ver_rest | cut -f1 -d-`; then
      break
   fi
   ## 4rd, no more rest, then break
   if [ "$ver_rest" = "$extra" ]; then
      break
   fi
   ## concat the name then continue
   name="${name}-${extra}"
done
echo $name
}

## Insert dependency info ala slapt-get 
## The autodependency is generated using ldd ala swaret
## Let them fight as they like, we are free to get the best of them :)

REQUIRED=install/slack-required
DESCRIPTION=install/slack-desc

## Add dependency info if not exist yet
add_required()
{
    if ! grep -qw "$1" $REQUIRED 2>/dev/null; then
    	if [ "$SLAPT_FULL" = "y" ] && [ "$3" ]; then
	    # trying to find the lesser version
	    REQ_VERSION=${3%%_*}
	    REQ_VERSION=`echo $REQ_VERSION | cut -f 1-2 -d '.'`
	    echo "$*" >> $REQUIRED
    	    echo "$*"
	else
	    echo "$1" >> $REQUIRED
	    echo "$1"
	fi
    fi
}

## find dependency 
find_required()
{
    ## if $2 not null, assume it is a complete requirement
    if [ "$2" ]; then
	add_required $*
	return 0
    fi
    ## try to find version info from the installed packages
    DDNAME=$1
    if ls /var/log/packages/$DDNAME-* &>/dev/null; then
	for DD in /var/log/packages/$DDNAME-* ; do
	    DDBASE=`basename $DD`
	    if [ "$DDNAME" = "`pkgname $DDBASE`" ]; then
		DDVERSION=${DDBASE#${DDNAME}-}
		# Left only version
		DDVERSION=${DDVERSION%%-*}
		add_required $DDNAME '>=' $DDVERSION
		return 0
	    fi
	done
    fi
    ## Can't find version info, just add it then
    add_required $DDNAME 
}

# contributed by YaP
function lib_with_path()
{
    LIB="$1"
    if [ "${LIB:0:1}" == "/" ]; then
        echo "${LIB:1}"
        return 1
    fi
    if [ -f "/lib/$LIB" ]; then
        echo "lib/$LIB"
   return 1;
    fi
    if [ -f "/usr/lib/$LIB" ]; then
        echo "usr/lib/$LIB"
   return 1;
   fi
   cat /etc/ld.so.conf | while read PATH_LINE; do
        LIBPATH="$PATH_LINE/$LIB"
        if [ -f "$LIBPATH" ]; then
            echo "${LIBPATH:1}"
            return 0
        fi
    done
    echo "$LIB"
    return 1
}

function add_dependency()
{
  # find the executables and track the required packages
  find . -perm +1 ! -path './install/*' -print | while read LINE; do
     [ ! -f "$LINE" ] && continue
     [ ".${LINE##*.}" = ".la" ] && continue
     echo "$LINE:"
     if ! ldd "$LINE" &>/dev/null; then
        # not a dynamic, possibly script
	FTYPE=`file "$LINE"`
	if echo $FTYPE | grep -q "Bourne" ; then
	    find_required bash
	elif echo $FTYPE | grep -q "C shell" ; then
	    find_required tcsh
	elif echo $FTYPE | grep -iqw "perl" ; then
	    find_required perl
	elif echo $FTYPE | grep -iqw "python" ; then
	    find_required python
	elif echo $FTYPE | grep -iqw "ruby" ; then
	    find_required ruby
	elif echo $FTYPE | grep -iqw "php" ; then
	    find_required php
	elif echo $FTYPE | grep -qw "tcl"; then
	    find_required tcl
	elif echo $FTYPE | grep -qw "expect"; then
	    find_required expect
	    find_required tclx
	    find_required tcl
	else
	    echo "WARNING: unknown dependency for $LINE" 
	fi
     else 
	ldd $LINE | while read LINE1; do
    	    LIB=`echo $LINE1 | cut -f1 -d ' '`
	    # SELF=$(find -name `basename $LIB`)
            SELF=$(find -name `basename "$LIB*"`)
	    [ "$SELF" ] && continue
	    LIB="`lib_with_path $LIB`"
	    grep "$LIB" /var/log/packages/* | while read LINE2; do
		DFULL=`echo $LINE2 | cut -f1 -d:`
		DBASE=`basename $DFULL`
		DNAME=`pkgname $DBASE`
		case "$DNAME" in
		    aaa_elflibs|$PNAME)
		    continue
		    ;;
		esac
		DVERSION=${DBASE#${DNAME}-}
		DVERSION=${DVERSION%%-*}
		add_required $DNAME '>=' $DVERSION
		break
	    done
	    if [ $? != 0 ]; then
		echo "WARNING : Cannot find dependency for $LIB"
	    fi
	done
     fi
  done
}

function add_doinst() {
    echo "Moving symbolic links to scripts ..."
    # Using readlink to read the link, works with coreutils (Slackware 9.1 up).
    # Old method using ls -l was broken since coreutil 5.0
    find . -type l -print | while read LINE; do
      DIRNAME="`dirname $LINE`" 
      LINKNAME="`basename $LINE`"
      LINKTO="`readlink $LINE`"
      echo "( cd $DIRNAME ; rm -rf $LINKNAME )" >> install/doinst.sh
      echo "( cd $DIRNAME ; ln -sf $LINKTO $LINKNAME )" >> install/doinst.sh
      rm -fv $LINE
    done
}

# Default options
LINKADD=y
PREPEND=y
CHOWN=n
SLAPT=y
SLAPT_FULL=y
PKGFORMAT=${PKGFORMAT:-tgz}

# Parse options
while [ 0 ]; do
  if [ "$1" = "--linkadd" -o "$1" = "-l" ]; then
    if [ "$2" = "y" ]; then
      LINKADD=y
    elif [ "$2" = "n" ]; then
      LINKADD=n
    else
      usage
      exit 2
    fi
    shift 2
  elif [ "$1" = "--chown" -o "$1" = "-c" ]; then
    if [ "$2" = "y" ]; then
      CHOWN=y
    elif [ "$2" = "n" ]; then
      CHOWN=n
    else
      usage
      exit 2
    fi
    shift 2
  elif [ "$1" = "--slapt" -o "$1" = "-s" ]; then
    if [ "$2" = "y" ]; then
      SLAPT=y
    elif [ "$2" = "n" ]; then
      SLAPT=n
    else
      usage
      exit 2
    fi
    shift 2
  elif [ "$1" = "--full" -o "$1" = "-f" ]; then
    if [ "$2" = "y" ]; then
      SLAPT_FULL=y
    elif [ "$2" = "n" ]; then
      SLAPT_FULL=n
    else
      usage
      exit 2
    fi
    shift 2
  elif [ "$1" = "-p" -o "$1" = "--prepend" ]; then
    PREPEND=y
    shift 1
  elif [ "$1" = "-g" -o "$1" = "--tgz" ]; then
    PKGFORMAT=tgz
    shift 1
  elif [ "$1" = "-b" -o "$1" = "--tbz" ]; then
    PKGFORMAT=tbz
    shift 1
  elif [ "$1" = "-l" -o "$1" = "--tlz" ]; then
    PKGFORMAT=tlz
    shift 1
  elif [ "$1" = "-h" -o "$1" = "-H" -o "$1" = "--help" -o $# = 0 ]; then
    usage
    exit 0
  else
    break
  fi
done

echo
echo "Slackware SLAPT-GET package maker, version 2.1."
PACKAGE_NAME=$1

PDIR=`dirname $PACKAGE_NAME`
PLONG=`basename $PACKAGE_NAME`
PSHORT=${PLONG%.*}
PEXT=${PLONG##*.}
PNAME=`pkgname $PLONG`

mkdir -p install

if [ "$LINKADD" = "y" ]; then
    if [ "$PREPEND" = "y" ]; then
	echo "Prepending doins script ..."
	touch install/doinst.sh
	mv install/doinst.sh install/doinst.sh.shipped
	echo "#!/bin/sh" > install/doinst.sh
	add_doinst
	echo "" >> install/doinst.sh
	cat install/doinst.sh.shipped >> install/doinst.sh
	rm -f install/doinst.sh.shipped
    else
	echo "Concatenating doinst script ..."
	echo "" >> install/doinst.sh
	add_doinst 
    fi
fi

if [ "$CHOWN" = "y" ]; then
  echo "Fixing permission ..."
  find . -type d -exec chmod -v 755 {} \; 
  find . -type d -exec chown -v root.root {} \;
fi

## Add dependency
if [ "$SLAPT" = "y" ]; then
    echo "Adding slapt-get dependencies ..."
    add_dependency
fi

## Add description, if not yet
if [ ! -f install/slack-desc ]; then
    echo "$PNAME: $PNAME" > install/slack-desc
fi

echo
echo "Creating package $PSHORT.$PKGFORMAT ..."

# Don't be a dumb bunny, TAR must be tar-1.13
# With newer tar, these are broken:
# tar czvf $PACKAGE_NAME . --> creates leading ./, though fixable by installpkg
# tar czvf $PACKAGE_NAME * --> no leading ./, but installpkg will be confused
echo
echo "Creating tar file $PSHORT.tar..."
echo
$TAR cvf $PSHORT.tar .

# Warn of zero-length files:
find . -type f -size 0c | while read file ; do
  echo "WARNING: zero length file $file"
done
find . -type f -name '*.gz' -size 20c | while read file ; do
  echo "WARNING: possible empty gzipped file $file"
done

# packing the tar file into tgz, tlz, or tbz
echo
echo "Compressing $PSHORT.$PKGFORMAT ..."

case $PKGFORMAT in
  tgz)
    gzip -9 $PSHORT.tar
    mv $PSHORT.tar.gz ${PDIR}/${PSHORT}.${PKGFORMAT}
    ;;
  tlz)
    lzma -7 $PSHORT.tar
    mv $PSHORT.tar.lzma ${PDIR}/${PSHORT}.${PKGFORMAT}
    ;;
  tbz)
    bzip2 -9 $PSHORT.tar
    mv $PSHORT.tar.bz2 ${PDIR}/${PSHORT}.${PKGFORMAT}
    ;;
esac
echo
echo "Package creation $PSHORT.$PEXT complete."
echo
if [ "$PEXT" != "$PKGFORMAT" ]; then
  echo "WARNING: The package format is not the same as the given name."
  echo "Please check the options or PKGFORMAT enviromental variable"
fi

