#!/usr/bin/env perl

use strict;
use Cwd;
use DirHandle;
use FileHandle;


my $top_dir = cwd();
my $src_dir = "$top_dir/pegasus";

# autoflush our STDOUT
$| = 1;

#if ($ENV{_NMI_STEP_FAILED}) {
#    die "Previous step failed, exiting\n";
#}

my $taskname = $ENV{_NMI_TASKNAME};
if( ! $taskname ) {
    # if we have no task, just return success immediately
    print "No tasks specified, returning SUCCESS\n";
    exit 0;
}
    
env_setup();

if    ($taskname eq "build-binary")    { build_binary();  }
elsif ($taskname eq "build-worker")    { build_worker();  }
elsif ($taskname eq "build-wms")       { build_wms();     }
elsif ($taskname eq "clean-sources")   { clean_sources(); }
elsif ($taskname eq "build-deb")       { build_deb();     }
elsif ($taskname eq "build-rpm")       { build_rpm();     }
elsif ($taskname eq "test-binary")     { test_binary();   }
elsif ($taskname eq "test-worker")     { test_worker();   }
elsif ($taskname eq "test-wms")        { test_wms();      }
else {
    print "Unknown task: $taskname";
    exit(1);
}
exit(0);


########################################################################

sub env_setup
{
    announce("env and tooling");

    my $JAVA_HOME="";
    my $ANT_HOME="";
    my $VACPP_HOME="";
    my $VAC_HOME="";

    # java home on macosx
    if ( -e "/System/Library/Frameworks/JavaVM.framework" ) {
        # we require java 1.6
        if ( ! -e "/System/Library/Frameworks/JavaVM.framework/Versions/1.6" ) {
            logmsg("No java 1.6 found! Available versions:");
            cmd("ls -l /System/Library/Frameworks/JavaVM.framework/Versions/", 1, 0);
            die("No java 1.6 found!");
        }
        $JAVA_HOME = "/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home";
        $ENV{JAVA_HOME} = $JAVA_HOME;
    }
 
    # nmi prereqs
    for my $key ( keys %ENV){
        if ($key=~ m/_NMI_PREREQ_wget/) {
            $ENV{'PATH'} = $ENV{$key} . "/bin:" . $ENV{'PATH'};
        }
        if ($key=~ m/_NMI_PREREQ_([A-Za-z0-9]+_)*java/) {
            $JAVA_HOME=$ENV{$key};
            $ENV{JAVA_HOME}=$JAVA_HOME;
        }
        if ($key=~ m/_NMI_PREREQ_apache_ant/) {
            $ANT_HOME=$ENV{$key};
            $ENV{ANT_HOME}=$ANT_HOME;
        }
        if ($key=~ m/_NMI_PREREQ_vac_ROOT/){
            $VAC_HOME=$ENV{$key};
        }
        if ($key=~ m/_NMI_PREREQ_vacpp_ROOT/){
            $VACPP_HOME=$ENV{$key};
        }
    }

    $ENV{PATH} = "$ENV{JAVA_HOME}/bin:$ENV{ANT_HOME}/bin:$ENV{PATH}";
    
    if ($ENV{NMI_PLATFORM} =~ m/aix/){
	    $ENV{PATH}="/usr/vac/bin:/usr/vacpp/bin:$VAC_HOME/bin:$VACPP_HOME/bin/:$ENV{PATH}";
    }

    $ENV{'CLASSPATH'} = "";
    
    cmd("env", 1, 1);
    cmd("which java 2>&1", 1, 0);
    cmd("java -version 2>&1", 1, 0);
    cmd("ant -version 2>&1", 1, 0);
    cmd("python -V 2>&1", 1, 0);
    cmd("(rpm -qa | grep python) 2>&1", 1, 0);
    cmd("(dpkg -l | grep python) 2>&1", 1, 0);

    # tmp dir
    $ENV{'TMPDIR'} = "$top_dir/tmp";
    logmsg("TMPDIR set to " . $ENV{'TMPDIR'});
    cmd("mkdir -p $top_dir/tmp", 1, 1);
}


sub build_binary
{
    announce("build mappper package");
    
    cd($src_dir);

    cmd("ant clean", 1, 0);
    cmd("rm -rf dist/*", 1, 0);
    cmd("mkdir -p build-results", 1, 1);

    cmd("ant dist", 1, 1);
    cmd("mv dist/*.tar.gz build-results/", 1, 1);
    cmd("cd build-results/ && ls -l -h", 1, 1);
}


