#!/bin/bash
###############################################################################
# Debian Paket Builder
# A wrapper to debbuild
#------------------------------------------------------------------------------
# This script is intended to fill a little gap in debbuild, which does not
# interpret the %dir tag. As a side-effect, it eases package creation for
# programmers who don't want to care about packaging too much - but still
# want to provide packages for their users. Thus, it automats package creation.
#
# Requirements are the same as for debbuild, which the script finally calls.
# Of course, you may modify the settings at the top of the script to call
# rpmbuild instead - so you can use it to build RPMs as well (just modify
# BUILDDEB to point to "/usr/src/rpm" (or "/usr/share/redhat, whatever the
# location is with your distribution), plus DEBBUILD to point to "rpmbuild",
# and you are done.
#
# To use the script finally, you need to set up a template SPEC file. In there,
# you *can* use 2 placeholders which are filled by this script:
# __VERSION__ will be replaced with the release (cmdline option "-r")
# __DIR__     will be replaced with the complete filelist of your distribution
# Setup the distribution directory (i.e. make a copy, clean up all CVS/SVN
# files, re-arrange files if necessary - e.g. the %doc files need to be
# under usr/share/doc/), and run the script. The result will be:
# - a tarball in $BUILDDEB/SOURCES
# - a source package in $BUILDDEB/SDEBS (or $BUILDDEB/SRPMS)
# - a binary package in the directory for the corresponding architecure
###############################################################################
# $Id: pkgmake 98 2008-07-14 10:36:27Z izzy $

#===============================================[ Setup Script environment ]===
#---------------------------------------------------------------[ Settings ]---
BUILDDEB="/usr/src/debian"       	# Where the packages are located
DEBBUILD="debbuild"			# debbuild executable
RPMBUILD="rpmbuild"			# rpmbuild executable
SPEC2ARCH="spec2arch"			# spec2arch executable
# Some defaults:
VENDOR="root <root@`hostname`>" 	# Who wrote it
VENDORURL=""		  		# Default vendor URL (Escape slashes!)
PACKAGER="root <root@`hostname`>" 	# Who made the package
BUILDARCH="noarch"                      # Target Architecture (noarch,i386,...)
LICENSE="GPL"                           # License of the program
RELEASE="1"                        	# Release of this version
GROUP="Applications\/Internet"         	# RPM group this goes to
SECTION=""              	        # Debian section this goes to
SPECONLY=0                              # we not only create the spec by default
MKTAR=1                                 # Create tarball from source
NUKECVS=1                               # Cleanup CVS/* and .svn/* from source?
MKDEB=1					# Make Debian package (*.deb)?
MKRPM=0					# Make RPM package (*.rpm)?
MKSDEB=0				# Make Debian source package (*.sdeb)?
MKSRPM=0				# Make RPM source package (*.src.rpm)?
DEBOPTS=""
RMDSPEC=1                               # Remove .dspec after processing
RMSPEC=1                                # Remove .spec after processing
CHANGELOGSORT=1                         # Shall we care for the changelogs order?
AUTOSECT=0				# Automatically derive Debian section
PKGBUILD=0				# Create the PKGBUILD file and include it in tarball

