#!/bin/bash
##########################################################################
# Slackware package build script v-0.2
#
# (C) 2013 Andrei Boros <slackware at andrix dot ro>
# based on slackbuilds.org scripts
##########################################################################

usage() {
cat << EOM
    usage: $0 [options]

    OPTIONS:
    -h		show this help
    -V version	build specified version (if available)
    -b build	build with specified build number
    -t tag	build with specified tag
    -f format	build package in specified format (tgz or txz)
    -s		configure for statically linked build
    -k		keep build files under /tmp
    -i		install package after build
    -c		cleanup source dir of previous builds (all)

EOM
}

copyleft() {
echo "package.slackbuild v-0.2 (C) 2013 slackware@andrix.ro"
echo
}

param() {
while getopts "hV:b:t:f:skic" OPTS; do
    case $OPTS in
	h)
	    usage
	    exit 1
	    ;;
	V)	VERSION=${OPTARG} ;;
	b)	BUILD=${OPTARG} ;;
	t)	TAG=${OPTARG} ;;
	f)	FMT=${OPTARG} ;;
	s)	STATIC=1 ;;
	k)	KEEP=1 ;;
	i)	INSTALL=1 ;;
	c)	CLEAN=1 ;;
	\?)
	    echo "use $0 -h for help"
	    exit 1
	    ;;
	*)
	    ;;
    esac
done
}

# Include custom build instructions (included here to set default VERSION and PRGNAM2)
if [ -f $(pwd)/package.build ]; then
    source $(pwd)/package.build
fi

PRGNAM=${PRGNAM:-$(basename $(pwd))}	 # name of program
PRGNAM2=${PRGNAM2:-${PRGNAM}}			 # alternate name (some don't save sources with same name, or same case)
					 # used only during build process
param $*
					 # version of program
VERSION=${VERSION:-$(echo $PRGNAM2-*.tar.?z* | rev | cut -f 3- -d . | cut -f 1 -d - | rev)}
BUILD=${BUILD:-1}
TAG=${TAG:-anx}                          # "_SBo" is required by SlackBuilds
FMT=${FMT:-$(if [ -x /usr/bin/xz ]; then echo "txz"; else echo "tgz"; fi)} # package format

# Include custom build instructions for this $VERSION
if [ -f $(pwd)/package.build-$VERSION ]; then
    source $(pwd)/package.build-$VERSION
fi

# Automatically determine the architecture we're building on:
if [ -z "" ]; then
    case "$( uname -m )" in
	i?86) ARCH=i486 ;;
	arm*) ARCH=arm ;;
	# Unless  is already set, use uname -m for all other archs:
	*) ARCH=$( uname -m ) ;;
    esac
fi

DOCS=${DOCS:-"ABOUT-NLS AUTHORS BUGS ChangeLog COPYING* INSTALL NEWS PROJECTS README* THANKS TODO VERSION"}
STATIC=${STATIC:-}

CWD=$(pwd)
TMP=${TMP:-/tmp/$(whoami)}		# Temporary
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-$(pwd)}		# Drop the package in same dir
NUMJOBS=${NUMJOBS:-" -j4 "}

# Where do we look for sources?
SRCDIR=$(cd $(dirname $0); pwd)
SOURCE=${SOURCE:-$(echo $PRGNAM2-$VERSION.tar.?z* | rev | cut -f 1 -d " " | rev)}
SRCURL=${SRCURL:-}

case "$ARCH" in
    i486)
	SLKCFLAGS="-O2 -march=i486 -mtune=i686"
	SLKLDFLAGS=""; LIBDIRSUFFIX=""
    ;;
    i686)
	SLKCFLAGS="-O2 -march=i686 -mtune=i686"
	SLKLDFLAGS=""; LIBDIRSUFFIX=""
    ;;
    x86_64)
	SLKCFLAGS="-O2 -fPIC"
	SLKLDFLAGS="-L/usr/lib64"; LIBDIRSUFFIX="64"
    ;;
    s390)
	SLKCFLAGS="-O2"
	SLKLDFLAGS=""; LIBDIRSUFFIX=""
    ;;
    powerpc)
	SLKCFLAGS="-O2"
	SLKLDFLAGS=""; LIBDIRSUFFIX=""
    ;;
    athlon-xp)
	SLKCFLAGS="-march=athlon-xp -O3 -pipe -fomit-frame-pointer"
	SLKLDFLAGS=""; LIBDIRSUFFIX=""
    ;;