sub build_worker
{
    announce("building worker package");
    
    cd($src_dir);

    cmd("ant clean", 1, 0);
    cmd("rm -rf dist/*", 1, 0);
    cmd("mkdir -p build-results", 1, 1);

    cmd("ant dist-worker", 1, 1);
    cmd("mv dist/*.tar.gz build-results/", 1, 1);
    cmd("cd build-results/ && ls -l -h", 1, 1);
}


sub build_wms
{
    announce("building wms package");
    
    cd("$top_dir/public");
    cmd("ls -l", 1, 1);
    my $condor_version = `ls *.gz | sed 's/condor-//' | sed 's/-.*//' | head -n 1`;
    chomp($condor_version);

    cmd("rm -rf native *.deb *.rpm *.sha1 *.md5 condor_examples condor_tests", 1, 1);
    cmd("rm -f *unstripped*", 1, 1);
    cmd("rm -f *debug*", 1, 1);
    my $num_tars = `ls *.tar.gz | wc -l`;
    # some platforms only have dynamic builds, try to remove the static ones
    if ($num_tars == 2) {
         cmd("ls | grep -v dynamic | xargs rm", 1, 1);
    }
    $num_tars = `ls *.tar.gz | wc -l`;
    if ($num_tars != 1) {
        cmd("ls -l -h", 1, 1);
        die("Too many tars left: $num_tars");
    }

    cmd("ls -l -h", 1, 1);
    cmd("tar xzf *.tar.gz", 1, 1);
    cmd("rm *.tar.gz", 1, 1);

    cmd("ls -l -h", 1, 1);

    # untar our binary package and mv condor into it
    cd("$src_dir/dist");
    cmd("tar xzf ../build-results/pegasus-binary-*.tar.gz", 1, 1);
    cmd("ls -l -h", 1, 1);

    my $pegasus_version = `ls | grep pegasus | sed 's/.*-//'`;
    chomp($pegasus_version);
    logmsg("Pegasus version is $pegasus_version");

    my $pegasus_system = `$src_dir/release-tools/getsystem/getsystem`;
    chomp($pegasus_system);
    logmsg("Pegasus system is $pegasus_system");

    cmd("mv pegasus-$pegasus_version pegasus-wms-$pegasus_version", 1, 1);

    cmd("mv $top_dir/public/condor-* pegasus-wms-$pegasus_version/condor");

    cd("pegasus-wms-$pegasus_version");
    cmd("ls -l -h", 1, 1);
    
    cmd("cp $src_dir/release-tools/nmi/condor* condor/etc/", 1, 1);

    #open(SETUP, ">>setup.sh") or die("Unable to open setup.sh");
    #print SETUP "\n# condor setup\n";
    #print SETUP "PATH=\$PEGASUS_HOME/condor/bin:\$PEGASUS_HOME/condor/sbin:\$PATH\n";
    #print SETUP "export PATH\n";
    #print SETUP "CONDOR_CONFIG=\$PEGASUS_HOME/condor/etc/condor_config\n";
    #print SETUP "export CONDOR_CONFIG\n";
    #close(SETUP);

    #open(SETUP, ">>setup.csh") or die("Unable to open setup.csh");
    #print SETUP "\n# condor setup\n";
    #print SETUP "setenv PATH \$PEGASUS_HOME/condor/bin:\$PEGASUS_HOME/condor/sbin:\$PATH\n";
    #print SETUP "setenv CONDOR_CONFIG \$PEGASUS_HOME/condor/etc/condor_config\n";
    #close(SETUP);

    # work dirs
    cmd("mkdir -p condor/var/execute", 1, 1);
    cmd("mkdir -p condor/var/log", 1, 1);
    cmd("mkdir -p condor/var/spool", 1, 1);

    # tar up the result
    cd("..");
    cmd("tar czf ../build-results/pegasus-wms-binary-$pegasus_version-$pegasus_system.tar.gz" .
        " pegasus-wms-$pegasus_version", 1, 1);
    cmd("rm -rf pegasus*");

    cd("../build-results/");
    cmd("ls -l -h", 1, 1);
}


sub clean_sources
{
    announce("cleaning source tree and condor inputs");

    cd("$top_dir");
    cmd("rm -rf public", 1, 1);

    cd("$src_dir");
    cmd("rm -rf bin build contrib dist doc etc lib libexec man" .
        " share sql src var", 1, 1);

}


