#! /bin/sh

# cobuild: Build something from a checked-out wavefront.

# $Id$

###################################################
# Usage information
###################################################

usage () {
  echo "Usage: $0 -m EMAIL_ADDRESS -i SOURCE_DIR -o OUTPUT_DIR -p PROJECT -r [cvs | p4 | svn | none] [ -c CHANGELIST ]"
  echo "  A notification e-mail will be sent to EMAIL_ADDRESS"
  echo "  Source code is in SOURCE_DIR"
  echo "  A symlink tree is made in OUTPUT_DIR/src"
  echo "  Build is done in OUTPUT_DIR/build"
  echo "  Install is done in OUTPUT_DIR/install"
  echo ""
  echo "  PROJECT is the name of the project to be built"
  echo ""
  echo "  Revision control options:"
  echo "    cvs   checkout PROJECT from CVS repository"
  echo "    svn   checkout PROJECT from Subversion repository"
  echo "    p4    checkout PROJECT from Perforce repository"
  echo "    none  use source directory as is, do not attempt to checkout"
  echo ""
  echo "  CHANGELIST indicates Perforce change number to use"
  
  exit 1
}

###################################################
# Set defaults
###################################################

MAILTO=root
CM_REPOSITORY=none

###################################################
# Parse commande line
###################################################

while getopts c:i:o:m:p:r: opt
do
  case $opt in
    c)
      CHANGELIST="$OPTARG"
      ;;
    i)
      SOURCE_DIR=$OPTARG
      ;;
    o)
      OUTPUT_DIR=$OPTARG
      ;;
    m)
      MAILTO=$OPTARG
      ;;
    p)
      PROJECT=$OPTARG  
      ;;
    r)
      CM_REPOSITORY=$OPTARG
      ;;
    *)
      usage
      ;;
   esac
done

if [ "x$OUTPUT_DIR" = "x" ]
then
  usage
fi

if [ "x$SOURCE_DIR" = "x" ]
then
  usage
fi

case "$CM_REPOSITORY" in
  p4|cvs|svn|none)
    ;;
  *)
    usage
    ;;
esac

###################################################
# Setup environment
###################################################

if [ "x$CM_REPOSITORY" = "xp4" ]
then
    P4CONFIG=.p4
    export P4CONFIG
fi

case ":$PATH:" in
  *:/usr/local/bin:*)
    ;;
  *)
    PATH=/usr/local/bin:$PATH
    ;;
esac
TMPDIR=/var/tmp
GNUMAKE=gmake
LANG=C

export MAILTO OUTPUT_DIR SOURCE_DIR TMPDIR GNUMAKE \
  PATH LANG

set -e
umask 022

PIDFILE=$OUTPUT_DIR/build.pid
CHGFILE=$OUTPUT_DIR/build.change
LOGFILE=$OUTPUT_DIR/build.log

###################################################
# Prepare build
###################################################

# Take mutex.

lockfile $PIDFILE.lock
trap 'rm -f $PIDFILE.lock' 0

# Determine change level to be built.

cd $SOURCE_DIR

case "$CM_REPOSITORY" in
  p4)
    if [ "$CHANGELIST" = "" ]; then
      CHANGELIST=`p4 changes -m 1 ... | awk '{print \$2}'`
    fi
    CM_TAG="$CHANGELIST"
    ;;
  svn)
    if [ "$CHANGELIST" = "" ]; then
      CHANGELIST=`svn log --limit 1 | sed -n '2s/^r\([0-9]*\) .*$/\1/p'`
    fi
    CM_TAG="$CHANGELIST"
    ;;
  cvs)
    if [ "$CHANGELIST" = "" ]; then
      CM_TAG="HEAD"
    else
      CM_TAG="ch_$CHANGELIST"
    fi
    ;;
  none)
    CM_TAG="current"
    ;;
esac
export CHANGELIST CM_TAG

# Kill any previous build, unless we know for a fact
# that the build in porgress is building this change
# or a more recent one.

