#!/usr/bin/env perl

$tagsets = "tagsets";
if (!-d $tagsets || !-r $tagsets || !-x $tagsets) { die "missing the directory of distribution tables: $tagsets\n"; }

$version = "";
$clean = 0;
$rebuild = 0;
$optimize = 0;
$start = "";
$stop = "";
$verbose = 0;

@tARGV = ();
for (; @ARGV > 0; ) {
    if ($ARGV[0] eq "-version") {
	$version = $ARGV[1];
        shift; shift; next;
    }
    if ($ARGV[0] eq "-verbose") {
	$verbose = 1;
        shift; next;
    }
    if ($ARGV[0] eq "-clean") {
	$clean = 1;
        shift; next;
    }
    if ($ARGV[0] eq "-rebuild") {
	$rebuild = 1;
        shift; next;
    }
    if ($ARGV[0] eq "-optimize") {
	$optimize = 1;
        shift; next;
    }
    if ($ARGV[0] eq "-only") {
	$start = $ARGV[1];
	$stop = $ARGV[1];
        shift; shift; next;
    }
    if ($ARGV[0] eq "-start") {
	$start = $ARGV[1];
        shift; shift; next;
    }
    if ($ARGV[0] eq "-stop") {
	$stop = $ARGV[1];
        shift; shift; next;
    }
    if ($ARGV[0] eq "-list") {
	&list_distributions ();
    }
    if ($ARGV[0] eq "-env") {
	&show_environment ();
    }
    if ($ARGV[0] eq "-h")     { &usage (); }
    if ($ARGV[0] eq "-help")  { &usage (); }
    if ($ARGV[0] eq "--help") { &usage (); }
    @tARGV = (@tARGV, $ARGV[0]);
    shift;
}
@ARGV = @tARGV;