sub build_deb
{
    announce("building debian package");
   
    cmd("mkdir -p $top_dir/tmp"); 
    cd("$top_dir/tmp/");

    # we need fakeroot to get file ownership correct in the deb
    cmd("wget -nv http://pegasus.isi.edu/wms/download/tooling/fakeroot-1.12.4.tar.gz 2>&1", 1, 1);
    cmd("tar xzf fakeroot-1.12.4.tar.gz", 1, 1);
    cd("fakeroot-1.12.4");
    cmd("./configure --prefix=$top_dir/tmp/fakeroot-install && make && make install 2>&1", 1, 1);

    cd("$top_dir/tmp/");
    cmd("$top_dir/tmp/fakeroot-install/bin/fakeroot" .
        " $src_dir/release-tools/nmi/deb/build-pegasus-deb" .
        " $src_dir/build-results/pegasus-binary-*.tar.gz", 1, 1);

    cmd("rm -rf fakeroot*", 1, 1);
    cmd("find . -type f -exec ls -l -h {} \\;", 1, 1);

    if ( -e "debian" ) {
        cmd("mv debian $src_dir/build-results/", 1, 1);
    }
    
    if ( -e "ubuntu" ) {
        cmd("mv ubuntu $src_dir/build-results/", 1, 1);
    }
}


sub build_rpm
{
    announce("building rpm package");

    cmd("df -H");
    
    cmd("mkdir -p $top_dir/tmp"); 
    cd("$top_dir/tmp/");

    # rpmbuild has TMPDIR bug
    cmd("(unset TMPDIR &&" .
        " $src_dir/release-tools/nmi/rpm/build-pegasus-rpm" .
        " $src_dir/build-results/pegasus-binary-*.tar.gz)", 1, 1);

    cmd("find . -type f -exec ls -l -h {} \\;", 1, 1);

    if ( -e "rhel" ) {
        cmd("mv rhel $src_dir/build-results/", 1, 1);
    }
    else {
        die("RPM was built - but where did it go?");
    }
}


sub test_binary
{
    my $rc = 0; 
    
    announce("Installing the binary package");
    cmd("mkdir -p $top_dir/binary-test/", 1, 1);
    cd("$top_dir/binary-test");
    cmd("tar xzf $src_dir/build-results/pegasus-binary-*.tar.gz", 1, 1);
    my $dir = `ls`;
    chomp($dir);

    # make sure we are not missing any expected files
    announce("Checking install for missing files");
    my @expected_files = (
        'bin/pegasus-cleanup',
        'bin/pegasus-cluster',
        'bin/pegasus-create-dir',
        'bin/pegasus-keg',
        'bin/pegasus-kickstart',
        'bin/pegasus-transfer',
    );
    foreach my $efile (@expected_files) {
        my $msg = "Checking install for $efile...";
        if ( -e "$top_dir/binary-test/$dir/$efile" ) {
            $msg = sprintf("%-50s %-10s", $msg, "OK");
        }
        else {
            $msg = sprintf("%-50s %-10s", $msg, "MISSING");
            $rc++;
        }
        logmsg($msg);
    }  
    
    announce("cleaning up");
    cd($top_dir);
    cmd("rm -rf binary-test", 1, 0);

    if ($rc != 0) {
        die("Some tests failed");
    }
}


sub test_worker
{
    my $rc = 0; 
    
    announce("Installing the worker package");
    cmd("mkdir -p $top_dir/worker-test/", 1, 1);
    cd("$top_dir/worker-test");
    cmd("tar xzf $src_dir/build-results/pegasus-worker-*.tar.gz", 1, 1);
    my $dir = `ls`;
    chomp($dir);

    # make sure we are not missing any expected files
    announce("Checking install for missing files");
    my @expected_files = (
        'bin/pegasus-cleanup',
        'bin/pegasus-cluster',
        'bin/pegasus-create-dir',
        'bin/pegasus-keg',
        'bin/pegasus-kickstart',
        'bin/pegasus-transfer',
    );
    foreach my $efile (@expected_files) {
        my $msg = "Checking install for $efile...";
        if ( -e "$top_dir/worker-test/$dir/$efile" ) {
            $msg = sprintf("%-50s %-10s", $msg, "OK");
        }
        else {
            $msg = sprintf("%-50s %-10s", $msg, "MISSING");
            $rc++;
        }
        logmsg($msg);
    }  
    
    announce("cleaning up");
    cd($top_dir);
    cmd("rm -rf worker-test", 1, 0);

    if ($rc != 0) {
        die("Some tests failed");
    }
}


