#!/bin/bash

# Return a package name that has been stripped of the dirname portion
# and any of the valid extensions (only):
pkgbase() {
  # basename + strip extensions .tbz, .tgz, .tlz and .txz
  echo "$1" | sed 's?.*/??;s/\.t[bglx]z$//'
}

EXITSTATUS=0

# Do not store md5sums by default:
MD5SUM=0

# So that we know what to expect...
umask 022
TAR=tar

usage() {
 cat << EOF
Usage: installpkg [options] <package_filename>

Installpkg is used to install a .t{gz,bz,lz,xz} package like this:
   installpkg slackware-package-1.0.0-i486-1.tgz (or .tbz, .tlz, .txz)

options:     --root /mnt (install someplace else, like /mnt)
EOF
}

# Strip version, architecture and build from the end of the name
package_name() {
  pkgbase $1 | sed 's?-[^-]*-[^-]*-[^-]*$??'
}

# Parse options:
while [ 0 ]; do
  if [ "$1" = "-root" -o "$1" = "--root" ]; then
    if [ "$2" = "" ]; then
      usage
      exit
    fi
    ROOT="$2"
    shift 2
  else
    break
  fi
done

# Set the prefix for the package database directories (packages, scripts).
ADM_DIR="$ROOT/var/log"
# If the directories don't exist, "initialize" the package database:
for PKGDBDIR in packages removed_packages removed_scripts scripts setup ; do
  if [ ! -d $ADM_DIR/$PKGDBDIR ]; then
    rm -rf $ADM_DIR/$PKGDBDIR # make sure it's not a symlink or something stupid
    mkdir -p $ADM_DIR/$PKGDBDIR
    chmod 755 $ADM_DIR/$PKGDBDIR 
  fi
done

# Make sure there's a proper temp directory:
TMP=$ADM_DIR/setup/tmp
# If the $TMP directory doesn't exist, create it:
if [ ! -d $TMP ]; then
  rm -rf $TMP # make sure it's not a symlink or something stupid
  mkdir -p $TMP
  chmod 700 $TMP # no need to leave it open
fi