if ( @ARGV == 0) { 
    @list = <$tagsets/*.dist>;
    $distribution = $list[-1];
} else {
    $distribution = "$tagsets/$ARGV[0].dist";
}

&load_distfile ();

&build_distribution ();
exit 0;

sub show_environment {
    
    # use psconfig.csh to set needed build aliases

    # set the psconfig version:
    if ("$version" eq "") {
	$version = $ENV{'PSVERSION'};
    }
    if ("$version" eq "") {
	$version = "default";
    }

    $psconfigure = `csh psconfig.csh --psconfigure $version`; chomp $psconfigure;
    $psautogen   = `csh psconfig.csh --psautogen $version`;   chomp $psautogen;
    $psperlbuild = `csh psconfig.csh --psperlbuild $version`; chomp $psperlbuild;

    # print "psconfigure: $psconfigure\n";
    # print "psautogen:   $psautogen\n";
    # print "psperlbuild: $psperlbuild\n";

    # set build environment variables
    ps_setenv (1, "PATH", 		  "--path");
    ps_setenv (1, "CPATH",		  "--cpath");
    ps_setenv (1, "ARCH", 		  "--arch");
    ps_setenv (1, "LIBRARY_PATH",    "--library_path");
    ps_setenv (1, "LD_LIBRARY_PATH", "--ld_library_path");
    ps_setenv (1, "PKG_CONFIG_PATH", "--pkg_config_path");
    ps_setenv (1, "ACLOCAL_FLAGS",   "--aclocal_flags");
    ps_setenv (1, "PERL5LIB",        "--perl5lib");

    exit 0;
}

sub build_distribution {
    
    # use psconfig.csh to set needed build aliases

    # set the psconfig version:
    if ("$version" eq "") {
	$version = $ENV{'PSVERSION'};
    }
    if ("$version" eq "") {
	$version = "default";
    }

    $psconfigure = `csh psconfig.csh --psconfigure $version`; chomp $psconfigure;
    $psautogen   = `csh psconfig.csh --psautogen $version`;   chomp $psautogen;
    $psperlbuild = `csh psconfig.csh --psperlbuild $version`; chomp $psperlbuild;

    # print "psconfigure: $psconfigure\n";
    # print "psautogen:   $psautogen\n";
    # print "psperlbuild: $psperlbuild\n";

    # set build environment variables
    ps_setenv (0, "PATH", 		  "--path");
    ps_setenv (0, "CPATH",		  "--cpath");
    ps_setenv (0, "ARCH", 		  "--arch");
    ps_setenv (0, "LIBRARY_PATH",    "--library_path");
    ps_setenv (0, "LD_LIBRARY_PATH", "--ld_library_path");
    ps_setenv (0, "PKG_CONFIG_PATH", "--pkg_config_path");
    ps_setenv (0, "ACLOCAL_FLAGS",   "--aclocal_flags");
    ps_setenv (0, "PERL5LIB",        "--perl5lib");

    # some versions of libtool use this value:
    $ENV{'D'} = "";

    # make sure the aclocal path exists
    @word = split (" ", $ENV{'ACLOCAL_FLAGS'});
    if (@word != 2) { &failure("setup", "ACLOCAL_FLAGS is not set"); }
    if (! -e $word[1]) { vsystem ("mkdir -p $word[1]"); }

    $psopts = "";
    if ($optimize) { $psopts = "$psopts --enable-optimize"; }

    $homedir = `pwd`; chomp $homedir;

    $stop_now = 0;
    for ($i = 0; !$stop_now && ($i < @cvsname); $i++) {
	if (($stop ne "") && ($stop eq $cvsname[$i])) { $stop_now = 1; }
	if (($start ne "") && ($start ne $cvsname[$i])) { next; }
	$start = "";

	($do_tag, $do_build, $do_package, $do_update) = $mode[$i] =~ m|(\S)(\S)(\S)(\S)|;
	if ($do_build eq "N") { next; }

	$workdir = "../$cvsname[$i]";

	# XXX need to grab current value for cleanup
	print "\n ** psbuild: $cvsname[$i] ** \n";
	print "\033]0; ** psbuild: $cvsname[$i] ** \007";

	if (!-d $workdir || !-r $workdir || !-x $workdir) { 
	    print STDERR "WARNING: no directory for component $cvsname[$i], skipping\n"; 
	    next;
	}
	
	chdir $workdir;

	# how do we build this component?
	# - autogen.sh : configure : make : make install
	# - configure : make : make install
	# - make : make install
	# - perl Build.PL : ./Build : ./Build install
 
	if (-e "Build.PL") {
	    vsystem ("$psperlbuild");
	    if ($?) { &failure($cvsname[$i], "failure in perl Build.PL"); }

	    vsystem ("./Build");
	    if ($?) { &failure($cvsname[$i], "failure in Build"); }

	    vsystem ("./Build install");
	    if ($?) { &failure($cvsname[$i], "failure in Build install"); }
	    
	    next;
	}

	if ($rebuild && $clean) {
	    if (-e "configure") { unlink "Makefile"; }
	    if (-e "configure.ac" && -e "autogen.sh") { unlink "configure"; }
	}
	$rebuild_this = $rebuild;

	# set a local variable for this loop on rebuild;
	if (! -e "Makefile") { $rebuild_this = 1; }

	#  run autogen
	$skip_configure = 0;
	if ($rebuild_this && ! -e "configure" && -e "autogen.sh") {
	    $skip_configure = 1;
	    vsystem ("$psautogen $psopts");
	    if ($?) { &failure($cvsname[$i], "failure in psautogen"); }
	}

	if ($rebuild_this && -e "configure" && !$skip_configure) {
	    vsystem ("$psconfigure $psopts");
	    if ($?) { &failure($cvsname[$i], "failure in psconfigure"); }
	}

	if (! -e "Makefile") { &failure($cvsname[$i], "missing makefile"); }

	if ($clean) { 
	    vsystem ("make clean");
	    if ($?) { &failure($cvsname[$i], "failure in make clean"); }
	}

	vsystem ("make");
	if ($?) { &failure($cvsname[$i], "failure in make"); }

	vsystem ("make install");
	if ($?) { &failure($cvsname[$i], "failure in make install"); }

	print "*** done with $cvsname[$i] ***\n";

      success:
	chdir $homedir;
    }
    print "\033]0; ** psbuild: finished ** \007";
    exit 0;
}

sub vsystem {
    print STDERR "@_\n";
    $status = system ("@_");
    $status;
}

sub list_distributions {
    @list = <$tagsets/*.dist>;
    foreach $line (@list) {
	chomp $line;
	($dist) = $line =~ m|$tagsets/(\S*).dist|;
	print STDERR "$dist\n";
    }
    exit 2;
}

sub load_distfile {
    # open and read the distribution file
    # results go into @cvsname, @branchtag, @branchver, @mode
    open (FILE, $distribution) || die "ERROR: can't open distribution file $distribution\n";
    @list = <FILE>;
    close (FILE);

    @mode = ();
    @cvsname = ();
    @branchtag = ();
    @branchver = ();

    foreach $line (@list) {
	chop $line;
	if ($line =~ m|^\s*$|) { next; }
	if ($line =~ m|^\s*\#|) { next; }

	($mode, $cvsname, $branchtag, $branchver) = split (" ", $line);
	
	if ($cvsname eq "") { die "missing module name\n"; }

	($do_tag, $do_build, $do_package, $do_update) = $mode =~ m|(\S)(\S)(\S)(\S)|;
	if (($do_tag ne "Y") && ($do_tag ne "N")) { die "invalid tag option $do_tag\n"; }
	if (($do_build ne "Y") && ($do_build ne "N")) { die "invalid tag option $do_build\n"; }
	if (($do_package ne "Y") && ($do_package ne "N")) { die "invalid tag option $do_package\n"; }
	if (($do_update ne "Y") && ($do_update ne "N")) { die "invalid tag option $do_update\n"; }
	
	if ($verbose) { print "tag: $do_tag, build: $do_build, package: $do_package, update: $do_update "; }
	if ($verbose) { print "module: $cvsname, branchtag: $branchtag, branchver: $branchver \n"; }

	push @mode, $mode;
	push @cvsname, $cvsname;
	push @branchtag, $branchtag;
	push @branchver, $branchver;
    }
}

sub failure {
    die "problem building $_[0] : $_[1]\n";
    print "\033]0; ** psbuild: failure  ** \007";
}

sub usage {
    print STDERR "USAGE: psbuild [options] (distribution)\n";
    print STDERR "     : -version (version) : specify alternate psconfig installation version\n";
    print STDERR "     : -clean             : clean the source directories before building\n";
    print STDERR "     : -rebuild           : run 'autogen' (C code)\n";
    print STDERR "     : -optimize          : set flags for optimized code\n";
    print STDERR "     : -only (module)     : only build the specified module\n";
    print STDERR "     : -start (module)    : begin build at specified module\n";
    print STDERR "     : -stop (module)     : stop build after specified module\n\n";
    print STDERR "     : psbuild -list      : list the available distributions\n";
    print STDERR "     : psbuild -h         : this help listing\n";
    print STDERR "     : psbuild -help      : this help listing\n";
    print STDERR "     : psbuild --help     : this help listing\n";
    exit 2;
}

sub ps_setenv {

    my $verbose = $_[0];
    my $var = $_[1];
    my $flag = $_[2];

    my $answer = `csh psconfig.csh $flag $version`;
    chomp $answer;

    $ENV{$var} = $answer;
    if ($verbose) {
	print STDERR "$var = $answer\n";
    }
}