sub test_wms
{
    my $rc = 0; 

    announce("fake globus location for Pegasus to be happy");
    $ENV{'GLOBUS_LOCATION'} = "$top_dir/globus";
    cmd("mkdir -p \$GLOBUS_LOCATION/bin", 1, 1);
    cmd("touch \$GLOBUS_LOCATION/bin/globus-url-copy", 1, 1);
    cmd("touch \$GLOBUS_LOCATION/bin/grid-proxy-info", 1, 1);

    announce("installing the wms package");
    cmd("mkdir -p $top_dir/wms/", 1, 1);
    cd("$top_dir/wms");
    cmd("tar xzf $src_dir/build-results/pegasus-wms-*", 1, 1);
    my $dir = `ls`;
    chomp($dir);
    my $install_dir = "$top_dir/wms/$dir";
    cd($install_dir);

    # env
    $ENV{'CONDOR_CONFIG'} = "$install_dir/condor/etc/condor_config";
    $ENV{'PATH'} = "$install_dir/bin:$install_dir/condor/bin:$install_dir/condor/sbin:" . $ENV{'PATH'};

    announce("setting up condor");
    cmd("perl -p -i -e \"s:^RELEASE_DIR.*:RELEASE_DIR=$install_dir/condor:\"" .
        " $install_dir/condor/etc/condor_config", 1, 1);
    cmd("perl -p -i -e \"s:^CONDOR_ADMIN.*:CONDOR_ADMIN=rynge\@isi.edu:\"" .
        " $install_dir/condor/etc/condor_config", 1, 1);

    announce("checking condor");
    $rc += cmd("condor_version", 1, 0);
    $rc += cmd("condor_config_val RELEASE_DIR", 1, 0);

    announce("starting master");
    $rc += cmd("condor_master", 1, 0);

    # wait for the daemons to register
    sleep(120);

    announce("simple condor tests");
    $rc += cmd("condor_status", 1, 0);
    $rc += cmd("condor_q", 1, 0);

    #announce("black diamond test");
    #$rc += cmd("wget -nv http://yggdrasil.isi.edu/~rynge/pegasus-testing/blackdiamond.tar.gz" .
    #           " && tar xzf blackdiamond.tar.gz", 1, 0);
    #cd("blackdiamond");
    #$rc += cmd(". \$PEGASUS_HOME/setup.sh && ./submit-local 2>&1", 1, 0);
    #sleep(180);
    #$dir = `(cd workdir-localcondor/pegasusexec/*/pegasus/black-diamond/*/ && pwd)`;
    #chomp($dir);
    #if ( -e "$dir/f.d" ) {
    #    logmsg("black diamond test successful!");
    #}
    #else {
    #    logmsg("black diamond test failed!");
    #    $rc++;
    #    $dir = `(cd dags/*/pegasus/black-diamond/*/ && pwd)`;
    #    chomp($dir);
    #    cd($dir);
    #    cmd(". \$PEGASUS_HOME/setup.sh && condor_q", 1, 0);
    #    cmd("ls -l $dir/", 1, 0);
    #    cmd(". \$PEGASUS_HOME/setup.sh && pegasus-analyzer -q", 1, 0);
    #}
    
    announce("stopping condor");
    cmd("condor_off -master", 1, 0);
    
    sleep(20);

    announce("showing logs");
    cd("$install_dir/condor/var/log");
    cmd("find $install_dir/condor");
    cmd("for LOG in `ls *Log`; do echo; echo \"## cat \$LOG\"; cat \$LOG; done", 1, 1);    
    
    announce("cleaning up");
    cd($top_dir);
    cmd("rm -rf wms", 1, 0);

    if ($rc != 0) {
        die("Some tests failed");
    }
}


sub cmd
{
    my $cmd = shift;
    my $log = shift;
    my $fatal = shift;
    my $rc = 0;

    if (!defined($log) or $log != 0) {
        $log = 1;
    }

    if (!defined($fatal) or $fatal != 0) {
        $fatal = 1;
    }

    if ($log) {
        logmsg($cmd);
    }

    system("$cmd");
    $rc = $? >> 8;
    if ($fatal and $? & 127) {
        print "\n\n";
        printf "'$cmd' died with signal %d, %s coredump\n",
               ($? & 127),  ($? & 128) ? 'with' : 'without';
        fatal_error("\n");
    }
    if ($rc != 0) {
        if ($fatal) {
            print "\n\n";
            fatal_error("'$cmd' failed with return code $rc\n");
        }
        else {
            logmsg("Ignoring return code $rc. Continuing...");
        }
    }
    print "\n";

    return ($rc);
}

sub cd
{
    my $dir = shift;
    logmsg("cd $dir");
    chdir($dir) or fatal_error("Unable to cd to $dir");
}


sub announce
{
    my $m = shift;
    print "\n";
    print "################################################################\n";
    print "#\n";
    print "#  $m\n";
    print "#\n";
    print "\n";
}


sub logmsg
{
    my $m = shift;
    my $date = `/bin/date +'\%y\%m\%d \%H:\%M'`;
    chomp($date);
    print "[$date]:  $m\n";
}


sub fatal_error
{
    my $msg = shift;

    print STDERR "$msg\n\n";

    exit(1);
}


