#!/bin/sh
##############################################################################
# buildpkg
# Install and/or build a Vector Linux (slackware) package from source tarball 
# The script will produce:
#   package-version-ARCH-RELEASE.tgz
#   package-version-ARCH-RELEASE.txt
#   package-version-ARCH-RELEASE.tgz.md5
# and optionally install it.
#
# Usage :
# * Arange packages in a tree stucture, start on $BASE/$PGROUP/$PNAME
#
# * On each $BASE/$PGROUP/$PNAME dir, prepare :
#   the_tarbal (tar.gz/tar.bz2). If not exist then custom only 
#   custom (directory, tar.gz, or tar.bz2), will be copied to /) 
#   custom-prefix (directory, tar.gz, or tar.bz2), will be copied to $PREFIX   
#   description-pak
#   install-pak
#   changelog-pak
#   VCompile   optional non standard compilation script
#   VBuild     build script that defines some env var ten call this script
#
# * create $BASE/$PGROUP/$PNAME/VBuild script that call this pkgbuild script.
#   Before calling the pkgbuild, export these environment variables
#     PNAME    = package name (default = current dir)
#     PVERSION = package version. overwritten by the tarball version
#     PREFIX   = the install prefix (default = /usr/local)
#     DOC_PREFIX = the documentation prefix (default = not copied).
#                  standard build should set it to /usr/doc
#     CONFIGURE  = configuration options, including the --prefix
#
# * create $BASE/build script that call the VBuild scripts
#   Set these environment variables before calling the VBuild scripts
#     PGROUP   = package group (base,dev,app, default = none)
#     PRELEASE = release (1,vl4,slack9,etc. default = 1)
#     MARCH    = architecture (i386,i486,etc. default = the host)
#     MCPU     = the intended CPU (i386,i486,etc. default = the host)
#     CFLAGS   = C compiler flags (default = none). 
#                It will be appended with -march=$ARCH -mcpu=$CPU
#     CXXFLAGS = C++ compiler flags (default = $CFLAGS)
#
#     SRC_DIR  = extracted source directory (default = /tmp/src)
#     IMG_DIR  = temporary directory (default = /tmp/img)
#     PKG_DIR  = packages will be saved there (default = /tmp/pkg)
#
#     OVERWRITE_PKG= overwrite the package if exist (default = no)
#     INSTALL_PKG  = install the package (default = no)
#     CLEAN_SRC    = clean SRC and IMG after finished (default = no)
#
# * If the tarball does not follow standard compilation procedure, you must provide VCompile script
#   The standard compilation is:
#     ./configure $CONFIGURE
#     make 
#     make install DESTDIR=$IMG_DIR
#
# (c) 2003, Eko M. Budi
#
# Parts of this script were taken/mofied version from 
# - SlackBuild, commonly available in various Slackware's source packages
# - makepkg, Copyright 1994, 1998  Patrick Volkerding, Moorhead, Minnesota USA 
# - checkinstall 1.5.3, Copyright 2001 Felipe Eduardo Sanchez Diaz Duran
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
############################################################################

# determine the values
BUILDPKG_VERSION=0.1
CONFIGURE_CMD="./configure"
MAKE_CMD="make"
INSTALL_CMD="make install"
INSTALLPKG="/sbin/installpkg"
CHMOD="chmod"
CHOWN="chown"

CWD=`pwd`
[ -z "$PNAME" ] && PNAME=`basename $CWD`
[ -z "$PREFIX" ] && PREFIX=/usr/local
[ -z "$CUSTOM_PREFIX" ] && CUSTOM_PREFIX=$PREFIX
[ -z "$MARCH" ] && MARCH=`uname -m`
[ -z "$MCPU" ] && MCPU=`uname -m`
[ -z "$PRELEASE" ] && PRELEASE=1
[ -z "$SRC_DIR" ] && SRC_DIR=$HOME/src
[ -z "$IMG_DIR" ] && IMG_DIR=$HOME/tmp
[ -z "$PKG_DIR" ] && PKG_DIR=$HOME/pkg

PBASENAME="$PNAME-$VERSION"
if [ -f $PNAME*.tar.gz ]; then
  TARBALL=`ls $PNAME*.tar.gz` 
  PBASENAME=`basename "$TARBALL" .tar.gz`  