esac

# Distro version
if [ -f /etc/slackware-version ]; then
    DISTRO_NAME="slack"
    DISTRO_VERSION=$(cat /etc/slackware-version | cut -f2 -d " " | cut -f1,2 -d.)
    case "$ARCH" in
	x86_64)
	    DISTRO_SUFFIX="64"
	    ;;
	arm)
	    DISTRO_SUFFIX="arm"
	    ;;
	*)
	    DISTRO_SUFFIX=""
	    ;;
    esac
else
    DISTRO_NAME="" ; DISTRO_VERSION=""; DISTRO_SUFFIX=""
fi
if [ ! -z "${DISTRO_NAME}" ]; then 
    DISTRO="_${DISTRO_NAME}${DISTRO_SUFFIX}_${DISTRO_VERSION}"
else
    DISTRO=""
fi
DISTRODIR=${DISTRO/_/}

copyleft
echo "Building Slackware package for:  ${PRGNAM}-${VERSION}"
echo "SOURCE : ${SOURCE}"
echo "ARCH   : ${ARCH}"
echo "BUILD  : ${BUILD}"
echo "TAG    : ${TAG}"
echo "DISTRO : ${DISTRO/_/}"
echo "FMT    : ${FMT}"
echo
sleep 1s

set -e # Exit on most errors
trap 'echo "$0 FAILED at line ${LINENO}"' ERR
set -u # Catch uninitialized variables

# Source file availability:
if ! [ -f ${SOURCE} ]; then
    if ! [ "x${SRCURL}" == "x" ]; then
	# Check if the $SRCDIR is writable at all - if not, download to $OUTPUT
	[ -w "$SRCDIR" ] || SOURCE="$OUTPUT/$(basename $SOURCE)"
	echo "Source '$(basename ${SOURCE})' not available yet..."
	echo "Will download file to $(dirname $SOURCE)"
	wget -nv -T 20 -O "${SOURCE}" "${SRCURL}" || true
	if [ $? -ne 0 -o ! -s "${SOURCE}" ]; then
	    echo "Downloading '$(basename ${SOURCE})' failed... aborting the build."
	    rm -f "${SOURCE}" "${SOURCE}".FAIL
	    exit 1
	fi
    else
	echo "File '$(basename ${SOURCE})' not available... aborting the build."
	exit 1
    fi
fi

if [ "${CLEAN:-unset}" == "1" ]; then
    rm -f $CWD/$PRGNAM-*.tgz* $CWD/$PRGNAM-*.txz*
fi

rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $PRGNAM2-$VERSION
tar xvf $CWD/$SOURCE || exit 1
cd $PRGNAM2-$VERSION

# Apply patches if customized in package.build
if [ "$(type -t _01_patch)" = "function" ]; then
    _01_patch
fi