if [ -f $PIDFILE ]
then
  OLDPID=`cat $PIDFILE`
  if [ "x$OLDPID" != x ] && ps -p $OLDPID > /dev/null
  then
    # Build in progress.

    if [ "$CHANGELIST" != "" && -f "$CHGFILE" ]; then
      if [ "`cat $CHGFILE`" -ge "$CHANGELIST" ]
      then
        # Already building this changelist or a more recent one.
        exit 0
      fi
    fi

    # Interrupt current build
    kill $OLDPID > /dev/null 2>&1 || true
  fi
fi

# Here comes the hot builder.

exec > $LOGFILE 2>&1

# Prepare execution.

echo "---------- Starting build of ${PROJECT} at `date`"
echo "---------- Syncing from repository $CM_REPOSITORY at $CM_TAG"

###################################################
# Update files
###################################################

case "$CM_REPOSITORY" in
  p4)
    p4 sync @$CM_TAG
    ;;
  cvs)
    cvs update -d -C -r$CM_TAG
    ;;
  svn)
    svn update -r$CM_TAG
    ;;
  *)
    echo "Using currently directory as is"
    ;;
esac

###################################################
# Launch build process
###################################################

rungroup /bin/sh -c '(
  set -e
  sleep 10

  echo "---------- Preparing source tree"
  
  cd $OUTPUT_DIR
  rm -fr src
  mkdir src
  mkdir build > /dev/null 2>&1 || true
  mkdir install > /dev/null 2>&1 || true

  cd src
  while read file
  do
    dir=`dirname "$file"`
    mkdir -p "$dir"
    if [ -f "$SOURCE_DIR/$file" ]
    then
      ln -s "$SOURCE_DIR/$file" "$file"
    fi
  done < $SOURCE_DIR/MANIFEST
  if [ ! -e testsuite ]
  then
    ln -s "$SOURCE_DIR/testsuite" .
  fi

  support/reconfig -w

  # At this point every file named in MANIFEST must exist

  while read file
  do
    if [ ! -f "$file" ]
    then
      echo "FATAL: MANIFEST file $file not found."
      exit 1
    fi
  done < MANIFEST

  cd ../build

  echo "---------- Building"
  if [ -x $OUTPUT_DIR/src/configure ]
  then
    $OUTPUT_DIR/src/configure --disable-shared --enable-debug \
       --with-proto-perso="giop soap srp" --with-appli-perso="corba moma" \
       --with-corba-services="naming ir event notification time" --with-openssl --prefix=$OUTPUT_DIR/install
  fi && ${GNUMAKE} && ${GNUMAKE} install && cd examples && ${GNUMAKE} && cd ../docs && ${GNUMAKE} && ${GNUMAKE} install
  #  && cd ../testsuite && ${GNUMAKE} 
  # XXX configure is not processing testsuite diectory!
  RC=$?
  exit $RC
)' &

# The build is now running in background. Save PID and changelist #,
# and release mutex.

THISPID=$!
echo $THISPID > $PIDFILE
if [ "$CHANGELIST" != "" ]; then
  echo $CHANGELIST > $CHGFILE
fi

###################################################
# Analyze build output
###################################################

trap '' 0
rm -f $PIDFILE.lock

set +e
wait $THISPID
RC=$?
set -e

if [ $RC = 0 ]
then
  echo "---------- Build completed successfully: `date`"
  STATUS="completed"
  MSG="Build completed successfully.\\nSee details at $OUTPUT_DIR/build.log"
  SUCCESS=true
elif [ $RC -ge 128 ]
then
  echo "---------- Build aborted by a signal: `date`"
  STATUS="aborted"
  MSG="The build process was interrupted by a signal."
  SUCCESS=true
else
  echo "---------- BUILD FAILED: `date`"
  SUCCESS=false
fi

if $SUCCESS
then
  echo -e "$MSG" | Mail -s "${PROJECT} build $CM_REPOSITORY $CM_TAG $STATUS" $MAILTO
else
  cat $OUTPUT_DIR/build.log | Mail -s "${PROJECT} BUILD $CM_REPOSITORY $CM_TAG FAILED" $MAILTO
fi

lockfile $PIDFILE.lock
THATPID=`cat $PIDFILE`
if [ "$THATPID" = "$THISPID" ]
then
  rm -f $PIDFILE
fi
rm -f $PIDFILE.lock
