#!/usr/bin/perl -w
#
# webbuilder
#
# Script to traverse a directory, building stuff in each dir as it goes.
#
# Copyright (C) 1999-2000 S Morphet <smorphet@iee.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software 
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

# Modules.
use Cwd;
use FileHandle;

# Function to print usage information.
sub DieUsage {
  print "\n";
  print "$id_name $id_version ($id_tag)\n" .
    "Usage: $id_name [options] dir-options\n\n";
  print "Options: -v \t\t Be verbose\n";
  print "\t -r dir \t Remote build directory\n";
  print "\t -l dir \t Local build directory\n";
  print "\t -X file \t Name of dirs NOT to recurse into.\n";
  print "\t -M file \t Name of files to treat as makefiles.\n";
  print "\t -make prog \t Name of program to run as make.\n";
  print "\t -makeopts opts  Options to pass to make program.\n";
  print "\t -filespec arg \t Command line argument to specify " .
    "makefile to make.\n";
  print "\t -ltarg target \t Target for local build (default 'local').\n";
  print "\t -rtarg target \t Target for remote build (default 'remote').\n";
  print "\t -version \t Print version info and exit.\n";
  print "\n";
  print "One or both of -r and -l must be specified.\n";
  print "If -filespec is not used the makefile will not be specified " .
    "to the\nmake program.\n\n";
  exit;
}


# Expand a filename in a directory, and store the results in a hash.
sub ExpandFilenameIntoHash {
  my ($filename, $srcdir, $hashref) = @_;
  my @explist;
  my $earg;

  # Expand the filename.
  @explist = map { glob($_) } "$srcdir/$arg";

  # Add each expanded filename to the hash.
  foreach $earg ( @explist ) {
    # Remove the source directory from the name.
    $earg =~ s/$srcdir\/(.*)/$1/;

    # Add the name to the hash.
    $$hashref{$earg} = 1;
  }
}


#########################
## Main program start. ##
#########################

# Get information from rcs.
# Spaces before the closing quotes are preserved by RCS and stop
# emacs syntax highlighting thinking there's a variable called $'
$programid = '$Id: webbuilder,v 1.7 2000/06/11 00:37:37 sdm Exp $ ';
$programid =~ /\$Id: (.*?),v (.*?) (.*?) /;
$id_name = $1;
$id_version = $2;
$id_date = $3;

$tagname   = '$Name: Guava-1_0_3 $ ';
$tagname   =~ /\$Name: (.*?) /;
if( $1 ne "" ) {
  $id_tag = $1;
}else{
  $id_tag = "none";
}

# Process arguments specified on command line.
$verbose = 0;

$doremote = 0;
$dolocal = 0;

$remotetarget = "remote";
$localtarget = "local";

@norecurseargs = ();

$makefilesset = 0;
@makefiles = ();

$makeopts = "";

$makefilespecset = 0;
$makefilespec = "";

$makeprog = "make";

$recurseargs = "";

$numargs = $#ARGV;
while( ($numargs >= 0) and $ARGV[0] =~ /^-/ )
  {  
    if( $ARGV[0] eq "-v" ) {
      $verbose = 1;
      $recurseargs .= "-v";
    }
    elsif( $ARGV[0] eq "-l" ) {
      $numargs -= 1;
      shift;
      $dolocal = 1;
      $localdir = $ARGV[0];
    }
    elsif( $ARGV[0] eq "-r" ) {
      $numargs -= 1;
      shift;
      $doremote = 1;
      $remotedir = $ARGV[0];
    }
    elsif( $ARGV[0] eq "-X" ) {
      shift;
      $numargs -= 1;
      push( @norecurseargs, $ARGV[0] );
      $recurseargs .= " -X \"$ARGV[0]\"";
    }
    elsif( $ARGV[0] eq "-M" ) {
      shift;
      $numargs -= 1;
      $makefilesset = 1;
      push( @makefiles, $ARGV[0] );
      $recurseargs .= " -M $ARGV[0]";
    }
    elsif( $ARGV[0] eq "-make" ) {
      shift;
      $numargs -= 1;
      $makeprog = $ARGV[0];
      $recurseargs .= " -make $ARGV[0]";
    }
    elsif( $ARGV[0] eq "-makeopts" ) {
      shift;
      $numargs -= 1;
      $makeopts = $ARGV[0];
      $recurseargs .= " -makeopts \"$ARGV[0]\"";
    }
    elsif( $ARGV[0] eq "-filespec" ) {
      shift;
      $numargs -= 1;
      $makefilespecset = 1;
      $makefilespec = $ARGV[0];
      $recurseargs .= " -filespec \"$ARGV[0]\"";
    }
    elsif( $ARGV[0] eq "-ltarg" ) {
      shift;
      $numargs -= 1;
      $localtarget = $ARGV[0];
      $recurseargs .= " -ltarg \"$ARGV[0]\"";
    }
    elsif( $ARGV[0] eq "-rtarg" ) {
      shift;
      $numargs -= 1;
      $remotetarget = $ARGV[0];
      $recurseargs .= " -rtarg \"$ARGV[0]\"";
    }
    elsif( $ARGV[0] eq "-version" ) {
      print "$id_name, version $id_version, release $id_tag, $id_date.\n";
      exit;
    }
    else {
      print "Unknown option $ARGV[0]\n";
      DieUsage;
    }
    
    $numargs -= 1;
    shift;
  }

