#!/bin/bash
# vim:ts=4
#-----------------------------------------------------------------------
# DESCRIPTION
#-------------
# SuperPaco - installs Debian, RPM or Slackware binary packages without
#             dpkg, RPM or pkgtool; and logs them with paco.
#
# To install RPM packages, rpm2cpio and cpio are required.
#-----------------------------------------------------------------------
# AUTHOR
#--------
# SuperPaco is part of the package paco
# Copyright (C) 2005 David Rosal <david.rosal@upf.edu>
# For more information visit http://paco.sourceforge.net
#-----------------------------------------------------------------------
# CREDITS
#---------
# SuperPaco uses a modified version of Patrick Volkerding's rpm2targz:
# Copyright 1997, 1998 Patrick Volkerding, Moorhead, MN USA
# Copyright 2002 Slackware Linux, Inc., Concord, CA USA
# All rights reserved.
#
# The code for installing Debian packages is based upon "installdeb", by
# Islam Motab <phaeron@gawab.com>.
#
# Patched by Richard Johns <johnsr@woosh.co.nz>, to allow the use of 
# rpmunpack.
#-----------------------------------------------------------------------
# LICENSE
#---------
# 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.
#-----------------------------------------------------------------------


#---------------------------------------#
# Initialize and parse the command line #
#---------------------------------------#

# Remove tmp stuff on exit
trap 'rm -rf $tmpdir' 0