else 
  if [ -f $PNAME*.tar.bz2 ]; then
    TARBALL=`ls $PNAME*.tar.bz2` 
    PBASENAME=`basename "$TARBALL" .tar.bz2`
  else
    PBASENAME="$PNAME-$PVERSION"
  fi
fi
PLONGNAME="$PBASENAME-$MARCH-$PRELEASE"

if [ -f "$PLONGNAME.tgz" ]; then
  TGZBALL=`ls $PLONGNAME.tgz`
fi

# TODO, determine the version from the tarball

# add the ARCH and CPU to the FLAGS
export CFLAGS="$CFLAGS -march=$MARCH -mcpu=$MCPU"
if [ -z "$CXXFLAGS" ]; then
  export CXXFLAGS=$CFLAGS
else
  export CXXFLAGS="$CXXFLAGS -march=$MARCH -mcpu=$MCPU"
fi

SRCD=$SRC_DIR     # source location
PKGD=$PKG_DIR
IMGD=$IMG_DIR
if [ "$PGROUP" ]; then
   SRCD="$SRCD/$PGROUP"
   PKGD="$PKGD/$PGROUP"
   IMGD="$IMGD/$PGROUP" 
fi

mkdir -p $SRCD
mkdir -p $PKGD
mkdir -p $IMGD

if [ -d "$IMGD/$PBASENAME" ]; then
   rm -rf $IMG/$PBASENAME
fi
mkdir -p $IMGD/$PBASENAME

# TO DO: should check to overwrite it if the package is older
if [ -f "$PKGD/$PLONGNAME.tgz" ]; then
  if [ ! "$OVERWRITE_PKG" = "yes" ]; then
     NEWER=`find . -newer $PKGD/$PLONGNAME.tgz`
     if [ -z "$NEWER" ]; then
       echo $PLONGNAME.tgz is up to date. Skipping ...   
       exit 0
     fi
  fi
fi

echo "buildpkg $BUILDPKG_VERSION"
echo "(c) Eko M. Budi, 2003"
echo
echo "Source       : $TARBALL"
echo "Build target : $PLONGNAME"
echo

#############################################################################
# the functions


# Extract $CWD/package.tar.gz to $SRCD
function extract_tarball() {
  if [ -f $CWD/$PBASENAME.tar.bz2 ]; then
    echo "Extracting tarbal $PBASENAME.tar.bz2 ..."
    cd $SRCD
    tar -xjf $CWD/$PBASENAME.tar.bz2
  elif [ -f $CWD/$PBASENAME.tar.gz ]; then
    echo "Extracting tarbal $CWD/$PBASENAME.tar.gz ..."
    cd $SRCD
    tar -xzf $CWD/$PBASENAME.tar.gz
  fi
  if [ ! $? = 0 ]; then
    echo "ERROR: Can not extract the tarbal. Aborting .."
    exit 1
  fi
  if [ ! -d $SRCD/$PBASENAME ]; then
    echo "ERROR: Missing extracted source code. Aborting ..."
    exit 1 
  fi
}

function compile_src() {
  
  cd $SRCD/$PBASENAME
  if [ -x $CWD/VCompile ]; then
    source $CWD/VCompile  
  else
    echo "Configuring ..."
    ./configure $CONFIGURE
    if [ $? != 0 ]; then
      echo "ERROR: Configuration failed, aborting ..."
      exit 1;
    fi
    echo "Compiling ... "
    grep DESTDIR Makefile > /dev/null 2>&1
    if [ $? = 0 ]; then
       make && make install DESTDIR=$IMGD/$PBASENAME
    else
       make && make prefix=$IMGD/$PBASENAME/$PREFIX install
    fi
    if [ $? != 0 ]; then
      echo "ERROR: Compilation failed, aborting ..."
      exit 1;
    fi
  fi
}

# Just explode the package
function explode_tgz() {
  cd $IMGD/$PBASENAME
  explodepkg $CWD/$PLONGNAME.tgz
}