# Don't change anything below this line except you know what you're doing
BINDIR=${0%/*}				# where this script resides
PREFIX="/"				# absolute path needed for *.deb
TMPFILE="/tmp/flist.$$"			# we need some tempfile
QUIET=0                                 # Shall we shutup ourself?
PKGMV=0.0.0                             # Version of this script (kept in /etc/pkgmake/version)
S2APARMS=""				# Optional parameters to spec2arch
[ -f /etc/pkgmake/version ] && . /etc/pkgmake/version

#-----------------------------------------------------------------[ Colors ]---
red='\e[0;31m'
blue='\e[0;34m'
blink='\E[5m'
NC='\e[0m'              # No Color

#================================================[ little helper functions ]===
#-----------------------------------------------------------[ Display help ]---
function help {
  SCRIPT=${0##*/}
  clear
  echo
  echo -e "${blue}==============================================================================="
  echo "Package Builder v${PKGMV}          (c) 2007 by Itzchak Rehberg (devel@izzysoft.de)"
  echo -e "-------------------------------------------------------------------------------$NC"
  echo "This script is a wrapper to debbuild  (which is a wrapper to the Debian package"
  echo "building binaries)  and  rpmbuild.   It shall  simplify  the build process  for"
  echo "developers by automatizing mosts steps."
  echo "Distributed under the terms of the GPL. No warranties - use at your own risk!"
  echo -e "${blue}-------------------------------------------------------------------------------$NC"
  echo "Syntax: ${SCRIPT} <PackageName> <Version> [Options]"
  echo "  Parameter:"
  echo "     <PackageName>              Name of the package"
  echo "     <Version>                  Version of this release"
  echo "  Options (overwrite defaults):"
  echo "     -a <author/vendor>         Vendor for this package (default: ${VENDOR})"
  echo "     -autosect			Automatically derive Debian section from RPM group"
  echo "     -b <build architecture>    Target architecture (default: ${BUILDARCH})"
  echo "     -c <changelog file>        Filename of changelog file"
  echo "     -conf <conffiles>          Space separated list of files to thread as %config"
  echo "     -d <directory root>        Where to take the files from"
  echo "     -deb			Make *.deb even if MKDEB=0"
  echo "     -descfile <file>           Filename of the file holding the long desc"
  echo "     -g <group>                 Group for this package (escape slashes!)"
  echo "     -keepdspec                 Don't remove the .dspec file after processing"
  echo "     -l <license>               License of the program (default: ${LICENSE})"
  echo "     -nodeb			Don't make *.deb even if MKDEB=1"
  echo "     -nonukecvs                 Don't cleanup CVS/* and .svn/* files from source"
  echo "     -norpm			Don't make *.rpm even if MKRPM=1"
  echo "     -nopkgbuild		Don't create PKGBUILD file even if PKGBUILD=1"
  echo "     -nosdeb			Don't make Debian source package"
  echo "     -nosrpm			Don't make RPM source package"
  echo "     -notar                     Don't create the tarball (i.e. it's already there)"
  echo "     -p <packager>              Packager for this package (default: ${PACKAGER})"
  echo "     -pkgbuild			Create the ArchLinux PKGBUILD file even if PKGBUILD=0"
  echo "     -pkgbuildfile <file>	Create PKGBUILD file at the specified location"
  echo "     -prov <provides>           Space separated list of provides"
  echo "     -r <release>               Release of this version (default: ${RELEASE})"
  echo "     -req <requires>            Space separated list of required packages"
  echo "     -rpm			Make *.rpm even if MKRPM=0"
  echo "     -q	                        Be Quiet (subprocesses)"
  echo "     -Q	                        Be Quiet (ourself)"
  echo "     -s <summary>               Short description (put in quotes!)"
  echo "     -s2aparms \"parms\"	Additional parameters to pass to spec2arch"
  echo "     -sdeb			Make Debian source package (*.sdeb)"
  echo "     -section <section>         Make separate *.dspec file with given section"
  echo "     -speconly                  Only create the SPEC file and exit, no build"
  echo "     -srpm			Make RPM source package (*.src.rpm)"
  echo "     -t <TemplateFile>          Template file (default: <PackageName>.tpl)"
  echo "     -u <vendor URL>            Vendor URL for this package (default: ${VENDORURL})"
  echo
  echo " The SPEC template file must reside in the ${BUILDDEB}/SPEC directory."
  echo
  echo "See 'man pkgmake' for more information."
  echo -e "${blue}===============================================================================$NC"
  echo
  exit
}

#-----------------------------------------------[ Show progress (or don't) ]---
function say {
  [ $QUIET -eq 0 ] && echo -e "$1"
}

#------------------[ Read one char user input and convert it to lower case ]---
function yesno {
  read -n 1 -p "" ready
  echo
  res=`echo $ready|tr [:upper:] [:lower:]`
}

function stayorgo {
  [ "$res" != "y" ] && {
    echo "* Process canceled."
    exit 0
  }
  echo
}

#---------------------------------------------------[ Output script header ]---
function header {
  [ $QUIET -eq 0 ] && clear
  say "${blue}pkgmake v${PKGMV}"
  say "--------------"
  say
  say "Preparing ${PROG} v${VERSION} for release:${NC}"
}