# usage(), exit if called with no arguments:
if [ $# = 0 ]; then
  usage;
  exit
fi

# Main loop:
for package in $* ; do

  # Simple package integrity check:
  if [ ! -f $package ]; then
    echo "Cannot install $package:  file not found"
    exit 1
  fi

  # "shortname" isn't really THAT short...
  # it's just the full name without ".t{gz,bz,lz,xz}"
  shortname="$(pkgbase $package)"
  packagedir="$(dirname $package)"
  # This is the base package name, used for grepping tagfiles and descriptions:
  packagebase="$(package_name $shortname)"

  # Reject package if it does not end in '.t{gz,bz,lz,xz}':
  if [ "$shortname" = "$(basename $package)" ]; then
    echo "Cannot install $package:  file does not end in .tgz, .tbz, .tlz, or .txz"
    exit 1
  fi

  # Determine extension:
  packageext="$(echo $package | rev | cut -f 1 -d . | rev)"

  # Determine compressor utility:
  case $packageext in
  'tgz' )
    packagecompression=gzip
    ;;
  'tbz' )
    packagecompression=bzip2
    ;;
  'tlz' )
    packagecompression=lzip
    ;;
  'txz' )
    packagecompression=xz
    ;;
  esac

  # Test presence of external compression utility:
  if ! $packagecompression --help 1> /dev/null 2> /dev/null ; then
    echo "Cannot install $package:  external compression utility $packagecompression missing"
    exit 1
  fi

  # Figure out some package information, like the compressed and uncompressed
  # sizes, and where to find the package description:
  COMPRESSED="$(/bin/du -sh "$(readlink -f $package)" | cut -f 1)"

  # Test tarball integrity and get uncompressed package size:
  echo "Verifying package $(basename $package)."
  cat $package | $packagecompression -dc | dd 2> $TMP/tmpsize$$ | $TAR tf - 1> $TMP/tmplist$$ 2> /dev/null
  TARERROR=$?
  if [ ! "$TARERROR" = "0" ]; then
    echo "Unable to install $package:  tar archive is corrupt (tar returned error code $TARERROR)"
    rm -f $TMP/tmplist$$ $TMP/tmpsize$$
    exit 1
  fi
  UNCOMPRESSED="$(cat $TMP/tmpsize$$ | tail -n 1 | cut -f 1 -d ' ' | numfmt --to=iec)"
  rm -f $TMP/tmpsize$$

  # If we still don't have a package description, look inside the package.
  # This requires a costly untar.
  if [ "$DESCRIPTION" = "" ]; then
    mkdir -p $TMP/scan$$
    ( cd $TMP/scan$$ ; $packagecompression -dc | $TAR xf - install ) < $package 2> /dev/null
    ( cd $TMP/scan$$ ; $packagecompression -dc | $TAR xf - share ) < $package 2> /dev/null 
    if [ "$( find $TMP/scan$$/share -name "$packagebase.SMBuild" | wc -l)" == "1" ] ; then
      source "$( find $TMP/scan$$/share -name "$packagebase.SMBuild" )"
      # The build file contains the $DESC variable. We use that as our description
      DESCRIPTION="$(echo $desc)"
      # Set a custom variable once we source the application build file
      SMLINUX_DESC=1
    fi
  fi

  echo "Size: Compressed: ${COMPRESSED}, uncompressed: ${UNCOMPRESSED}." >> $TMP/tmpmsg$$
  # For recent versions of dialog it is necessary to add \n to the end of each line
  # or it will remove repeating spaces and mess up our careful formatting:
  cat << EOF > $TMP/controlns$$
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
EOF
  paste -d "" $TMP/tmpmsg$$ $TMP/controlns$$ > $TMP/pasted$$
  rm -f $TMP/controlns$$
  mv $TMP/pasted$$ $TMP/tmpmsg$$
  # Emit information to the console:
  if [ "$PMSG" = "" ]; then
    echo "Installing package $(basename $package):"
  else
    echo "Installing package $(basename $package) $PMSG:"
  fi

  echo "PACKAGE DESCRIPTION:"
  
  # If SMLINUX_DESC is set, echo that description
  if [ -n "$SMLINUX_DESC" ] && [ "$SMLINUX_DESC" == "1" ] ; then 
    echo ""
    echo "<<<< $DESCRIPTION >>>>"
    echo ""
  fi

  # Make sure there are no symbolic links sitting in the way of
  # incoming package files:
    grep -v "/$" $TMP/tmplist$$ | while read file ; do
    if [ -L "$ROOT/$file" ]; then
      rm -f "$ROOT/$file"
    fi
  done
  rm -f $TMP/tmplist$$

  # Write the package file database entry and install the package:
  echo "PACKAGE NAME:     $shortname" > $ADM_DIR/packages/$shortname
  echo "COMPRESSED PACKAGE SIZE:     $COMPRESSED" >> $ADM_DIR/packages/$shortname
  echo "UNCOMPRESSED PACKAGE SIZE:     $UNCOMPRESSED" >> $ADM_DIR/packages/$shortname
  echo "PACKAGE LOCATION: $package" >> $ADM_DIR/packages/$shortname
  echo "PACKAGE DESCRIPTION:" >> $ADM_DIR/packages/$shortname
  if [ -n "$SMLINUX_DESC" ] ; then
    echo $DESCRIPTION >> $ADM_DIR/packages/$shortname 2> /dev/null
  fi
  if [ "$shortname" != "$packagebase" ]; then
    if [ -n "$SMLINUX_DESC" ] ; then
      echo $DESCRIPTION >> $ADM_DIR/packages/$shortname 2> /dev/null
    else
      grep "^$shortname:" $DESCRIPTION >> $ADM_DIR/packages/$shortname 2> /dev/null
    fi
  fi
  echo "FILE LIST:" >> $ADM_DIR/packages/$shortname
  ( cd $ROOT/ ; $packagecompression -dc | $TAR -xlUpvf - | sort ) < $package >> $TMP/$shortname 2> /dev/null
  if [ "$( grep '^\./' $TMP/$shortname | wc -l | tr -d ' ')" = "1" ]; then
    # Good.  We have a package that meets the Slackware spec.
    cat $TMP/$shortname >> $ADM_DIR/packages/$shortname
  fi
  rm -f $TMP/$shortname

  if [ -f $ROOT/install/doinst.sh ]; then
    echo "Executing install script for $(basename $package)."
    # If bash is available, use sed to convert the install script to use pushd/popd
    # rather than spawning subshells which is slow on ARM.  This will also speed up
    # install script processing on any platform.
    ( cd $ROOT/ ; sh install/doinst.sh ; )
  fi 
  # Clean up the mess...
  if [ -d $ROOT/install ]; then
    if [ -r $ROOT/install/doinst.sh ]; then
      cp $ROOT/install/doinst.sh $ADM_DIR/scripts/$shortname
      chmod 755 $ADM_DIR/scripts/$shortname
    fi
    # /install/doinst.sh and /install/slack-* are reserved locations for the package system.
    ( cd $ROOT/install ; rm -f doinst.sh slack-* 1> /dev/null 2>&1 )
    rmdir $ROOT/install 1> /dev/null 2>&1
  fi
  # If we used a scan directory, get rid of it:
  if [ -d "$TMP/scan$$" ]; then
    rm -rf "$TMP/scan$$"
  fi
  rm -f $TMP/tmpmsg$$ $TMP/reply$$
  echo "Package $(basename $package) installed."
  echo
done

exit $EXITSTATUS
