#!/bin/bash
# Version: 1.9.3 GNOME SlackBuild Build Script
# Copyright (c) 2007, 2008, 2009
#   Darren 'Tadgy' Austin <darren (at) gnomeslackbuild.org>, Coventry, UK.
#   Steve Kennedy <steve (at) gnomeslackbuild.org>
#   Chip Cuccio <chipster (at) gnomeslackbuild.org>, Byron, MN USA
# All rights reserved.
#
# Licenced under the terms of the GNU General Public Licence version 3.
#
# 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.

# GNOME SlackBuild Version
GSB_VERSION=2_32

#========================================================================
# FUNCTIONS
. ${BASH_SOURCE%/*}/functions.sh || {
   echo "Can't find functions.sh."
   exit 1;
}

# Trap keyboard interrupt 
trap error_out SIGINT

#========================================================================
# ENVIRONMENT

# If the user created an options file, read it.
[ -r ./gsb.options ] && {
  . ./gsb.options
  export OPTIONSREAD=1
}

# Basic settings
TMP=${TMP:-/tmp}
ARCH=${ARCH:-"$(arch)"}
GSB_ARCH=${GSB_ARCH:-""}
if [ "$ARCH" = "x86_64" ]; then
  GSB_ARCH=64
fi
GSBDIR=${GSBDIR:-gsb${GSB_ARCH}}
TAG=${TAG:-gsb}
PKGDEST=${PKGDEST:-$TMP/gsb${GSB_ARCH}-tree}
LOGSDIR=${LOGSDIR:-$TMP/gsb${GSB_ARCH}-buildlogs}

# Location of our build source
BUILDSOURCE=${BUILDSOURCE:-"${BASH_SOURCE%/*}/../src"}

# GPG-KEY
GPGKEY=${GPGKEY:-"${BUILDSOURCE}/../GPG-KEY"}
[ ! -f ${GPGKEY} ] && {
  echo ; header "WARNING: Can't find GPG-KEY for verification."
  exit 1;
}

# We will mimic Slackware's tree
SOURCEDIR=${SOURCEDIR:-source}
CHANGELOG=${CHANGELOG:-$LOGSDIR/ChangeLog.txt}
TESTINGDIR=${TESTINGDIR:-testing}
EXTRADIR=${EXTRADIR:-extra}
PASTUREDIR=${PASTUREDIR:-pasture}
PATCHESDIR=${PATCHESDIR:-patches}

# Option defaults.
WITH_TEST_PACKAGES=0
AUTO_DOWNLOAD=0
ONLY_DOWNLOAD=0
CONFIRM_INSTALLS=0
NOPATCHESDIR=0
NOSKIP=0
SKIP_REBUILDS=0
NOPRUNE=0
PUBLISH=0

# Download settings
DOWNLOAD_ATTEMPTS=${DOWNLOAD_ATTEMPTS:-3}
WGET_OPTIONS="-4"

#========================================================================
# COMMAND LINE PARSING 
#
while [ -n "$1" ] ; do
  case $1 in
    -force|--force)
      SLACKBUILD_ARGS="${SLACKBUILD_ARGS:+"$SLACKBUILD_ARGS "}--force"
      shift
    ;;
    -no-cleanup|--no-cleanup)
      SLACKBUILD_ARGS="${SLACKBUILD_ARGS:+"$SLACKBUILD_ARGS "}--no-cleanup"
      shift
    ;;
    -no-patchesdir|--no-patchesdir)
      NOPATCHESDIR=1
      shift
    ;;
    -no-skip|--no-skip)
      NOSKIP=1
      NOPATCHESDIR=1
      shift
    ;;
    -no-prune|--no-prune)
      NOPRUNE=1
      shift
    ;;
    -publish|--publish)
      PUBLISH=1
      SKIP_REBUILDS=1
      shift
    ;;
    -with-testing|--with-testing)
      WITH_TEST_PACKAGES=1
      shift
    ;;
    -confirm-installs|--confirm-installs)
      CONFIRM_INSTALLS=1
      shift
    ;;
    -set=*|--set=*)
      SETS=$(echo $1 | cut -f2 -d=)
      shift
    ;;
    -package=*|--package=*)
      PKG_ONLY=$(echo $1 | cut -f2 -d=)
      shift
    ;;
    -download-only|--download-only)
      ONLY_DOWNLOAD=1
      shift
    ;;
    -download|--download)
      AUTO_DOWNLOAD=1
      shift
    ;;
    -skip-rebuilds|--skip-rebuilds)
      SKIP_REBUILDS=1
      shift
    ;;
    -help|--help)
      usage
      exit 1
    ;;
    *)
      usage ;
      echo ;
      echo "Invalid option: $1"
      exit 1
    ;;
  esac
done

#========================================================================
# STARTUP
echo ; header "* Building GSB "
if [ "$(id -u)" != "0" ]; then
  echo "* Error: Only root can build, install, upgrade, or remove packages."
  exit 1
fi

# Temporary space, package and log file storage.
mkdir -p $TMP &&
mkdir -p $PKGDEST &&
mkdir -p $LOGSDIR &&
mkdir -p $PKGDEST/${EXTRADIR} &&
mkdir -p $PKGDEST/${PASTUREDIR} &&
mkdir -p $PKGDEST/${TESTINGDIR} || exit 
[ "$NOPATCHESDIR" = "0" ] && {
  mkdir -p $PKGDEST/${PATCHESDIR}/packages || exit 1
}

# Clear away all tagfiles from build tree to prevent some applications
# from being skipped when upgradepkg is called.
find $PKGDEST/ -name tagfile -exec rm {} \;

#========================================================================
# MAIN LIST
# 
# The set list is read in from buildlist.txt, with any comments and blank 
# lines removed.
#
cd ${BUILDSOURCE}
BUILDLIST=${BUILDLIST:-""}
[ -f buildlist.txt ] && {
BUILDLIST="$(egrep -v "^#|^$" buildlist.txt | \
  # Remove our testing packages if not specified.
  if [ "$WITH_TEST_PACKAGES" = "1" ]; then cat ; else egrep -v testing; fi | \
  # Perhaps the user only wants a certain set of packages.
  if [ -z "$SETS" ]; then cat ; else egrep ^${SETS}; fi | \
  # Perhaps the user only wants a specific package. 
  if [ -z "$PKG_ONLY" ]; then cat ; else egrep ${PKG_ONLY}$; fi;)"
}

[ -z "$BUILDLIST" ] && {
   echo "Nothing to build."
   exit 1;
}

#========================================================================
# CLEAN SYSTEM OF TESTING/ PACKAGES
#
# Clear the system of any packages from testing/ which might be lying around.
# This ensures that we don't accidently build against a package we don't want.
#
if [ "$WITH_TEST_PACKAGES" = "0" -a "${ONLY_DOWNLOAD}" = "0" ]; then
  echo; header "Removing any test packages."
( cd ${BUILDSOURCE}/../testing &&
  for testpkg in $(find . -type d -mindepth 1 -maxdepth 1); do
    removepkg $testpkg 1>/dev/null 2>/dev/null
  done;
)
fi;

#========================================================================
# MAIN BUILD LOOP
#
# Do the build.

echo; header "* Starting build."; echo;

# LOOP THROUGH ALL PACKAGES IN $BUILDLIST
for listitem in $BUILDLIST ;
do 

(

BUILD_OPTION="$(echo $listitem | cut -f1 -d:)"
SET="$(echo $listitem | cut -f2 -d: | cut -f1 -d/)"
PACKAGE="$(echo $listitem | cut -f2 -d: | cut -f2 -d/)"
SKIP_BUILD=0
DISALLOW_PATCHES=0
SOURCE=$BUILDSOURCE

# Create our tree according to Slackware defaults
case $SET in
   extra)
     SUBDIR=$GSBDIR/../${EXTRADIR}/${PACKAGE}
     SOURCE=$BUILDSOURCE/../
     DISALLOW_PATCHES=1
     ;;
   pasture)
     SUBDIR=$GSBDIR/../${PASTUREDIR}
     SOURCE=$BUILDSOURCE/../
     DISALLOW_PATCHES=1
     ;;
   testing)
     SUBDIR=$GSBDIR/../${TESTINGDIR}/packages
     SOURCE=$BUILDSOURCE/../
     DISALLOW_PATCHES=1
     ;;
   *)
     SUBDIR=$GSBDIR/$SET
     ;;
esac

if [ -d $SOURCE/$SET ]; then
  cd $SOURCE/$SET 
else
  echo "Can't find set directory $SOURCE/$SET."
  exit 1
fi

# Look for package
[ ! -d $PACKAGE ] && { 
  header "Error: Can't find package $PACKAGE." ; 
  exit 1 ;
}

# Make sure we can run our SlackBuild
[ ! -x "$PACKAGE/$PACKAGE.SlackBuild" ] && {
  header "'$PACKAGE.SlackBuild' is not executable." ; 
  exit 1
}

# Get package version and build numbers from the package SlackBuild.
declare PACKAGE_$( egrep -m 1 "^VERSION=.*" $PACKAGE/$PACKAGE.SlackBuild )
declare PACKAGE_$( egrep -m 1 "^BUILD=.*" $PACKAGE/$PACKAGE.SlackBuild )
# Check that we got a version and build.
[ -z "$PACKAGE_VERSION" ] || [ -z "$PACKAGE_BUILD" ] && {
  header "Failed to get VERSION or BUILD from '$PACKAGE.SlackBuild' " ; exit 1
}

# Check if the package should be rebuilt, and where it should be put.
# The assumption is to always rebuild and put packages in the main
# directory, unless modified by the checks below.
if [ "${ONLY_DOWNLOAD}" = "0" ]; then 
  if find_package_files "$PKGDEST/$SUBDIR" "${PACKAGE//+/\+}" \
    "" "" "" "\.txz" >/dev/null && [ "$NOSKIP" = "0" ]
  then
    if find_package_files "$PKGDEST/$SUBDIR" "${PACKAGE//+/\+}" \
      "${PACKAGE_VERSION//-/_}" "" "${PACKAGE_BUILD}${TAG}" "\.txz" >/dev/null 
    then
      # Package with same version/build was found in the main directory.
      SKIP_BUILD=1
    else
      # Not in the main directory, check patches.
      if [ "$NOPATCHESDIR" = "0" -a "$DISALLOW_PATCHES" = "0" ]; then
        [ -d $PKGDEST/$PATCHESDIR/packages ] && {
          if find_package_files "$PKGDEST/$PATCHESDIR/packages" \
            "${PACKAGE//+/\+}" "${PACKAGE_VERSION//-/_}" "" "${PACKAGE_BUILD}${TAG}" \
            "\.txz" >/dev/null
          then
            # Found in patches dir.
            SKIP_BUILD=1
            SUBDIR=$PATCHESDIR/packages
          else
            # No package in patches with the same version/build.
            SUBDIR=$PATCHESDIR/packages
          fi
        }
      fi
    fi
  fi
fi;

#========================================================================
# BUILD PACKAGES
#
# Build package if required.
#
SUCCESSFUL_NEW_BUILD=0
if [ "${ONLY_DOWNLOAD}" = "1" ]; then
  cd $PACKAGE && 
  download_package $PACKAGE || exit $?
elif [ "$SKIP_BUILD" = "0" -o "$BUILD_OPTION" = "rebuild" -a "$SKIP_REBUILDS" = "0" ]; then
  rm -f $( find_package_files "$PKGDEST/$SUBDIR" "${PACKAGE//+/\+}" \
    "${PACKAGE_VERSION//-/_}" "" "${PACKAGE_BUILD}${TAG}" "\.txz|\.txt|\.txz\.asc" \
    | tr '\n' ' ' ) >/dev/null 2>&1
  find_package_files "/var/log/packages" "${PACKAGE//+/\+}" "" "" "" "" \
    >/dev/null && {
    echogreen "* "; echo "Removing old $PACKAGE and cleaning up files."
    removepkg $( basename $( find_package_files "/var/log/packages" \
      "${PACKAGE//+/\+}" "" "" "" "" ) ) || exit 1
    }

  echo ; echogreen "* "; echo "Building package '$PACKAGE'"
  mkdir -p $PKGDEST/$SUBDIR
  mkdir -p $LOGSDIR/$SET

  # Run the SlackBuild
   ( 
     cd $PACKAGE && 
     export PKGDEST=$PKGDEST/$SUBDIR || exit 1
     if [ "$AUTO_DOWNLOAD" = "1" ]; then
       [ "$BUILD_OPTION" = "nofetch" ] || {
        download_package $PACKAGE || exit $?
       }
     fi;
     ./$PACKAGE.SlackBuild $SLACKBUILD_ARGS 2>&1 
   ) | tee $LOGSDIR/$SET/$PACKAGE-$( date +%Y%m%d-%H%M%S ).log
 
   ERR=${PIPESTATUS[0]}
   [ "$ERR" != "0" ] && { 
     exit $ERR 
   }
   SUCCESSFUL_NEW_BUILD=1
else
  echo "* Found: $PACKAGE-${PACKAGE_VERSION//-/_}-${ARCH}-${PACKAGE_BUILD}${TAG}.txz" 
fi

#========================================================================
# PRUNE OLD FILES
#
# Remove any old packages lying around
#
if [ "${NOPRUNE}" = "0" -a "${ONLY_DOWNLOAD}" = "0" ]; then
  PRUNE_FILES="$( find_package_files "$PKGDEST/$SUBDIR" "${PACKAGE//+/\+}" \
    "" "" "" "\.txz|\.txt|\.txz\.asc" | grep -v "$( find_package_files \
    "$PKGDEST/$SUBDIR" "${PACKAGE//+/\+}" "${PACKAGE_VERSION//-/_}" "" \
    "${PACKAGE_BUILD}${TAG}" "\.txz|\.txz\.asc" )" | tr '\n' ' ' )"
  [ ! -z "$PRUNE_FILES" ] && {
      rm -f $PRUNE_FILES
  }
fi;

#========================================================================
# MAKE CHECKSUMS AND DESCRIPTIONS
#
# Make a txt description of the package
if [ "$PUBLISH" = "1" -a "${ONLY_DOWNLOAD}" = "0" ]; then
  make_pkg_txt "$( find_package_files "$PKGDEST/$SUBDIR" "${PACKAGE//+/\+}" \
    "${PACKAGE_VERSION//-/_}" "" "${PACKAGE_BUILD}${TAG}" "\.txz" )" || {
    header "Failed to create txt description for '$PACKAGE'." ; exit 1
  }
  # Sign the package
  SIGN_PACKAGE="$( find_package_files "$PKGDEST/$SUBDIR" "${PACKAGE//+/\+}" \
    "${PACKAGE_VERSION//-/_}" "" "${PACKAGE_BUILD}${TAG}" "\.txz" )"
  if [ -f ${SIGN_PACKAGE}.asc ]; then
    gpg --verify ${SIGN_PACKAGE}.asc ${SIGN_PACKAGE} 1>/dev/null 2>/dev/null || {
      echo ;echo ; header "$SIGN_PACKAGE failed to pass asc verification."
      echo "Has the package been corrupted?" ;
      exit 1
    }
    echo " (ASC Signature passed.) "
  else
    echo ; echogreen "* " ; echo "Please sign for ${PACKAGE}:"
    make_pkg_asc "$SIGN_PACKAGE" || {
      header "Failed to create asc signature for '$PACKAGE'." ; exit 1
    }
  fi;
fi;

#========================================================================
# INSTALL NEW PACKAGE
#
# Install our new package if necessary
#
if [ "${ONLY_DOWNLOAD}" = "0" ]; then
  INSTALLED=$(find_package_files "/var/log/packages" "${PACKAGE//+/\+}" "${PACKAGE_VERSION//-/_}" \
               "" "${PACKAGE_BUILD}${TAG}" "") 
  if [ "$SKIP_BUILD" = "0" -o "${INSTALLED}" = "" ]; then
    # Should we pause for before installing package?
    [ "${CONFIRM_INSTALLS}" = "1" ] && {
       echo ;echo "Press enter to install new package." ; 
       read goop;
    }
    upgradepkg --install-new $( find_package_files "$PKGDEST/$SUBDIR" \
      "${PACKAGE//+/\+}" "${PACKAGE_VERSION//-/_}" "" "${PACKAGE_BUILD}${TAG}" "\.txz" ) || {
      header "Failed to install '$PACKAGE'." ; exit 1
    }
    # Update changelog on success install and build of changed packages.
    if [ "${SUCCESSFUL_NEW_BUILD}" = "1" ]; then
changelog "${SET}/${PACKAGE}-${PACKAGE_VERSION//-/_}-${ARCH}-${PACKAGE_BUILD}${TAG}.txz: Built." ;
    fi;
  fi;
fi;  
# BUILDING PACKAGE
) || {
 echo "Check the build logs in: $LOGSDIR"
 exit 1
}

# Done our PACKAGES loop
done 

# Break out if there has been an error.
[ "$?" != "0" ] && {
  exit 1
}

#========================================================================
# COPY DOCUMENTATION AND TAGFILES
#
if [ "${PUBLISH}" = "1" -a "${ONLY_DOWNLOAD}" = "0" ]; then
(
cd $BUILDSOURCE ;
# Copy tagfiles
for tagfile in $(find . -type f -name tagfile); 
do 
 cp $tagfile $PKGDEST/$GSBDIR/$(echo $tagfile | cut -f2 -d/) || exit 1
done;

# Copy our main documentation
cd $BUILDSOURCE/.. ;
if [ "$ARCH" = "x86_64" ]; then
  cat README.TXT | sed 's,@BINARY_EDITION@,64-bit x86_64 edition,g' > \
    $PKGDEST/README.TXT ;
else
  cat README.TXT | sed 's,@BINARY_EDITION@,32-bit x86 edition,g' > \
    $PKGDEST/README.TXT ;
fi;
for i in COPYING COPYING3 CREDITS INSTALL.TXT UPGRADE.TXT \
 CHANGES_AND_HINTS.TXT GPG-KEY COPYRIGHT.TXT MIRRORS.TXT CURRENT.WARNING \
 SLACKWARE_REPLACED_PACKAGES.TXT FAQ.TXT ANNOUNCE.$GSB_VERSION;
do
 if [ -f $i ]; then
   cp $i $PKGDEST || exit 1;
 fi;
done;

cat << EOF > $PKGDEST/$GSBDIR/README.TXT

This directory contains the primary GNOME SlackBuild packages -- the ones that
actually install files to your hard drive.  You can install these packages with
"pkgtool", or "installpkg".  See the man pages (man installpkg) for details.

Have fun!

EOF

# Copy extra documentation
cp extra/README.TXT $PKGDEST/$EXTRADIR || exit 1
[ "$WITH_TEST_PACKAGES" = "1" ] && {
  cp testing/README.TXT $PKGDEST/$TESTINGDIR || exit 1
}
if [ "$ARCH" = "x86_64" ]; then
  cp ChangeLog.slackware64 $PKGDEST/ChangeLog.txt &&
  cp VERSIONS.slackware64 $PKGDEST/VERSIONS || exit 1
else
  cp ChangeLog.slackware $PKGDEST/ChangeLog.txt &&
  cp VERSIONS.slackware $PKGDEST/VERSIONS || exit 1
fi
echo;
header "* Published documentation."
echo;
)
fi;

#========================================================================
# CREATE MD5 CHECKSUMS, FILELIST AND MANIFEST
#
if [ "${PUBLISH}" = "1" ]; then
  echo ; header "* Generating package file lists and checksums."
  ( 
  cd $PKGDEST || exit 1
    PUBLISH_DIRS="$GSBDIR $PATCHESDIR $EXTRADIR $SOURCEDIR $PASTUREDIR"
    if [ "${WITH_TEST_PACKAGES}" = "1" ]; then
       PUBLISH_DIRS="${PUBLISH_DIRS} $TESTINGDIR"
    fi;
    for DIR in ${PUBLISH_DIRS}
    do
      if [ -d "${DIR}" ]; then
        # Skip making packages for our source/
        if [ "${DIR}" != "source" ]; then
           make_packages_txt ${DIR} ${DIR} || exit 1
        fi;
        make_manifest ${DIR} ${DIR} || exit 1
        make_filelist_txt "${DIR}" "${DIR}" "FILE_LIST" || exit 1
        make_checksums_md5 ${DIR} ${DIR} || exit 1
      fi;
    done
    ( cd $PKGDEST ; mv $GSBDIR/PACKAGES.TXT . )
    ( cd $GSBDIR ; ln -sf ../PACKAGES.TXT )
    # Make a date stamped file list of our full set of files.
    make_filelist_txt "." "" "" "1" || exit 1
    make_checksums_md5 .
  )
fi;

echo "* Finished building GSB!"
echo "* The complete GSB binary tree can be found in: $PKGDEST"
echo "* Build logs can be found in: $LOGSDIR"
echo ;