#-------------------------------------------------------------[ ErrorExits ]---
function nospec {
  header
  echo -e "${red}SPEC file template (${SPECTPL}) not found, aborting.$NC"
  exit 2
}

function nosrc {
  header
  echo -e "${red}Sources of $PROG v$VERSION (${SRCDIR}/*) not found, aborting.$NC"
  exit 3
}

function notar {
  header
  echo -e "${red}Tarball for $PROG v$VERSION (${BUILDDEB}/SOURCES/${PROG}-${VERSION}.tar.gz) not found, aborting.$NC"
  exit 4
}

function finito {
  say "${blue}* Done.$NC"
  say
  exit
}

#--------------------------[ Output a file entry to the debbuild file list ]---
function list {
  echo ${PREFIX}$1 >>$TMPFILE
}

#--------------[ Walk the source and create include file list for debbuild ]---
function walkdir {
  local DIR=$1
  if [ -d $DIR ]; then
    for entry in ${DIR}/*; do
      walkdir "${entry}"
    done
  elif [ -f $DIR ]; then
    list "${entry}"
  elif [ -h $DIR ]; then
    list "${entry}"
  fi
}

#========================================[ Sort the ChangeLog by date desc ]===
# $1 is the changelog input file. (Sorted) output will be appended to $2
function changelog_sort {
  local infile=$1
  local outfile=$2
  # Internal Field Separator by default is " " (space), which would truncate
  # trailing spaces
  IFS_ORI=$IFS
  IFS="§"
  # switch off file name expansion - changelog uses "*" at line start!
  set -f

# ----------------------------------------------------------[ Setup months ]---
  Jan="01"; Feb="02"; Mar="03"; Apr="04"; May="05"; Jun="06";
  Jul="07"; Aug="08"; Sep="09"; Oct="10"; Nov="11"; Dec="12";

#---------------------------------------[ Read the original changelog file ]---
  # $change[0..n] = "YYYYMMDD"
  # $changename[YYYYMMDD] = "* Thu Jul 26 2007 John Doe <john@doe.com>"
  # $change_YYYYMMDD[0..n] = <list of changes>
  typeset -i num=0; typeset -i i=0;
  while read line
  do
    if [ "${line:0:1}" = "*" ]; then
      eval mon=\$${line:6:3}
      ts="${line:13:4}${mon}${line:10:2}$num"
      change[$num]=$ts
      changename[$ts]=$line
      cur=$num
      let num=$num+1; let i=0
    else
      eval varname=change_\${ts}
      eval $varname[$i]="\$line"
      let i=$i+1
    fi
  done <$infile

#----------------------------------------------------[ sort the date array ]---
  for var in ${change[*]}; do x="$x\n`echo $var`"; done
  y=`echo -e $x|sort -r|tr "\n" " "`
  IFS=" "; set $y; IFS="§"; let num=0
  while [ -n "$1" ]; do
    change[$num]=$1
    let num=$num+1
    shift
  done

#----------------------------------------[ Write the sorted changelog file ]---
  for ts in ${change[*]}; do
    eval line=\${changename[\$ts]}
    echo $line >>$outfile
    eval varname=change_\${ts}
    eval count=\${#$varname[*]}
    typeset -i run=0
    while [ $run -lt $count ]; do
      eval line=\${$varname[$run]}
      echo $line >>$outfile
      let run=$run+1
    done
  done

#----------------------------------------------------[ restore environment ]---
  set +f
  IFS=$IFS_ORI
}


#=============================================================[ Do the job ]===
#----------------------------------------------[ Read config file (if any) ]---
[ -f /etc/pkgmake/pkgmake.conf ] && . /etc/pkgmake/pkgmake.conf
[ -f ~/.pkgmake/pkgmake.conf ] && . ~/.pkgmake/pkgmake.conf

#-------------------------------------------[ process command line options ]---
typeset -i SILENT=0
typeset -i SILENTc=0
PROG=$1
VERSION=$2
while [ "$1" != "" ] ; do
  case "$1" in
    -a) shift; VENDOR=$1;;
    -autosect) AUTOSECT=1;;
    -b) shift; BUILDARCH=$1;;
    -c) shift; CHANGELOG=$1; [ "${CHANGELOG:0:1}" != "/" ] && CHANGELOG="`pwd`/$CHANGELOG";;
    -conf) shift; CONF=$1;;
    -d) shift; SRCDIR=$1;;
    -deb) MKDEB=1;;
    -debopt) shift; DEBOPTS=$1;;
    -descfile) shift; DESCFILE=$1;;
    -g) shift; GROUP=$1;;
    -l) shift; LICENSE=$1;;
    -keepdspec) RMDSPEC=0;;
    -keepspec) RMSPEC=0;;
    -nochangelogsort) CHANGELOGSORT=0;;
    -nodeb) MKDEB=0;;
    -nonukecvs) NUKECVS=0;;
    -nopkgbuild) PKGBUILD=0;;
    -norpm) MKRPM=0;;
    -nosdeb) MKSDEB=0;;
    -nosrpm) MKSRPM=0;;
    -notar) MKTAR=0;;
    -p) shift; PACKAGER="$1";;
    -pkgbuild) PKGBUILD=1;;
    -pkgbuildfile) shift; PKGBUILD=1; PKGBUILDFILE="$1";;
    -prov) shift; PROV=$1;;
    -q) [ $SILENTc -lt 2 ] && let SILENTc=$SILENT+1;;
    -Q) QUIET=1;;
    -r) shift; RELEASE=$1;;
    -req) shift; REQ=$1;;
    -rpm) MKRPM=1;;
    -rpmopt) shift; RPMOPTS=$1;;
    -s) shift; SUMMARY=$1;;
    -s2aparms) shift; S2APARMS="$1";;
    -sdeb) MKSDEB=1;;
    -section) shift; SECTION=$1;;
    -speconly) SPECONLY=1;;
    -srpm) MKSRPM=1;;
    -t) shift; SPECTPL="${BUILDDEB}/SPECS/$1";;
    -u) shift; VENDORURL=$1;;
  esac
  shift
done
[ $SILENTc -gt 0 ] && SILENT=$SILENTc

[ -z "$PROG" ] && help
[ -z "$VERSION" ] && help

#----------------------------------------------------[ check preconditions ]---
# SPEC file
[ -z "$SPECTPL" ] && SPECTPL="${BUILDDEB}/SPECS/${PROG}.tpl"
[ -f "${SPECTPL}" ] || nospec
# Sources
if [ $MKTAR -gt 0 ]; then
  if [ -z "$SRCDIR" ]; then
    SRCDIR="${BUILDDEB}/BUILD/${PROG}-${VERSION}"
    [ -d "$SRCDIR" ] || nosrc
  else
    [ -d "$SRCDIR" ] || nosrc
    rm -rf ${BUILDDEB}/BUILD/${PROG}-${VERSION}
    cp -rp $SRCDIR ${BUILDDEB}/BUILD/${PROG}-${VERSION}
    SRCDIR="${BUILDDEB}/BUILD/${PROG}-${VERSION}"
  fi
  [ $NUKECVS -gt 0 ] && {
    cd $SRCDIR
    find . -type d -name "CVS" | xargs rm -fR
    find . -type d -name ".svn" | xargs rm -fR
    rc=`cd -`
  }
else
  [ -f ${BUILDDEB}/SOURCES/${PROG}-${VERSION}.tar.gz ] || notar
  rm -rf ${BUILDDEB}/BUILD/${PROG}-${VERSION}
  cd ${BUILDDEB}/BUILD
  tar xzf ${BUILDDEB}/SOURCES/${PROG}-${VERSION}.tar.gz
  cd -
  [ $NUKECVS -gt 0 ] && {
    cd ${BUILDDEB}/BUILD/${PROG}-${VERSION}
    find . -type d -name "CVS" | xargs rm -fR
    find . -type d -name ".svn" | xargs rm -fR
    cd -
  }
fi

#-----------------------------------------------------------[ print header ]---
header

#----------------------------------------------------[ preparing SPEC file ]---
say "${blue}* Preparing SPEC file$NC"
SPECFILE=${BUILDDEB}/SPECS/${PROG}-${VERSION}.spec
DSPECFILE=${BUILDDEB}/SPECS/${PROG}-${VERSION}.dspec
cd "${BUILDDEB}/BUILD/${PROG}-${VERSION}"
# Setup filelist
for i in *; do
  walkdir "$i"
done
# Requirements
[ -n "$REQ" ] && {
  typeset -i c=0
  for r in $REQ; do
    [ $c -gt 0 ] && REQUIRES="${REQUIRES}\n";
    REQUIRES="${REQUIRES}Requires: $r"
    let c=$c+1
  done
}
# Provides
[ -n "$PROV" ] && {
  typeset -i c=0
  for r in $PROV; do
    [ $c -gt 0 ] && PROVIDES="${PROVIDES}\n";
    PROVIDES="${PROVIDES}Provides: $r"
    let c=$c+1
  done
}
# ConfFiles
[ -n "$CONF" ] && {
  typeset -i c=0
  for r in $CONF; do
    [ $c -gt 0 ] && CONFIG="${CONFIG}\n";
    CONFIG="${CONFIG}%config $r"
    let c=$c+1
  done
}
# Search and Replace the template vars
cat $SPECTPL | sed "s/__RELEASE__/${RELEASE}/g" | sed "s/__NAME__/${PROG}/g" \
 | sed "s/__VENDOR__/${VENDOR}/g" | sed "s/__PACKAGER__/${PACKAGER}/g" \
 | sed "s/__BUILDARCH__/${BUILDARCH}/g" | sed "s/__CONFIG__/${CONFIG}/g" \
 | sed "s/__SUMMARY__/${SUMMARY}/g" \
 | sed "s/__LICENSE__/${LICENSE}/g" | sed "s/__VERSION__/${VERSION}/g" \
 | sed "/__DIR__/ r ${TMPFILE}" | sed "/__DIR__/ d" > $SPECFILE
if [ -f "${DESCFILE}" ]; then
  cat $SPECFILE | sed "/__DESCRIPTION__/ r ${DESCFILE}" | sed "/__DESCRIPTION__/ d" > $TMPFILE
else
  cat $SPECFILE | sed "s/__DESCRIPTION__/${SUMMARY}/g" > $TMPFILE
fi
# The Vendor URL:
if [ -n "$VENDORURL" ]; then
  VENDORURL="URL: ${VENDORURL}"
  cat $TMPFILE | sed "s/__VENDORURL__/${VENDORURL}/g" > $SPECFILE
else
  cat $TMPFILE | sed "/__VENDORURL__/ d" > $SPECFILE
fi
# Manual Requires:
if [ -n "${REQUIRES}" ]; then
  cat $SPECFILE | sed "s/__REQUIRES__/${REQUIRES}/g" > $TMPFILE
else
  cat $SPECFILE | sed "/__REQUIRES__/ d" > $TMPFILE
fi
# Manual Provides:
if [ -n "${PROVIDES}" ]; then
  cat $TMPFILE | sed "s/__PROVIDES__/${PROVIDES}/g" > $SPECFILE
else
  cat $TMPFILE | sed "/__PROVIDES__/ d" > $SPECFILE
fi
mv $SPECFILE $TMPFILE
# Debian section?
[ $AUTOSECT -gt 0 ] && {
  if [ -f ~/.pkgmake/autosect ]; then
    $asect=~/.pkgmake/autosect
  elif [ -f /etc/pkgmake/autosect ]; then
    $asect=/etc/pkgmake/autosect
  fi
  [ -n "$asect" ] && {
    $SECTION=`cat $asect|grep $GROUP|awk -F: '{print $2}'`
  }
}
if [ -n "$SECTION" ]; then
  cat $TMPFILE | sed "s/__GROUP__/${SECTION}/g" | sed "/__RPM_REQUIRES__/d" | sed "s/__DEB_REQUIRES__/Requires/g" \
  | sed "s/__RECOMMENDS__/Recommends/g" | sed "s/__SUGGESTS__/Suggests/g" | sed "s/__REPLACES__/Replaces/g" >$DSPECFILE
else
  cat $TMPFILE | sed "/__RPM_REQUIRES__/d" | sed "s/__DEB_REQUIRES__/Requires/g" \
  | sed "s/__RECOMMENDS__/Recommends/g" | sed "s/__SUGGESTS__/Suggests/g" | sed "s/__REPLACES__/Replaces/g" >$DSPECFILE
fi
# RPM group
cat $TMPFILE | sed "s/__GROUP__/${GROUP}/g" | sed "/__DEB_REQUIRES__/d" | sed "s/__RPM_REQUIRES__/Requires/g" \
 | sed "/__RECOMMENDS__/d" | sed "/__SUGGESTS__/d" | sed "/__REPLACES__/d" >$SPECFILE
# ChangeLog:
if [ -n "$PKGMAKE_USED" ]; then
  PKGMAKE_USED="using pkgmake v${PKGMV} & ${PKGMAKE_USED}"
else
  PKGMAKE_USED="using pkgmake v${PKGMV}"
fi
echo "* `LANG=en_EN date +"%a %b %d %Y"` ${PACKAGER}"> $TMPFILE
echo "- packaged ${PROG}_${VERSION}-${RELEASE} ${PKGMAKE_USED}" >>$TMPFILE
[ -n "${CHANGELOG}" ] && [ -f "${CHANGELOG}" ] && {
  echo >>$TMPFILE
  cat ${CHANGELOG} >> $TMPFILE
}
if [ $CHANGELOGSORT -gt 0 ]; then
  changelog_sort $TMPFILE $SPECFILE
else
  cat $TMPFILE >> $SPECFILE
fi
cat $TMPFILE >>$DSPECFILE

rm -f $TMPFILE

[ $SPECONLY -eq 1 ] && finito

#---------------------------------------------------[ Create PKGBUILD file ]---
if [ $PKGBUILD -gt 0 -a $MKTAR -gt 0 ]; then
  say "${blue}* Generating PKGBUILD file$NC"
  [ -z "$PKGBUILDFILE" ] && PKGBUILDFILE="${BUILDDEB}/BUILD/${PROG}-${VERSION}/PKGBUILD"
  $SPEC2ARCH $SPECFILE $PKGBUILDFILE $S2APARMS
fi

#---------------------------------------------------------[ create tarball ]---
if [ $MKTAR -gt 0 ]; then
  say "${blue}* Creating tarball$NC"
  cd "${BUILDDEB}/BUILD/"
  tar czf ${BUILDDEB}/SOURCES/${PROG}-${VERSION}.tar.gz ${PROG}-${VERSION}
fi

#---------------------------------------------------[ building the package ]---
if [ $MKSDEB -eq 0 ]; then DEBPARM="-bb"; else DEBPARM="-ba"; fi
if [ $MKSRPM -eq 0 ]; then RPMPARM="-bb"; else RPMPARM="-ba"; fi
[ $MKDEB -gt 0 ] && {
  say "${blue}* Running ${DEBBUILD}$NC"
  case "$SILENT" in
    1)   eval "$DEBBUILD $DEBPARM $DEBOPTS $DSPECFILE >/dev/null" ;;
    2|3) eval "$DEBBUILD $DEBPARM $DEBOPTS $DSPECFILE &>/dev/null" ;;
    *)   eval "$DEBBUILD $DEBPARM $DEBOPTS $DSPECFILE" ;;
  esac
}
[ $MKRPM -gt 0 ] && {
  [ $MKDEB -gt 0 ] && say
  say "${blue}* Running ${RPMBUILD}$NC"
  case "$SILENT" in
    1)   eval "$RPMBUILD $RPMPARM $RPMOPTS $SPECFILE >/dev/null" ;;
    2|3) eval "$RPMBUILD $RPMPARM $RPMOPTS $SPECFILE &>/dev/null" ;;
    *)   eval "$RPMBUILD $RPMPARM $RPMOPTS $SPECFILE" ;;
  esac
}
[ $RMSPEC -gt 0 ] && rm -f $SPECFILE
if [ $RMDSPEC -gt 0 ]; then
  if [ "$SPECFILE" != "$DSPECFILE" ]; then
    if [ -f "$DSPECFILE" ]; then
      rm -f "$DSPECFILE"
    fi
  fi
fi

finito