# Name of the program
case $0 in
	/bin/*sh|/sbin/*sh) PROGRAM=`basename $1`;;
	*) PROGRAM=`basename $0`;;
esac

# Defaults
ROOT=/
QUIET=no
STRIP=no
PACKAGES=

# Parse the command line
while test -n "$1"; do
	case $1 in
	
		-q|--quiet)
			QUIET=yes;;
		
		-s|--strip-release|--strip)
			STRIP=yes;;
		
		-v|--version)
			echo "$PROGRAM (paco-1.10.2)"
			echo "Copyright (C) 2004-2005 David Rosal <david.rosal@upf.edu>"
			exit 0;;
			
		-h|--help)
cat << EOF
$PROGRAM - installs Debian, RPM or Slackware packages with paco.

Usage:
  $PROGRAM [OPTIONS] <packages>

Options:  [default values listed in brackets]
  -h, --help           Display this usage message and exit.
  -v, --version        Display version information and exit.
      --root=PATH      Use PATH as the root directory  [$ROOT].
  -q, --quiet          Do it silently.
  -s, --strip-release  Remove the release suffix from the name of the package
                        (e.g. 'boofar-1.0.2-2.1' --> 'boofar-1.0.2').

Author:
  David Rosal <david.rosal@upf.edu>
EOF
exit 0;;
		
		--root|--root=*)
			ROOT=`expr $1 : '[^=]*=\(.*\)'` || {
				echo "$PROGRAM: Option '$1' requires an argument" >&2
				echo "Try '$PROGRAM --help' for more information" >&2
				exit 1
			};;
			
		-*)
			echo "$PROGRAM: Unrecognized option: '$1'" >&2
			echo "Try '$PROGRAM --help' for more information" >&2
			exit 1;;
		
		*)	# Non option argument = Name of a package
			PACKAGES="$PACKAGES $1";;
	esac
	shift
done


test $QUIET = yes && exec 6>/dev/null || exec 6>&1

# Remove repeated package names
if test -n "$PACKAGES"; then
	PACKAGES=`for pkg in $PACKAGES; do echo $pkg; done | sort -u`
else
	echo "$PROGRAM: No input packages" >&2
	echo "Try '$PROGRAM --help' for more information" >&2
	exit 1
fi

paco --version >/dev/null 2>&1 || {
	echo "$PROGRAM: Can't find paco executable" >&2
	exit 1
}

# "Absolutize" ROOT, and remove trailing and duplicate slashes
expr "$ROOT" : '/' >/dev/null || ROOT=`pwd`/$ROOT
ROOT=`expr "$ROOT" : '\(.*[^/]\)' '|' '/' | tr -s '/'`

if test -f $ROOT; then
	echo "$PROGRAM: $ROOT: Not a directory" >&2
	exit 1
fi

# Tmp dir to store intermediate files
tmpdir=`mktemp -dt ${PROGRAM}XXXXXX 2>/dev/null || echo /tmp/${PROGRAM}.$$`
rm -rf $tmpdir
install -d $tmpdir

cpio --version >/dev/null 2>&1 && have_cpio=yes || have_cpio=no
type rpm2cpio >/dev/null 2>&1 && have_rpm2cpio=yes || have_rpm2cpio=no
type rpmunpack >/dev/null 2>&1 && have_rpmunpack=yes || have_rpmunpack=no			
			
# Process the packages
for pkg in $PACKAGES; do
	
	# Check that the package exists and it's a regular file
	test -f $pkg || {
		echo "$PROGRAM: $pkg: No such regular file" >&2
		continue
	}
	
	# "Absolutize" pkg, and remove trailing and duplicate slashes
	expr "$pkg" : '/' >/dev/null || pkg=`pwd`/$pkg
	pkg=`expr "$pkg" : '\(.*[^/]\)' '|' '/' | tr -s '/'`
	
	printf "Processing $pkg: " >&6
	
	# Get the type of the package and the basename. Strip suffixes.
	# In Debian packages, also strip the architecture suffix and convert
	# underscores ('_') to hyphens ('-').
	
	case "`file $pkg`" in
	
		*\.deb:\ Debian\ binary\ package*)
			pkg_type=Debian
			name=`basename $pkg .deb | sed 's@_[a-zA-Z].*@@; y@_@-@'`
			;;
			
		*\.rpm:\ RPM*\ src\ *)
			echo
			echo "$PROGRAM can't install source RPM packages (only binary)" >&2
			exit 1
			;;
			
		*\.rpm:\ RPM*\ bin\ *)
			# RPM packages require cpio and rpm2cpio or rpmunpack.
			if test $have_cpio = no; then
				echo
				echo "*** Can't find cpio program" >&2
				echo "*** cpio is required to install RPM packages" >&2
				continue
			elif test $have_rpm2cpio = no -a $have_rpmunpack = no; then
				echo
				echo "*** Can't find rpm2cpio/rpmunpack program" >&2
				echo "*** rpm2cpio/rpmunpack is required to install RPM packages" >&2
				continue
			fi
			pkg_type=RPM
			name=`basename $pkg .rpm`
			;;
			
		*\.tgz:\ gzip\ compressed\ data*)
			pkg_type=Slackware
			name=`basename $pkg .tgz`
			;;
			
		*)
			echo "Unsupported format" >&2
			continue
			;;
	esac
	
	echo "$pkg_type package" >&6
	
	# Strip the release suffix, if needed.
	if test $STRIP = yes; then
		name=`echo $name | sed -e 's@\(-[0-9\.-]*\)-.*@\1@'`
	fi
	
	echo "  Name: $name" >&6
	
	
	# Debian package #
	#----------------#
	if test $pkg_type = Debian; then
	
		printf "  Converting .deb package to .tar.gz... " >&6
		
		# Extract the control portion
		(ar p $pkg control.tar.gz > $tmpdir/control.tar.gz) || continue
		(cd $tmpdir && gzip -cd control.tar.gz | tar xf -) || continue
		
		# Extract the data portion
		(ar p $pkg data.tar.gz > $tmpdir/$name.tar.gz) || continue
		(gzip -d $tmpdir/$name.tar.gz) || continue
		
		printf "ok\n  Installing the package with paco... " >&6
		
		# Create an artificial .spec file to be read by paco when logging
		# the installation of the package.
		(cd $tmpdir
		sed -ne "{ \
			/^[Dd]escription:/,/^$/h;		\
			s@^[Pp]ackage:@Name:@p;			\
			/^[Vv]ersion:/p;				\
			s@^[Dd]escription:@Summary:@p;	\
			s@^[Mm]aintainer:@Vendor:@p;	\
			g; {s,^ *,,; s,^.$,,; s,^[Dd]escription:.*,%description,; p} \
		}" control > $name.spec

		# Take into account the preinst script
		test -x preinst && cmd="./preinst &&" || cmd=""

		# Install
		test -d $ROOT || install -d $ROOT
		paco -lp $name "$cmd tar -C $ROOT xf $tmpdir/$name.tar"
		
		echo ok >&6
		)
	
	
	# RPM package #
	#-------------#
	elif test $pkg_type = RPM; then
	
		printf "  Converting the RPM package to cpio... " >&6
		
		(	cd $tmpdir &&
		
		rm -f error
		
		if test $have_rpmunpack = yes; then
			rpmunpack < $pkg > $name.cpio.gz || continue
			gunzip $name.cpio.gz || continue
		else
			(rpm2cpio $pkg > $name.cpio 2>error) || {
				cat error >&6
				continue
			}
		fi
		
		printf " ok\n  Extracting files from the cpio package... " >&6
		
		cpio --extract --make-directories --quiet < $name.cpio
		rm -f $name.cpio
		find . -type d -perm 700 -exec chmod 755 '{}' \;
		
		printf "ok\n  Installing the package with paco... " >&6

		test -d $ROOT || install -d $ROOT
		paco -lp $name "cp --archive `ls` $ROOT/"

		echo ok >&6
		)
	
	# Slackware package #
	#-------------------#
	else
		
		printf "  Converting the .tgz package to .tar... " >&6
		
		base=`basename $pkg`
		cp $pkg $tmpdir/$base || continue
		(	cd $tmpdir &&
		(gzip -fcd $base | tar xf -) || continue
		(tar cf pkg.tar `ls | grep -wv install`) || continue
		
		printf "ok\n  Installing the package with paco... " >&6
		
		aux_cmd=""
		if test -f install/doinst.sh; then
			aux_cmd="&& /bin/sh $tmpdir/install/doinst.sh"
		fi
		if test -f install/slack-desc; then
			echo "%description" > $name.spec
			sed '1,/----/d;s@^[^:]*: *@@' install/slack-desc >> $name.spec
		fi
		test -d $ROOT || install -d $ROOT
		paco -lp $name "tar -C $ROOT xf $tmpdir/pkg.tar $aux_cmd"
		
		echo ok >&6
		)
	fi
	
	# Remove tmp files
	rm -rf $tmpdir/*
	
done

# Nice job SuperPaco!
exit 0

