#!/usr/bin/perl -w

#
# TODO:
#    Mangle master milestone into path, to avoid checkout pain.
#	( Restrict to N milestones on disk. )
#

use IO::Handle;
use Cwd;
use List::Util qw(shuffle);

# -- Things to tweak --
# Path to CWS tools modules
use lib ('/opt/OpenOffice/src680-m92/solenv/bin/modules');

$CONFIGURE_OPTIONS =
    '--enable-gnome-vfs --with-ant-home=/usr/share/ant '.
    '--with-jdk-home=/usr/lib/SunJava2-1.4.2 --without-myspell-dicts' .
    '--enable-libsn --enable-build-mozilla';

$COMMON_CONFIGURE_OPTIONS=
    '--disable-binfilter --disable-crashdump ' .
    '--enable-crashdump=no --enable-cups --enable-fontconfig ' .
    '--enable-openldap --with-lang="en_US" --without-fonts --without-gpc ' .
    '--with-system-freetype --with-system-gcc --with-system-jpeg ' .
    '--with-system-python --with-system-zlib';

$CONFIGURE_OPTIONS = "$COMMON_CONFIGURE_OPTIONS $CONFIGURE_OPTIONS";

$BUILD_DIR = '/tmp/tinder';
$BUILD_NCPUS = 1;
@BUILD_TAGS = ();
$BUILDNAME = 'NLD9/gcc33(x86)'; # best if it includes the OS etc.
$MAINTAINER = 'Michael Meeks <michael.meeks@novell.com>';
$BUILD_OS = 'NLD 9';
$DEFAULT_MASTER = 'SRC680';
$DEFAULT_CVSROOT = ':pserver:anoncvs@anoncvs.services.openoffice.org:/cvs';

# All for broken mozilla foo
$BUILD_SRC = '/share/src';
$MOZILLA_SRC = 'mozilla-source-1.7.5.tar.gz';
$MOZILLA_URL = 'http://ftp.mozilla.org/pub/mozilla.org/mozilla/releases/mozilla1.7.5/source/';

use Cws;
use Eis;

# -- debug tweaks --
my $debug = 1;
my $shortcircuit_checkout = 0;
my $shortcircuit_clean = 0;
my $shortcircuit_build = 0;

# -- Things not to tweak --
$TINDER_DEST = 'tinder@go-oo.org';
$SENDMAIL = '/usr/sbin/sendmail';
$LOGDIR = $ENV{'HOME'} . "/build-logs";
`mkdir -p $LOGDIR`;

-X $SENDMAIL || die "No sendmail";

sub log_msg($@)
{
    my $log = shift;
    my $logf;

    print STDERR @_ if ($debug);

    open($logf, ">>$log") || die "Can't open log: $!";
    print $logf @_;
    close($logf);
}

# 'not_running', 'building', 'build_failed', 'test_failed', 'success'
sub start_mail($$$)
{
	my $status = shift;
	my $tree   = shift;
	my $starttime = shift;
	my $MAIL;
	my $MAIL_HEADER =
		"X-Tinder: cookie\n".
		"\n". # vital header / body separator
		"tinderbox: administrator: michael\@ximian.com\n".
		"tinderbox: builddate: deprecated\n".
		"tinderbox: starttime: $starttime\n".
		"tinderbox: buildname: $BUILDNAME\n".
		"tinderbox: errorparser: unix\n".
		"tinderbox: status: $status\n".
		"tinderbox: timenow: ". time(). "\n".
		"tinderbox: tree: $tree\n".
		"tinderbox: END\n".
		"\n"; # end of tinder header separator

	print "Mailing '$status'\n";

#	open ($MAIL, "|cat > $TINDER_DEST") || die "Can't log to file";
	if( $debug ) {
	    $MAIL = STDERR;
	} else {
	    open ($MAIL, "|$SENDMAIL $TINDER_DEST") || die "Can't send mail";
	}
	print $MAIL $MAIL_HEADER;

	return $MAIL;
}

sub end_mail($)
{
    my $MAIL = shift;
    close ($MAIL) if (!$debug);
}

