#!/bin/bash
# Version: 1.3 GSB Section SlackBuild.
# Copyright (c) 2007 Darren 'Tadgy' Austin <darren (at) gnomeslackbuild.org>
#
# Licenced under the terms of the GNU General Public Licence version 3.
#

# The list of packages in this section, in the order they should be built.
PACKAGES="	xxx
		xxx
		xxx	"

# Section name.
# This should not need to be changed unless the auto detection fails.
SECTION="$( echo $0 | cut -d. -f2 )"

# Usage.
function usage() {
  cat << EOF
Usage: ${0##*/} [options]

Options:
  --help		Show this help screen.

  --list		List the packages which will be built in this section.

  --force		A package will not be built if a package of the same
			name is already installed, or any of the pre-requisite
			packages are not installed.  This option over-rides
			the checks and attempts a build (which will probably
			fail) anyway.

  --no-skip		During the build process, packages that are up to date
			(ie, the package version and build numbers match the
			coresponding SlackBuild) will not be rebuilt.  This
			option forces packages to be rebuilt regardless of the
			version and build numbers.  This does not affect the
			pre-build checks for installed packages (see --force).

  --no-metafiles	Do not create the .txt and .md5 files for each package
			which would usually be produced during a build.

  --no-prune		Normally, when a package is built and copied to the
			destination directory, any previous package(s) of the
			same name are deleted - it is assumed the new package
			is to replace any which were built previously.
			This option prevents previous packages being deleted
			from the destination directory, possibly leaving more
			than one package of the same name (but with different
			version or build numbers) laying around.

  --no-cleanup		By default, any source, temporary build and package
			directories will be deleted once the package is built.
			This option prevents those files from being removed.

  --no-install		Build packages but don't install them.  This should
			only be used for testing individual SlackBuilds as it
			WILL cause serious problems - some package builds may
			rely on another package being auto installed first.

  Options are passed down to the next level SlackBuild where appropriate.
EOF
}

function list_packages() {
  local PACKAGE
  echo "The following packages are built in this section, listed in processing order:"
  ( for PACKAGE in $PACKAGES
    do
      echo -n "$PACKAGE, "
    done ) | sed -e 's/, $//' | fmt -w 74 | sed -e 's/^/    /g'
}

function find_package_files() {
  # $1 = Directory to look for files in [required]
  # $2 = Package name or regex to match.  An empty string matches all.
  # $3 = Package version or regex to match.  An empty string matches all.
  # $4 = Package architecture or regex to match.  An empty string matches all.
  # $5 = Package build tag or regex to match.  An empty string matches all.
  # $6 = File extension or regex to match.  An empty string means no extension.
  # Note: Remember to escape any regex characters used in fixed strings.

  [ -z "$1" ] || [ ! -d "$1" ] && return 1
  ls -1 $1 2>/dev/null | \
    egrep "^(${2:-.*})(-${3:-[^-]*})(-${4:-[^-]*})(-${5:-[^-.]*})($6)$" 2>/dev/null
  return $?
}

function runtime() {
  # $1 = Number of seconds to convert to readable text

  local D=$(( $1 / 86400 ))
  local H=$(( ($1 - ($D * 86400)) / 3600 ))
  local M=$(( ($1 - ($D * 86400) - ($H * 3600)) / 60 ))
  local S=$(( $1 - ($D * 86400) - ($H * 3600) - ($M * 60) ))

  if [ $D -gt 0 ]; then
    echo -n "${D}d, ${H}h ${M}m ${S}s"
  else
    echo -n "${H}h, ${M}m ${S}s"
  fi
  return 0
}

function gen_pkg_txt() {
  # $1 = Package file to process [required].

  [ -z "$1" ] || [ ! -e "$1" ] && return 1
  local METAFILE=${1%.tgz}.txt
  local SIZES="$( gunzip -l $1 | tail -n 1 | tr -s '[:blank:]' )"
  echo "PACKAGE NAME:  $( echo $1 | rev | cut -d/ -f1 | rev )" >$METAFILE
  echo "PACKAGE LOCATION:  $( echo $1 | rev | cut -d/ -f2- | rev )" >>$METAFILE
  echo "PACKAGE SIZE (compressed):  $(( $( echo \"$SIZES\" | cut -d' ' -f2 ) / 1024 )) K" >>$METAFILE
  echo "PACKAGE SIZE (uncompressed):  $(( $( echo \"$SIZES\" | cut -d' ' -f3 ) / 1024 )) K" >>$METAFILE
  echo "PACKAGE REQUIRED:  $( tar zxOf $1 install/slack-required 2>/dev/null | tr '\n' ',' | sed -e 's/,$//' )" >>$METAFILE
  echo "PACKAGE CONFLICTS:  $( tar zxOf $1 install/slack-conflicts 2>/dev/null | tr '\n' ',' | sed -e 's/,$//' )" >>$METAFILE
  echo "PACKAGE SUGGESTS:  $( tar zxOf $1 install/slack-suggests 2>/dev/null | tr '\n' ' ' )" >>$METAFILE
  echo "PACKAGE DESCRIPTION:" >>$METAFILE
  tar xzOf $1 install/slack-desc 2>/dev/null | grep -v "^#" | egrep "[[:alnum:]\+]+\:" >>$METAFILE
  return 0
}

function gen_pkg_md5() {
  # $1 = Package file to process [required].

  [ -z "$1" ] || [ ! -e "$1" ] && return 1
  local METAFILE=${1%.tgz}.md5
  md5sum $1 >$METAFILE
  return 0
}

# Make sure we are in the right directory (you can never trust users..)
cd $( cd ${BASH_SOURCE%/*} ; pwd )

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

# Environment.
export TMP=${TMP:-/tmp}
export PKGDEST=${PKGDEST:-$TMP/gsb-tree/packages}
export LOGSDIR=${LOGSDIR:-$TMP/gsb-buildlogs}

# Option defaults.
NOSKIP=0
NOMETAFILES=0
NOPRUNE=0
NOINSTALL=0

# Sanity check (in case Steve forgets to add packages again :P).
[ $( echo "$PACKAGES" | wc -w ) != \
  $( find . -type d ! -name .svn -maxdepth 1 -mindepth 1 | wc -w ) ] && {
  echo
  echo "*********************************************************************"
  echo "** Error: the number of packages in the PACKAGES list is different
  echo "**        to the number of package directories in this section.
  echo "**        Some packages may not have been added to the PACKAGES list.
  echo "*********************************************************************"
  exit 1
}

# Parse command line arguments.
while [ $# -gt 0 ]; do
  if [ "$1" = "-help" ] || [ "$1" = "--help" ]; then
    usage
    exit 0
  elif [ "$1" = "-list" ] || [ "$1" = "--list" ]; then
    list_packages
    exit 0
  elif [ "$1" = "-force" ] || [ "$1" = "--force" ]; then
    SLACKBUILD_ARGS="${SLACKBUILD_ARGS:+"$SLACKBUILD_ARGS "}--force"
    shift
  elif [ "$1" = "-no-cleanup" ] || [ "$1" = "--no-cleanup" ]; then
    SLACKBUILD_ARGS="${SLACKBUILD_ARGS:+"$SLACKBUILD_ARGS "}--no-cleanup"
    shift
  elif [ "$1" = "-no-skip" ] || [ "$1" = "--no-skip" ]; then
    NOSKIP=1
    shift
  elif [ "$1" = "-no-metafiles" ] || [ "$1" = "--no-metafiles" ]; then
    NOMETAFILES=1
    shift
  elif [ "$1" = "-no-prune" ] || [ "$1" = "--no-prune" ]; then
    NOPRUNE=1
    shift
  elif [ "$1" = "-no-install" ] || [ "$1" = "--no-install" ]; then
    NOINSTALL=1
    shift
  else
    echo "${0##*/}: Unknown option: $1"
    echo "Try: $0 --help"
    exit 1
  fi
done

# Temporary space, package and log file storage.
mkdir -p $TMP
mkdir -p $PKGDEST
mkdir -p $LOGSDIR
mkdir -p $PKGDEST/$SECTION
mkdir -p $LOGSDIR/$SECTION

echo
echo "*********************************************************************"
echo "** Building section '$SECTION'..."
echo "*********************************************************************"

# Process packages.
( for PACKAGE in $PACKAGES
  do
    echo
    echo "*********************************************************************"
    echo "*** Processing package '$PACKAGE'..."
    echo "*********************************************************************"

    # Sanity checks.
    [ ! -e "$PACKAGE/$PACKAGE.SlackBuild" ] && {
      echo
      echo "*********************************************************************"
      echo "*** Error: '$PACKAGE.SlackBuild' not found."
      echo "*********************************************************************"
      exit 1
    }
    [ ! -x "$PACKAGE/$PACKAGE.SlackBuild" ] && {
      echo
      echo "*********************************************************************"
      echo "*** Error: '$PACKAGE.SlackBuild' is not executable."
      echo "*********************************************************************"
      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" ] && {
      echo
      echo "*********************************************************************"
      echo "*** Error: failed to get VERSION or BUILD from '$PACKAGE.SlackBuild'"
      echo "*********************************************************************"
      exit 1
    }

    # Check if the package has been built previously.
    SKIP_BUILD=0
    find_package_files "$PKGDEST/$SECTION" "$PACKAGE" "$PACKAGE_VERSION" '' \
     "$PACKAGE_BUILD" "\.tgz" >/dev/null && {
      if [ "$NOSKIP" = "0" ]; then
        # The package is up to date, no need to rebuild it.
        SKIP_BUILD=1
      else
        echo
        echo "*********************************************************************"
        echo "*** Removing '$PACKAGE' package files from tree..."
        echo "*********************************************************************"
        rm -f $( find_package_files "$PKGDEST/$SECTION" "$PACKAGE" \
          "$PACKAGE_VERSION" '' "$PACKAGE_BUILD" "\.tgz|\.txt|\.md5" | \
          tr '\n' ' ' )
      fi
    }

    # Remove the package if it's installed.
    # Note: this is done even with an "update" build so that the system is
    # refreshed from the package in the tree.
    find_package_files "/var/log/packages" "$PACKAGE" '' '' '' '' >/dev/null && {
      echo
      echo "*********************************************************************"
      echo "*** Removing installed package '$PACKAGE'..."
      echo "*********************************************************************"
      removepkg $PACKAGE
    }

    # Build package if required.
    if [ "$SKIP_BUILD" = "0" ]; then
      echo
      echo "*********************************************************************"
      echo "*** Building package '$PACKAGE'..."
      echo "*********************************************************************"
      ( cd $PACKAGE && export PKGDEST=$PKGDEST/$SECTION &&
        ./$PACKAGE.SlackBuild $SLACKBUILD_ARGS 2>&1 ) | \
        tee $LOGSDIR/$SECTION/$PACKAGE-$( date +%Y%m%d-%H%M%S ).log
      ERR=${PIPESTATUS[0]}
      [ "$ERR" != "0" ] && {
        echo
        echo "*********************************************************************"
        echo "*** Error: '$PACKAGE' build failed."
        echo "*********************************************************************"
        exit $ERR
      }
    else
      echo
      echo "*********************************************************************"
      echo "*** Skipping build of '$PACKAGE' - package up to date."
      echo "*********************************************************************"
    fi

    if [ "$NOPRUNE" = "0" ]; then
      echo
      echo "*********************************************************************"
      echo "*** Pruning old '$PACKAGE' package files from tree..."
      echo "*********************************************************************"
      rm -f $( find_package_files "$PKGDEST/$SECTION" "$PACKAGE" '' '' '' '' | \
        grep -v "$( find_package_files "$PKGDEST/$SECTION" "$PACKAGE" \
        "$PACKAGE_VERSION" '' "$PACKAGE_BUILD" "\.tgz" )" | tr '\n' ' ' )
    else
      echo
      echo "*********************************************************************"
      echo "*** Warning: not pruning any old '$PACKAGE' files."
      echo "*********************************************************************"
    fi

    if [ "$NOMETAFILES" = "0" ]; then
      echo
      echo "*********************************************************************"
      echo "*** Creating metafiles for '$PACKAGE'..."
      echo "*********************************************************************"
      gen_pkg_txt "$( find_package_files "$PKGDEST/$SECTION" "$PACKAGE" \
        "$PACKAGE_VERSION" '' "$PACKAGE_BUILD" "\.tgz" )" &&
      gen_pkg_md5 "$( find_package_files "$PKGDEST/$SECTION" "$PACKAGE" \
        "$PACKAGE_VERSION" '' "$PACKAGE_BUILD" "\.tgz" )" || {
        echo
        echo "*********************************************************************"
        echo "*** Error: failed to create metafiles for '$PACKAGE'."
        echo "*********************************************************************"
        exit 1
      }
    else
      echo
      echo "*********************************************************************"
      echo "*** Warning: not creating metafiles for '$PACKAGE'."
      echo "*********************************************************************"
    fi

    if [ "$NOINSTALL" = "0" ]; then
      echo
      echo "*********************************************************************"
      echo "*** Installing '$PACKAGE'..."
      echo "*********************************************************************"
      upgradepkg --install-new $( find_package_files $PKGDEST/$SECTION \
        "$PACKAGE" "$PACKAGE_VERSION" '' "$PACKAGE_BUILD" "\.tgz" ) || {
        echo
        echo "*********************************************************************"
        echo "*** Error: failed to install '$PACKAGE'."
        echo "*********************************************************************"
        exit 1
      }
    else
      echo
      echo "*********************************************************************"
      echo "*** Warning: not installing '$PACKAGE'."
      echo "*********************************************************************"
    fi
  done
) 2>&1 | tee $LOGSDIR/$SECTION-$(date +%Y%m%d-%H%M%S).log

# Return the exit status from the sub-shell, not the tee command.
exit ${PIPESTATUS[0]}
