#!/bin/ksh
########################################################################
# buildall - automated multi-platform build tool
#
# 10/09/97 - marcel - created
# 10/13/97 - marcel - support shared build tree
#  2/11/98 - marcel - updated for 4.0 Beta builds (need -update)
#  2/26/98 - marcel - added -r, -t and host specifiers
#  7/01/99 - robodan - added VAR=value ability
#  8/01/99 - robodan - explicitly know about building on localhost
#  10/15/99 - robodan - remove older OSes from build list
#  2000/4/7 - robodan - Created mstone version
########################################################################
#
# This script is intended to do a set of UNIX builds for a
# given CVS module.  It is designed to use 'rsh' between a
# set of trusting hosts and use shared NFS storage with common
# mount points (e.g. /u/username/...)
#
# To check if you have rights to rsh to a particular host, try:
#   rsh hostname "echo $PATH"
# You may have to edit your .rhosts or /etc/hosts.equiv
#
# A target directory will be created based on the current date.
#
# A set of global build logs plus a log per platform are kept
# in a log directory under the target
#
# It will checkout a copy of the source, duplicate it for
# each platform and perform a set of remote builds in parallel.
# The script will exit when all the work has been completed.
#
# Example usage:
#  cd ~/src; buildall msg
# Result:
#  ~/src/19980210_40.1/
#  ~/src/19980210_40.1/logs/...
#  ~/src/19980210_40.1/src/...
#  ...
#

# Buildhosts
DEFAULT_BUILDHOSTS="kimo nugget vsync shave purgatory trex0"

usage() {
  echo ""
  echo "usage: buildall [ make assigns... ] < -t | target > [ -r ] [ buildhosts... ]"
  echo "   [ -t | --test]:	just test rsh and report OS versions."
  echo "  [-r | --respin]:	rebuild in place using existing source."
  echo "  [-p | --postbuild]:	Execute post build command too."
  echo "  [make assigns]:	e.g. VARIANT=release"
  echo "         <target>:	one of: mstone42"
  echo "  [buildhosts...]:	default [$DEFAULT_BUILDHOSTS]"
  echo ""
  exit 1
}

########################################################################
# Set these defaults and options for your desired build
########################################################################

# Target base destination directory
DESTBASE=`pwd`

# Can we do multiple ARCH builds in same source tree
SHARESRC=yes

DESCRIPTION=""
BUILDHOSTS=""
RESPIN="no"
POSTBUILD="no"
JUST_TEST="no"
DESTTYPE=""
CO_CMD="cvs -d $CVSROOT -q checkout"
CHECKOUT=""
CHECKOUT2=""
#MOZCVSROOT=':pserver:anonymous@cvs.mozilla.org:/cvsroot'
MOZCVSROOT=':pserver:robodan%netscape.com@cvs.mozilla.org:/cvsroot'

MAKE="gmake"
MK_ARG=""

ARGS="$@"

for ARG in "$@"; do

# If this is a make assignment (FOO=whatever), add it to make command
# Arguments with quotes in them don't go all the way through.
# Make args trick: 'FOO=nop -j 2'
# The pre-post arg stuff uses hostnames as a switch, ugly calling syntax.
if [[ -n "`echo z$ARG | egrep '^z[A-Z0-9_]+=[^ 	]'`" ]] ; then
  if [[ -n "$DESCRIPTION" ]] ; then
	echo "Arg after target is ignored! ($ARG)"
	continue
  fi
  if [[ -z "$BUILDHOSTS" ]] ; then	# pre  args
    MAKE="$MAKE $ARG"
  else					# post args
    MK_ARG="$MK_ARG $ARG"
  fi
  continue
fi

# should we just rebuild todays latest source...
if [[ "$ARG" = "-r" || "$ARG" = "--respin" || "$ARG" = "respin" ]]; then
  RESPIN="yes"
  continue
fi

# should we just run post build command...
if [[ "$ARG" = "-p" || "$ARG" = "--postbuild" || "$ARG" = "postbuild" ]]; then
  POSTBUILD="yes"
  continue
fi

# should we just test remote connectivity and execute permissions...
if [[ "$ARG" = "-t" || "$ARG" = "--test" ]]; then
  JUST_TEST="yes"
  RESPIN="yes"
  continue
fi

# We will pull source using: "$CHECKOUT"
# And build on each machine: "cd $BUILDDIR && $BUILDCMD"


# expand targets (but don't confuse hosts for targets (msg7))

# These will build just mstone
# expand targets (but don't confuse hosts for targets (msg7))
if [[ "$BUILDCMD" = "" && "$ARG" = mailstone* ]]; then
  case ${ARG#mstone} in
	"")
	"42")
		DESTTYPE=_MSTONE42
		MS_BRANCH=""
		#BUILDCMD="$MAKE $MK_ARG debug release"
		#POSTCMD="$MAKE $MK_ARG all_DBG.OBJ all_OPT.OBJ"
		BUILDCMD="$MAKE $MK_ARG rpackage"
		POSTCMD="$MAKE $MK_ARG all_OPT"
		;;
	*)
		echo "Unknown mstone version in $ARG"
		echo "Try mstone42"
		exit 1;;
  esac

  DESCRIPTION="Mstone $MS_BRANCH"
  BUILDDIR=./mozilla/mstone
  CVSROOT=$MOZCVSROOT
  CHECKOUT="$CO_CMD $MS_BRANCH mozilla/mstone"
  # BUG No way to unpack perl, gd, and gnuplot before building
  continue