# All args should have been consumed...
DieUsage if( $numargs != -1 or ($doremote == 0 and $dolocal == 0));

# If nothing specified on command line, set some defaults.
if( $makefilesset == 0 ) {
  push( @makefiles, "Makefile" );
  push( @makefiles, "makefile" );
}


foreach $mode ( "-l", "-r" ) {

  # If we aren't doing a particular mode, skip it...
  next if( $mode eq "-l" and $dolocal == 0 );
  next if( $mode eq "-r" and $doremote == 0 );

  # Get the appropriate dir.
  if( $mode eq "-l" ){ 
    $dir = $localdir; 
  }else{ 
    $dir = $remotedir; 
  }

  print "Processing $mode in $dir\n" if $verbose;

  # Expand Norecurse filenames into the hash.
  %norecurse = ();
  foreach $arg (@norecurseargs) {
    ExpandFilenameIntoHash( $arg, $dir, \%norecurse );
  }

  # Strip trailing slash off the dir name.
  $dir =~ s/(.*)\/$/$1/;

  # Read the files in the current directory.
  @files = <$dir/*>;

  # Look for any of the makefiles in the local dir, and if found, run the
  # make commands.
  foreach $testfile ( @makefiles ) {
    print "Testing for $dir/$testfile... " if $verbose;
    if( -e "$dir/$testfile" ) {

      # Found a makefile.
      print "Found.\n" if $verbose;

      # Build the command string.
      $command = "$makeprog ";
      
      # If specifying the name of the makefile...
      if( $makefilespecset ) {
	$command .= "$makefilespec $testfile ";
      }

      # Add options to make.
      if( $makeopts ne "" ) {
	$command .= "$makeopts ";
      }

      # Add the appropriate target name.
      if( $mode eq "-l" ) {
	$command .= "$localtarget";
      } else {
	$command .= "$remotetarget";
      }

      # Change into the right dir.
      $initialpwd = cwd();
      chdir $dir;
      
      # Run the make command.
      print "Running \"$command\" in $dir for mode = $mode\n" if $verbose;
      
      STDOUT->flush();
      $rc = system "$command";

      if( $rc ) {
	die "$id_name: make command failed in $dir.\n";
      }

      # Change back to the working dir.
      chdir $initialpwd;
      
      # Break out of the loop when make has run once.
      last;
    } else {
      # Terminate the verbose output.
      print "\n" if $verbose;
    }
  }

  # Process each file to see if it has to be recursed into.
  foreach $file (@files) {
  
    # Is this file a directory?
    if( -d $file ) { $isdir = 1; } else { $isdir = 0; }
    
    # We need to search hashes for the basename, not the whole thing...
    $basename = `basename $file`;
    
    # Remove whitespace from the basename.
    $_ = $basename;
    /\s*(.*)\s*/;
    $basename = $1;

    if( $isdir ) {
      print "Checking directory $file..." if $verbose;
    
      if( !defined $norecurse{$basename} ) {
	# Go into directories (as long as it's not in the list of
	# directories not to go into).
	print "\n" if $verbose;
	
	# Run the same program in the subdirectory.
	print "Running: $0 $recurseargs $mode $file\n" if $verbose;

	#Flush verbose output before running another program.
	STDOUT->flush();
	$rc = system "$0 $recurseargs $mode $file";

	if( $rc ) {
	  die "$id_name: Failed to run $0 in $file.\n";
	}
      }   
      else {
	print "Blocked.\n" if $verbose;
      }
    }
  }
}