sub send_log($$$$)
{
    my $status = shift;
    my $tree   = shift;
    my $starttime = shift;
    my $buildlog = shift;

    $MAIL = start_mail ($status, $tree, $starttime);
    local $SIG{PIPE} = 'IGNORE';
    print $MAIL "Tinder build from $MAINTAINER, on $BUILD_OS\n"; 

    my $LOG;
    open ($LOG, "$buildlog") || warn "Can't open $buildlog: $!";
    while (<$LOG>) {
	print $MAIL $_;
    }
    close ($LOG);

    end_mail ($MAIL);
}

sub cvs_op($$$)
{
    my $op = shift;
    my $subdir = shift;
    my $log = shift;

    my $count = 0;
    while (1) {
	$count++;
	if (system ("cd $BUILD_DIR/$subdir ; cvs -z3 $op 2>&1 | tee -a $log")) {
	    if ($count < 5) {
		log_msg ($log, "WARNING: $op failed, retrying $count\n");
	    } else {
		log_msg ($log, "ERROR: $op failed, retry limit reached\n");
		return 0;
	    }
	} else {
	    log_msg ($log, "cvs $op succeeded\n");
	    return 1;
	}
    }
}

sub checkout_source($$)
{
    my $childws = shift;
    my $log = shift;
    my $master = $DEFAULT_MASTER;

    log_msg ($log, "Checking out $childws ... \n");

    my $eis = Cws::eis();
    $id = $eis->getChildWorkspaceId
	( Eis::to_string($master),
	  Eis::to_string($childws) );
    if (!$id) {
	log_msg ($log, "Invalid cws / no EIS Id\n");
	return 0;
    }

    my @modules = @{$eis->getModules($id)};
    my $milestone = $eis->getMilestone($id);

    log_msg ($log, "Modules:");
    foreach (@modules) {
	log_msg ($log, "\t$_\n");
    }

    my $creation_master = $eis->getCreationMasterWorkspace($id);
    my $cws_branch_tag = 'cws_' . lc($creation_master) . '_' . lc($childws);
    my $master_milestone_tag = uc($master) . "_" . $milestone;

    cvs_op ("checkout -r $master_milestone_tag OpenOffice", '', $log);

    for $module (@modules) {
	if (! -d "$BUILD_DIR/$module") {
	    log_msg ($log, "ERROR: missing module $module: no directory\n");
	    next;
	}
	cvs_op ("update -r $cws_branch_tag", $module, $log);
    }

    return 1;
}

sub clean_source($$)
{
    my $childws = shift;
    my $log = shift;

    log_msg ($log, "Cleaning tree ...\n");

    if (`cd $BUILD_DIR; rm -Rf */unx*.pro 2>&1 | tee $log`) {
	log_msg ($log, "ERROR: problem cleaning source");
	return 0;
    }

    log_msg ($log, "Linking moz source ...\n");
    my $dest = "$BUILD_DIR/moz/download/$MOZILLA_SRC";
    unlink ($dest);
    symlink ("$BUILD_SRC/$MOZILLA_SRC", $dest) || log_msg ($log, "Failed to link moz source: $!");

    log_msg ($log, "Successfully cleaned");
    return 1;
}