fi

#########################
# Other...
#########################

# These will print some tools info
if [[ "$ARG" = "tools" ]]; then
  CHECKOUT="$CO_CMD modules"
  BUILDDIR=.
  BUILDCMD="which gcc && ls -l /tools/ns/bin/gcc && which gcc-2.7.2.1 && ls -l /tools/ns/bin/gcc-2.7.2.1"
  continue
fi

#########################
# Everything else is assumed to be a hostname
#########################

BUILDHOSTS="$ARG $BUILDHOSTS"

done # for ARG in $*; do

if [[ "$BUILDHOSTS" = "" ]]; then
  BUILDHOSTS=$DEFAULT_BUILDHOSTS
fi

if [[ "$BUILDCMD" = "" && "$JUST_TEST" = "no" ]]; then
  usage
fi

########################################################################
# You shouldn't have to modify stuff below here too much
########################################################################

# Who and Where are we
PROG=buildall
RSH=rsh
SYS=`uname -s`
echo SYS=$SYS
if [[ "$SYS" = "HP-UX" ]]; then
  RSH=remsh
fi

########################################################################
# Simple log output function
########################################################################

log() {
#  echo "[`date +\"%Y/%m/%d %H:%M:%S\"`] $PROG: $*"
  echo "`date +\"%H:%M:%S\"` $PROG: $*"
}

########################################################################
# Error
########################################################################

quit() {
  log "$* (exiting)..."
  exit 1
}

# Where should the work be done
REV=1
WORKDIR=$DESTBASE/`date +"%Y%m%d"`$DESTTYPE.$REV
LASTWORKDIR=$WORKDIR
LASTREV=$REV

while [[ -d $WORKDIR ]]; do
  LASTREV=$REV
  let "REV= REV + 1"
  LASTWORKDIR=$WORKDIR
  WORKDIR=$DESTBASE/`date +"%Y%m%d"`$DESTTYPE.$REV
done

if [[ "$RESPIN" = "yes" ]]; then
  WORKDIR=$LASTWORKDIR
  REV=$LASTREV
fi
BUILDREV=$REV

if [[ ! -d $WORKDIR && "$RESPIN" = "yes" ]]; then
  quit "missing expected respin workdir ($WORKDIR)"
fi

mkdir -p $WORKDIR

# Where to send logs
LOGDIR=$WORKDIR/logs
[[ -d $LOGDIR ]] || mkdir $LOGDIR

# What tool to use for compressed tar
if [[ -x /tools/ns/bin/tar ]] ; then	# ROBDAN 9-15-98 for Linux
  TAR=/tools/ns/bin/tar
else
  TAR=tar
fi

SRCDIR=$WORKDIR/src
SRCTAR=$WORKDIR/src.tar.gz

########################################################################
# The function which extracts the source and prepares for copies
########################################################################

prepare_source() {
  log "Preparing source code..."
  mkdir $SRCDIR
  (cd $SRCDIR;
   log "Extracting source in $SRCDIR...";
   log "$CHECKOUT > $LOGDIR/cvs-co.txt";
   $CHECKOUT > $LOGDIR/cvs-co.txt;
   RET=$?
   if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $CHECKOUT"; fi
   if [[ "$CHECKOUT2" != "" ]]; then
      log "$CHECKOUT2 >> $LOGDIR/cvs-co.txt";
      $CHECKOUT2 >> $LOGDIR/cvs-co.txt;
      RET=$?
      if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $CHECKOUT2"; fi
   fi
   log "Listing source...";
   ls -Rl > $LOGDIR/src-ls-Rl.txt
   log "Archiving source..."
   $TAR czf $SRCTAR .
  )
  RET=$?
  if [[ $RET -ne 0 ]]; then
    quit "### Failed($RET): cannot prepare source";
  else
    log "Source extraction complete";
  fi
}

########################################################################
# The function which does a build
########################################################################

do_rbuild() {
  OSDEST=$1

  if [ "$SHARESRC" = "yes" ]; then
    RSRCDIR=$SRCDIR
  else
    RSRCDIR=$WORKDIR/$OSDEST
  fi

  [[ -d $RSRCDIR ]] || mkdir -p $RSRCDIR

  cd $RSRCDIR;

  # do any late variable expansions
  RAWCMD=$BUILDCMD
  BUILDCMD=$(eval echo $RAWCMD)
  
  if [[ $RHOST = localhost ]] ; then
    log "Build locally for $OSDEST ($BUILDCMD)...";
    cd $BUILDDIR && pwd && $BUILDCMD && echo $PROG: Success
    RET=$?
    if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $OSDEST build"; fi

    log "Completed local build..."
    return
  fi

  if [[ "$SHARESRC" != "yes" ]]; then
     log "Extracting source for $OSDEST...";
     $RSH $RHOST -n "cd $RSRCDIR && pwd && $TAR xzf $SRCTAR";
     RET=$?
     if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $OSDEST source extraction"; fi
  else
     log "Using common source in $RSRCDIR";
  fi
  
  log "Building for $OSDEST ($BUILDCMD)...";
  $RSH $RHOST -n "cd $RSRCDIR/$BUILDDIR && pwd && $BUILDCMD && echo $PROG: Success"
  RET=$?
  if [[ $RET -ne 0 ]]; then quit "### Failed($RET): $OSDEST build"; fi

  log "Completed $OSDEST...";
}