# Add documentations from the tarball
function add_docs() {
  
  if [ $DOC_PREFIX ]; then
    echo
    echo Adding documentations ...
    cd $IMGD/$PBASENAME
  
    mkdir -p ./$DOC_PREFIX/$PBASENAME
    cd ./$DOC_PREFIX/$PBASENAME
    for f in AUTHORS *COPYING* *COPYRIGHT* LICENSE *FAQ* INSTALL* *README* RELNOTES *BUG* *THANKS* ; do
      if [ -f "$SRCD/$PBASENAME/$f" ]; then
        cp $SRCD/$PBASENAME/$f .
      fi
    done
    if [ -d "$CWD/doc" ]; then
      cp -a $CWD/doc/* .
    fi
   
    # fix permission
    chmod -R 644 *
    chown -R root.users *
  else
    echo WARNING: documentation is not included
  fi
}

# add custom directory, custom.tar.gz or custom.tar.bz2
function add_custom() {
  echo
  echo "Adding customization ..."

  cd $IMGD/$PBASENAME
  if [ -d $CWD/custom ]; then
     cp -a $CWD/custom/* .
  elif [ -f $CWD/custom.tar.gz ]; then
     tar -xzvf $CWD/custom.tar.gz
  elif [ -f $CWD/custom.tar.bz2 ]; then
     tar -xjvf $CWD/custom.tar.bz2
  fi
  
  mkdir -p .$PREFIX
  cd .$PREFIX
  if [ -d $CWD/custom-prefix ]; then
     cp -a $CWD/custom-prefix/* .
  elif [ -f $CWD/custom-prefix.tar.gz ]; then
     tar -xzf $CWD/custom-prefix.tar.gz
  elif [ -f $CWD/custom-prefix.tar.bz2 ]; then
     tar -xjf $CWD/custom-prefix.tar.bz2
  fi
}

# add slackware's description
# 80% of this code was taken from checkinstall
function add_desc() {

  cd $IMGD/$PBASENAME
  mkdir -p install
  cat << EOF > install/slack-desc
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description.  
# Line up the first '|' above the ':' following the base package name, and 
# the '|' on the right side marks the last column you can put a character in. 
# You must make exactly 11 lines for the formatting to be correct.  
# It's also customary to leave one space after the ':'.

EOF

  # Calculate the spaces before the "handy-ruler"
  HR_SPACES=`echo $PNAME | wc -c| awk '{ for (i=1;substr ($0,i,1) ~ /[[:blank:]]/ ;i++); print substr ($0,i);}'`
  awk -v S=$HR_SPACES 'BEGIN {ORS=""; for (i=1; i < S; i++) print " ";}' >> install/slack-desc
  echo "|-----handy-ruler------------------------------------------------------|" >> install/slack-desc

  # add the contents
  if [ -f $CWD/description-pak ]; then
    cat $CWD/description-pak | while read line; do
      echo "$PNAME: $line" >> install/slack-desc
    done
  else
    echo "$PNAME: $PNAME" >> install/slack-desc
    echo "$PNAME: Built on " `uname -mrs` >> install/slack-desc
    echo "$PNAME: Date: " `date` >> install/slack-desc
  fi
}

# Add symlink to the doinstall script
# Taken  from makepkg
make_install_script() {
  COUNT=1
  LINE="`sed -n "$COUNT p" $1`"
  while [ ! "$LINE" = "" ]; do
   LINKGOESIN="`echo "$LINE" | cut -f 1 -d " "`" 
   LINKGOESIN="`dirname $LINKGOESIN`" 
   LINKNAMEIS="`echo "$LINE" | cut -f 1 -d ' '`"
   LINKNAMEIS="`basename "$LINKNAMEIS"`"
   LINKPOINTSTO="`echo "$LINE" | cut -f 3 -d ' '`"
   echo "( cd $LINKGOESIN ; rm -rf $LINKNAMEIS )"
   echo "( cd $LINKGOESIN ; ln -sf $LINKPOINTSTO $LINKNAMEIS )"
   COUNT=`expr $COUNT + 1`
   LINE="`sed -n "$COUNT p" $1`"
  done
}

# Create symlink for doinst.sh
# 99% of this code was taken from makepkg
function add_doinstall () {
  cd $IMGD/$PBASENAME
  mkdir -p install

  echo
  echo "Creating do install ..."

  echo "# doinstall.sh created by buildpkg $BUILDPKG_VERSION" > install/doinst.sh  

  echo "Searching for symbolic links:" 
  # Get rid of possible pre-existing trouble:
  INST=`mktemp /tmp/makepkg.XXXXXX`
  find . -type l -exec ls -l {} \; | while read foo ; do echo $foo ; done | cut -f 9- -d ' ' | cut -b3- | tee $INST
  if [ ! "`cat $INST`" = "" ]; then
    echo
    echo "Making symbolic link creation script:"
    make_install_script $INST | tee install/doinst.sh
    echo "Removing symbolic links:"
    find . -type l -exec rm -v {} \;
  fi

  # Add predefined doinst.sh
  echo "PREFIX=$PREFIX" >> install/doinst.sh
  if [ -f $CWD/install-pak ]; then
    echo Adding predefined install-pak
    cat $CWD/install-pak >> install/doinst.sh
  fi
}

# Create the slackware package
# 90% taken from makepkg
function make_pkg () {
  cd $IMGD/$PBASENAME

  echo
  echo "Creating the package ..."
  
  # Strip the ELFs
  ( find . | xargs file | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded )

  # fixing permission
  echo Fixing permission
  $CHOWN -R root.root .
  if [ -d .$PREFIX/bin ]; then 
    $CHOWN -R root.bin .$PREFIX/bin
  fi
  if [ -d .$PREFIX/sbin ]; then
    $CHOWN -R root.bin .$PREFIX/sbin
  fi
  find . -type d -exec $CHMOD 755 {} \;
  # find . -type d -exec $CHOWN -v root.root {} \;
 
  echo Tar-ing and Gzipping
  tar cvf $PBASENAME.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
  
  gzip -9 $PBASENAME.tar
    
  mv $PBASENAME.tar.gz $PKGD/$PLONGNAME.tgz

  # Delete temporary image
  cd $CWD
  rm -rf $IMGD/$PBASENAME
      
  if [ ! -f "$PKGD/$PLONGNAME.tgz" ]; then
    echo "ERROR: Could not build $PLONGNAME.tgz. Aborting ..."
    exit 1 
  fi 
}

# Create Text description
function make_txt() {
  echo
  echo Creating text description ...

  cd $PKGD
  TXTNAME="$PLONGNAME.txt"

  echo -n > $TXTNAME
  if [ -f "$CWD/description-pak" ]; then
    echo Adding description-pak
    cat $CWD/description-pak | while read line; do 
       echo $PNAME: $line >> $TXTNAME
    done
  else
    echo "$PNAME: $PNAME" >> $TXTNAME
  fi
  echo Adding build info
  echo "" >> $TXTNAME
  echo "-------------------------------------" >> $TXTNAME
  echo "BUILD INFO" >> $TXTNAME
  echo "  Host      :" `uname -mrs` >> $TXTNAME
  echo "  Date      :" `date` >> $TXTNAME
  echo "  CFLAGS    : $CFLAGS" >> $TXTNAME 
  echo -n "  CONFIGURE : " >> $TXTNAME
  for op in $CONFIGURE ; do
     echo $op >> $TXTNAME
     echo -n "          " >> $TXTNAME
  done
  echo >> $TXTNAME
  if [ -f $CWD/changelog-pak ]; then 
    echo Adding changelog-pak
    cat $CWD/changelog-pak >> $TXTNAME
  fi 
}

function make_md5() {
  echo
  echo Creating MD5 ...
  cd $PKGD
  md5sum $PLONGNAME.tgz > $PLONGNAME.tgz.md5
}

################################################################################
# Main 

if [ $TGZBALL ]; then
  explode_tgz
elif [ $TARBALL ]; then
  extract_tarball
  compile_src
else
  echo WARNING: No tarball. Building with custom only
fi
add_custom
add_doinstall
add_desc

make_pkg
make_md5
make_txt

if [ "$CLEAN_SRC" = "yes" ]; then
  echo Cleaning the source ...
  if [ -d "$SRCD/$PBASENAME" ]; then
     rm -rf $SRCD/$PBASENAME
  fi
fi

echo
echo "Package has been built. You may find it as"
echo "    $PKGD/$PLONGNAME.tgz"

if [ "$INSTALL_PKG" = "yes" ]; then
   echo
   $INSTALLPKG $PKGD/$PLONGNAME.tgz
   echo "Package has been installed. You may remove it later by using:"
   echo "   removepkg $PLONGNAME"
fi

echo =======================================================================