sub build_source($$)
{
    my $childws = shift;
    my $log = shift;

    log_msg ($log, "FIXME: no build logic yet");

    # FIXME - safe / random name
    my $script = '/tmp/build-ooo-bash';
    my $sof;
    
    open ($sof, ">$script") || die "can't open $script: $!";
    # force autoconf regen
    print $sof <<"EOF"
#!/bin/bash

#  main configure
cd $BUILD_DIR/config_office
rm -f config.cache
echo "configuring ...";
autoconf || exit 1;

echo "Env for configure:"
set
echo "Env for configure ends"

./configure $CONFIGURE_OPTIONS --with-build-version="Tinder built $childws" || exit 1;

# Many Java files have 8bit char-set comments, javac barfs on them in utf8 locales
export LANG="C";

# Many Java's can't cope with the NPTL on Linux.
LD_ASSUME_KERNEL=2.2.5 /bin/true 2> /dev/null || LD_ASSUME_KERNEL=2.4.10 /bin/true 2> /dev/null || LD_ASSUME_KERNEL=2.6.0 2> /dev/null || unset LD_ASSUME_KERNEL
export LD_ASSUME_KERNEL

# Embedded python dies without Home set
if test "z\$HOME" = "z"; then
    export HOME="";
fi

cd $BUILD_DIR
. $BUILD_DIR/*.Set.sh

echo 'Verifying environment'
echo "Path:  \'\$PATH\'"
echo "Shell: \'\$SHELL\'"
echo "Lang:  \'\$OOO_LANGS\'"
echo "Gcc: "
gcc -dumpversion
bison --version
flex --version
echo 'Bootstrapping'
./bootstrap || ./bootstrap || ./bootstrap || exit 1;

# parallel build setting
EXTRA_BUILD_FLAGS=
if test "$BUILD_NCPUS" -gt 1; then
    EXTRA_BUILD_FLAGS="-P$BUILD_NCPUS"
fi
# not for Win32 ...
EXTRA_BUILD_FLAGS="--dlv_switch link \$EXTRA_BUILD_FLAGS"

EXTRA_DMAKE_FLAGS=

# tcsh sucks great rocks, and refuses to re-direct it's output otherwise
export TERM=

# Automake exports MAKEFLAGS= --unix or something
# similar that gives child nmake's pain.
unset MAKEFLAGS

# Accelerate straight-through compiles by not building / using dependencies
export nodep=1
echo "Env:"
set

echo 'Commencing main build'
cd $BUILD_DIR/instsetoo_native || exit 1;
perl \$SOLARENV/bin/build.pl --all \$EXTRA_BUILD_FLAGS \$EXTRA_DMAKE_FLAGS || exit 1;
EOF
    ;
    close ($sof);
    chmod 0755, $script;

    return !`$script 2>&1 | tee $log`;
}

sub build_one {
    my $tree = shift;
    my $starttime = time();
    my $buildlog = "$LOGDIR/log-$tree-$starttime";
    my $ret;
    my $MAIL;

    print "Building $tree: ".$starttime." log $buildlog\n";

    $MAIL = start_mail ('building', $tree, $starttime);
    end_mail ($MAIL);

    if (($shortcircuit_checkout || checkout_source ($tree, $buildlog)) &&
	($shortcircuit_clean || clean_source ($tree, $buildlog)) &&
	($shortcircuit_build || build_source ($tree, $buildlog)) ) {
	$status = 'success';
    } else {
	$status = 'build_failed';
    }

    sleep 1; # time to flush that log.
    
    send_log ($status, $tree, $starttime, $buildlog);
}

# State can be 'integrated', 'ready for QA', 'planned', 'new' (etc.?)
sub get_cws_with_state($)
{
    my $cws_list;
    my $state = shift;

    my $eis = Cws::eis();
    
    $cws_list = $eis->getCWSWithState( Eis::to_string( $DEFAULT_MASTER ),
				       Eis::to_string( $state ) );

    my @list = @{$cws_list};
#    print STDERR "CWS list [$DEFAULT_MASTER] : @list\n";

    return @list;
}

if (! -f "$BUILD_SRC/$MOZILLA_SRC") {
    system( "cd $BUILD_SRC ; wget $MOZILLA_URL/$MOZILLA_SRC" ) && die "Failed to download $MOZILLA_SRC";
}

#
# FIXME - Fix all this ...
#
my $eis = Eis->new( uri => Cws::eis_uri(), 
		    proxy_list => Cws::eis_proxy_list(), 
		    net_proxy => Cws::net_proxy()
		    );

if (@ARGV) {
	@BUILD_TAGS = @ARGV;
} else {
    print ("Fetching suitable CWS' to build\n");
    @BUILD_TAGS = shuffle( get_cws_with_state( 'ready for QA' ) );
    print "Tags to build '@BUILD_TAGS'\n";
}

`mkdir -p $BUILD_DIR`;
chdir ($BUILD_DIR) || die "Can't enter $BUILD_DIR: $!";
$ENV{CVSROOT} = $DEFAULT_CVSROOT;

for my $tag (@BUILD_TAGS) {
    build_one ($tag);
}