buildhost() {
  RHOST=$1

  log "Query $RHOST configuration...";

  if [[ $RHOST = localhost ]] ; then
     uname -s > /tmp/$$.$RHOST 2>&1
  else
    $RSH $RHOST -n "uname -s" > /tmp/$$.$RHOST 2>&1
    RET=$?
    if [[ $RET -ne 0 ]]; then
      quit "..[$RHOST] ### Failed($RET): $RSH $RHOST -n \"uname -s\"";
    fi
  fi
  ROSTYPE=`tail -1 /tmp/$$.$RHOST`

  if [[ "$ROSTYPE" = "AIX" ]]; then
    $RSH $RHOST -n "uname -v" > /tmp/$$.$RHOST 2>&1
    ROSTYPE=${ROSTYPE}`tail -1 /tmp/$$.$RHOST`
  fi

  if [[ $RHOST = localhost ]] ; then
     uname -r > /tmp/$$.$RHOST 2>&1
  else
    $RSH $RHOST -n "uname -r" > /tmp/$$.$RHOST 2>&1
  fi
  ROSREV=`tail -1 /tmp/$$.$RHOST`
  rm /tmp/$$.$RHOST

  if [[ $RHOST = localhost ]] ; then
    OSDEST=`hostname | cut -f1 -d.`-${ROSTYPE}${ROSREV}
  else
    OSDEST=${RHOST}-${ROSTYPE}${ROSREV}
  fi
  log "..Building on [$OSDEST]..."

  REV=1				# find unique logfile name
  OSLOG=$LOGDIR/$OSDEST.$REV
  while [[ -f $OSLOG ]]; do
    let "REV = REV + 1"
    OSLOG=$LOGDIR/$OSDEST.$REV
  done

  if [[ "$JUST_TEST" = "yes" ]]; then
    echo "$PROG: Success" > $OSLOG
  else
    ( do_rbuild $OSDEST ) > $OSLOG 2>&1
  fi

  grep "$PROG: Success" $OSLOG > /dev/null
  RET=$?
  if [[ $RET -eq 0 ]]; then
    RESULT="SUCCESS";
  else
    RESULT="FAILURE($RET)";
  fi
  log "..Completed [$OSDEST] <$RESULT>.";
}

########################################################################
# The function which initiates all the builds
########################################################################

do_builds() {
  log "Launching builds..."

  for HOST in $BUILDHOSTS; do
    buildhost $HOST &
  done
}

########################################################################
# main
########################################################################

main() {
  if [[ "$JUST_TEST" = "yes" ]]; then
    log "Automated test starting..."
  else
    log "Automated build of [$DESCRIPTION] starting..."
  fi
  log ""
  log "       ARGS = $ARGS"
  log " BUILDHOSTS = $BUILDHOSTS"
  log "    WORKDIR = $WORKDIR"
  log "     SRCDIR = $SRCDIR"
  log "     LOGDIR = $LOGDIR"
  log "   CHECKOUT = $CHECKOUT"
  log "   BUILDDIR = $BUILDDIR"
  log "   BUILDCMD = $BUILDCMD"
  log "     RESPIN = $RESPIN"
  log ""

  [[ "$RESPIN" = "no" ]] && prepare_source
  do_builds
  log "Waiting for all builds to complete..."
  wait
  log "All builds completed."

  if [[ -n "$POSTCMD" && "$POSTBUILD" = "yes" ]] ; then
	log "Running post build command."

	REV=1				# find unique logfile name
	POSTLOG=$LOGDIR/postbuild.$REV
  	while [[ -f $POSTLOG ]]; do
 	  let "REV = REV + 1"
 	  POSTLOG=$LOGDIR/postbuild.$REV
	done

	echo "Dir $SRCDIR/$BUILDDIR" > $POSTLOG
	echo "Cmd $POSTCMD" >> $POSTLOG
	(cd $SRCDIR/$BUILDDIR && $POSTCMD && echo $PROG: Success) >> $POSTLOG 2>&1

        log "Post build command completed."
  elif [[ -n "$POSTCMD" ]] ; then
	echo "Skipping post build command: $POSTCMD"
  fi
}

REV=1
PROGLOG=$LOGDIR/$PROG.$REV

while [[ -f $PROGLOG ]]; do
  REV=`expr $REV + 1`
  PROGLOG=$LOGDIR/$PROG.$REV
done

main | tee $PROGLOG 2>&1
exit 0