chown -R root:root .
find . \
    \( -perm 777 -o -perm 775 -o -perm 711 -o -perm 555 -o -perm 511 \) \
    -exec chmod 755 {} \; -o \
    \( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
    -exec chmod 644 {} \;

##########################################################################
# Your application will probably need different configure flags;
# these are provided as an example only.
# Be sure to build only shared libraries unless there's some need for
# static.
if [ "${STATIC}" == "1" ]; then
    STATIC="--enable-static=yes"
fi

if [ "$(type -t _02_configure)" != "function" ]; then

# Detect if various --*dir are supported by configure
if [ ! -z "$(./configure --help | grep -e "--libdir")"        ]; then LIBDIR="--libdir=/usr/lib${LIBDIRSUFFIX}"; fi
if [ ! -z "$(./configure --help | grep -e "--docdir")"        ]; then DOCDIR="--docdir=/usr/doc/$PRGNAM-$VERSION"; fi
if [ ! -z "$(./configure --help | grep -e "--infodir")"       ]; then INFODIR="--infodir=/usr/info"; fi
if [ ! -z "$(./configure --help | grep -e "--datadir")"       ]; then DATADIR="--datadir=/usr/share/$PRGNAM"; fi
if [ ! -z "$(./configure --help | grep -e "--sysconfdir")"    ]; then SYSCONFDIR="--sysconfdir=/etc"; fi
if [ ! -z "$(./configure --help | grep -e "--localstatedir")" ]; then LOCALSTATEDIR="--localstatedir=/var"; fi
if [ ! -z "$(./configure --help | grep -e "--mandir")"        ]; then MANDIR="--mandir=/usr/man"; fi

CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
LDFLAGS="$SLKLDFLAGS" \
./configure \
    --prefix=/usr \
    ${LIBDIR:-} \
    ${DOCDIR:-} \
    ${INFODIR:-} \
    ${DATADIR:-} \
    ${SYSCONFDIR:-} \
    ${LOCALSTATEDIR:-} \
    ${MANDIR:-} \
    ${STATIC:-} \
    --build=$ARCH-slackware-linux

else
    # Use different configure command if customized in package.build
    _02_configure
fi

# Run commands after configure but before make
if [ "$(type -t _03_prep)" = "function" ]; then
    _03_prep
fi

# Compile the application and install it into the $PKG directory
if [ "$(type -t _04_make)" != "function" ]; then
make ${NUMJOBS}
make install DESTDIR=$PKG
else
    # Use different make command if customized in package.build
    _04_make
fi

# Finalize the build
if [ "$(type -t _05_final)" = "function" ]; then
    _05_final
fi

# Strip binaries and libraries - this can be done with 'make install-strip'
# in many source trees, and that's usually acceptable if so, but if not,
# use this:
(   cd $PKG
    find . | xargs file | grep "executable" | grep ELF | cut -f 1 -d : | \
	xargs strip --strip-unneeded 2> /dev/null || true
    find . | xargs file | grep "shared object" | grep ELF | cut -f 1 -d : | \
	xargs strip --strip-unneeded 2> /dev/null || true
)

# Compress man pages
# If the man pages are installed to /usr/share/man instead, you'll need to either
# add the --mandir=/usr/man flag to configure or move them manually after the
# make install process is run.
if [ -d $PKG/usr/share/man ]; then
    for i in 1 2 3 4 5 6 7 8 9; do
	mkdir -p $PKG/usr/man/man${i}
	if [ -d $PKG/usr/share/man/man${i} ]; then
	    (   cd $PKG/usr/share/man/man${i}
		find . -type f -exec cp -a {} $PKG/usr/man/man${i} \;
	    )
	fi
    done
    rm -rf $PKG/usr/share/man
fi

if [ -d $PKG/usr/man ]; then
(   cd $PKG/usr/man
    find . -type f -exec gzip -9 {} \;
    for i in $( find . -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
)
fi

# Compress info pages and remove the package's dir file
rm -f $PKG/usr/info/dir
(   cd $PKG
    find . -name "*.info*" \
	-exec gzip -9 {} \;
)

# Remove perllocal.pod and other special files that don't need to be installed,
# as they will overwrite what's already on the system.  If this is not needed,
# remove it from the script.
(   cd $PKG
    # Remove 'special' files
    find . -name perllocal.pod \
	-o -name ".packlist" \
	-o -name "*.bs" \
	| xargs rm -f
)

# Remove empty directories
find $PKG -depth -type d -empty -exec rm -rf {} \;

##########################################################################
# Copy program documentation into the package
# The included documentation varies from one application to another, so be sure
# to adjust your script as needed
# Also, include the SlackBuild script in the documentation directory
if [ -n "$DOCS" ]; then
    mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
    set +e
    cp -a $DOCS \
	$PKG/usr/doc/$PRGNAM-$VERSION
    set -e
fi
if [ -r $PKG/usr/share/$PRGNAM/FAQ ]; then
    (   cd $PKG/usr/doc/$PRGNAM-$VERSION
	ln -sf /usr/share/$PRGNAM/FAQ . )
fi

# Post finalize the build
if [ "$(type -t _06_postfinal)" = "function" ]; then
    _06_postfinal
fi

##########################################################################
# Add build script
mkdir -p $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION
if [ -f $CWD/$PRGNAM.slackbuild ]; then
    cat $CWD/$PRGNAM.slackbuild > $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
else
    if [ -f $CWD/package.slackbuild ]; then
	cat $CWD/package.slackbuild > $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
	if [ -f $(pwd)/package.build-$VERSION ]; then
	    cat $CWD/package.build-$VERSION > $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION/$PRGNAM.build
	else
	    if [ -f $(pwd)/package.build ]; then
		cat $CWD/package.build > $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION/$PRGNAM.build
	    fi
	fi
    else
	echo "Error, unable to include build script"
	exit 2
    fi
fi
chmod 755 $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
if [ -f $CWD/doinst.sh-$VERSION ]; then
    cp -a $CWD/doinst.sh-$VERSION $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION
else
    if [ -f $CWD/doinst.sh ]; then
	cp -a $CWD/doinst.sh $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION
    fi
fi
if [ -f $CWD/doinst.sh-$VERSION.gz ]; then
    zcat -a $CWD/doinst.sh-$VERSION.gz > $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION/doinst.sh
else
    if [ -f $CWD/doinst.sh.gz ]; then
	zcat -a $CWD/doinst.sh.gz > $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION/doinst.sh
    fi
fi
( cd $CWD
    find . -name "*.patch*" \
	-exec cp {} $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION \;
    find . -name "*.diff*" \
	-exec cp {} $PKG/usr/src/slackbuilds/$PRGNAM-$VERSION \;
)

# Copy the slack-desc (and a custom doinst.sh if necessary) into ./install
mkdir -p $PKG/install
if [ -f $CWD/slack-desc ]; then
    cat $CWD/slack-desc > $PKG/install/slack-desc
else
    if [ -f $CWD/slack-desc.$PRGNAM ]; then
	cat $CWD/slack-desc.$PRGNAM > $PKG/install/slack-desc
    fi
fi
if [ -f $CWD/slack-required ]; then
    cat $CWD/slack-required > $PKG/install/slack-required
fi
if [ -f $CWD/doinst.sh-$VERSION ]; then
    cat $CWD/doinst.sh-$VERSION > $PKG/install/doinst.sh
    chmod 755 $PKG/install/doinst.sh
else
    if [ -f $CWD/doinst.sh ]; then
	cat $CWD/doinst.sh > $PKG/install/doinst.sh
	chmod 755 $PKG/install/doinst.sh
    fi
fi
if [ -f $CWD/doinst.sh-$VERSION.gz ]; then
    zcat $CWD/doinst.sh-$VERSION.gz > $PKG/install/doinst.sh
    chmod 755 $PKG/install/doinst.sh
else
    if [ -f $CWD/doinst.sh.gz ]; then
	zcat $CWD/doinst.sh.gz > $PKG/install/doinst.sh
	chmod 755 $PKG/install/doinst.sh
    fi
fi

# Add system startup script
if [ -f $CWD/rc.$PRGNAM-$VERSION ]; then
   mkdir -p $PKG/etc/rc.d
   cat $CWD/rc.$PRGNAM-$VERSION > $PKG/etc/rc.d/rc.${PRGNAM}.new
   # admin will activate this
   chmod 644 $PKG/etc/rc.d/rc.${PRGNAM}.new
else
    if [ -f $CWD/rc.$PRGNAM ]; then
	mkdir -p $PKG/etc/rc.d
	cat $CWD/rc.$PRGNAM > $PKG/etc/rc.d/rc.${PRGNAM}.new
	# admin will activate this
	chmod 644 $PKG/etc/rc.d/rc.${PRGNAM}.new
    fi
fi

##########################################################################
# Make the package; be sure to leave it in $OUTPUT
# If package symlinks need to be created during install *before*
# your custom contents of doinst.sh runs, then add the -p switch to
# the makepkg command below -- see makepkg(8) for details
cd $PKG
mkdir -p $OUTPUT/pkg/$DISTRODIR

/sbin/makepkg -l y -c n $OUTPUT/pkg/$DISTRODIR/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG$DISTRO.$FMT

cd $OUTPUT/pkg/$DISTRODIR
md5sum $PRGNAM-$VERSION-$ARCH-$BUILD$TAG$DISTRO.$FMT > $PRGNAM-$VERSION-$ARCH-$BUILD$TAG$DISTRO.$FMT.md5

cd $CWD

# Clean up the extra stuff:
if [ "${KEEP:-unset}" != "1" ]; then
    rm -rf $TMP/$PRGNAM2-$VERSION
    rm -rf $PKG
fi

# Install new package (upgrade if existing)
if [ "${INSTALL:-unset}" = "1" ]; then
    upgradepkg --install-new $OUTPUT/pkg/$DISTRODIR/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG$DISTRO.$FMT
fi
