#! /s/std/bin/perl -w

##**************************************************************
##
## Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
## University of Wisconsin-Madison, WI.
## 
## Licensed under the Apache License, Version 2.0 (the "License"); you
## may not use this file except in compliance with the License.  You may
## obtain a copy of the License at
## 
##    http://www.apache.org/licenses/LICENSE-2.0
## 
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
##**************************************************************


use strict;

# Prototypes
sub main( @ );
sub List( $@ );
sub BuildTarball( $@ );

# Command line stuff
my $Program = "make_hawkeye_modules";
my %Options =
    (
     "[-a|--all]"	=> "Generate all targets",
     "[(-d|--dir)=dir]"	=> "Specify target directory 'dir'",
     "[--dep]"		=> "List dependencies (implies -n)",
     "[--dep-full]"	=> "List dependencies with full paths (implies -n)",
     "[-v|--versions]"	=> "Dump version of file (implies -n)",
     "[-n|--noexec]"	=> "No execute mode",
     "[-r|--release]"	=> "Enable release mode",
     "[-f|--force]"	=> "force",
     "[-h|--help]"	=> "Dump help",
     "tarball"		=> "Target tarball",
     "[files]"		=> "List of '.hawk' files",
    );

# Invoke main..
main( @ARGV );
$#ARGV = -1;

# ******************************************************
# Main program..
# ******************************************************
sub main( @ )
{
    my @Targets;
    my $AllTargets = 0;
    my $ModulesFile = "Hawkeye.modules";
    my %KnownTargets;
    my $DefaultDir = ".";
    my $TestDir = ".";
    my $ModulePrefix = "";
    my $TargetDir = "";
    my $Force = 0;
    my $ReleaseMode = 0;
    my $DumpVersion = 0;
    my $DumpList = 0;
    my $DumpDepend = 0;
    my $DumpDependFull = 0;
    my $Exec = 1;

    # Process the command line...
    foreach my $Arg ( @_ )
    {
	# Option?
	if ( $Arg =~ /^(-|--)(\w[\w_\-]*)(?:=(.*))?/ )
	{
	    my $Opt = "";
	    my $LongOpt = "";
	    my $Value = "";
	    if ( $1 eq "-" ) {
		$Opt = $2;
	    } else {
		$LongOpt = $2;
	    }
	    $Value = $3 if ( defined $3 );

	    if ( ( $Opt eq "h" ) or ( $LongOpt eq "help" ) )
	    {
		Help( );
	    }
	    elsif (  ( $Opt eq "d"  or  $LongOpt eq "dir"  ) and
		     ( $Value ne "" )  )
	    {
		$TargetDir = $Value;
	    }
	    elsif ( $Opt eq "f" or $LongOpt eq "force" )
	    {
		$Force = 1;
	    }
	    elsif ( $Opt eq "a" or $LongOpt eq "all" )
	    {
		$AllTargets = 1;
	    }
	    elsif ( $Opt eq "r" or $LongOpt eq "release" )
	    {
		$ReleaseMode = 1;
	    }
	    elsif ( $Opt eq "l" or $LongOpt eq "list" )
	    {
		$DumpList = 1;
		$Exec = 0;
	    }
	    elsif ( $Opt eq "v" or $LongOpt eq "version" )
	    {
		$DumpVersion = 1;
		$Exec = 0;
	    }
	    elsif ( $LongOpt eq "dep" )
	    {
		$DumpDepend = 1;
		$Exec = 0;
	    }
	    elsif ( $LongOpt eq "dep-full" )
	    {
		$DumpDependFull = 1;
		$Exec = 0;
	    }
	    elsif ( $Opt eq "n" or $LongOpt eq "noexec" )
	    {
		$Exec = 0;
	    }
	    else
	    {
		Usage( $Arg );
	    }
	    next;
	}

	# Must be a target name
	push( @Targets, $Arg );
    }

    # Read the modules file
    open( MODULES, $ModulesFile ) || die "Can't read $ModulesFile";
    my $Target = "";
    while( <MODULES> )
    {
	chomp;
	next if ( ( /^\#/ ) || ( $_ eq "" ) );
	if ( /^directory:\s+(\S+)/i )
	{
	    $DefaultDir = $1;
	}
	elsif ( /^test-directory:\s+(\S+)/i )
	{
	    $TestDir = $1;
	}
	elsif ( /^prefix:\s+(\S+)/i )
	{
	    $ModulePrefix = $1;
	}
	elsif ( /^target:\s+(\S+)/i )
	{
	    $Target = $1;
	}
	elsif ( /^version:\s+(\S+)/i )
	{
	    $KnownTargets{$Target}{Version} = $1;
	}
	elsif ( /^os:\s+(\S+)/i )
	{
	    $KnownTargets{$Target}{OS} = $1;
	}
	elsif ( /^\+(.*)/ )
	{
	    push( @{$KnownTargets{$Target}{HawkFiles}},
		  map( { "$_.hawk" } split( /[\s\,]+/, $1 ) ) );
	}
	else
	{
	    die "$ModulesFile line $.: parse error";
	}
    }
    close( MODULES );

    # Env variable overrides the dirctory from the file...
    if ( exists $ENV{HAWKEYE_RELEASE_DIR} )
    {
	$DefaultDir = "$ENV{HAWKEYE_RELEASE_DIR}/modules";
    }
    if ( exists $ENV{HAWKEYE_MODULES_DIR} )
    {
	$DefaultDir = $ENV{HAWKEYE_MODULES_DIR};
    }

    # Dir logic
    if ( $TargetDir eq "" )
    {
	$TargetDir = $ReleaseMode ? $DefaultDir : $TestDir;
    }

    # Create the directory?
    if ( ! -d $TargetDir )
    {
	mkdir $TargetDir || die "Can't create modoles dir $TargetDir";
    }

    # Any valid targets?
    {
	my @Tmp = keys %KnownTargets;
	die "No targets in $ModulesFile" if ( $#Tmp < 0 );
    }

    # Verify that the TarBall specified
    if ( $#Targets < 0 )
    {
	if ( $AllTargets )
	{
	    @Targets = sort keys %KnownTargets;
	}
	else
	{
	    print STDERR "No targets specfied; use --all to build all\n";
	    exit 1;
	}
    }

    # Quick checks of the defined targets
    foreach my $Target( keys %KnownTargets )
    {
	die "$Target has no version defined"
	    if ( ! exists $KnownTargets{$Target}{Version} );
	if ( ! exists $KnownTargets{$Target}{OS} )
	{
	    $KnownTargets{$Target}{OS} = "Unix-Any";
	    warn "No O/S Specified; assuming 'Unix-Any'";
	}
	die "$Target has no files"
	    if ( ! exists $KnownTargets{$Target}{HawkFiles} );
	foreach my $File ( @{$KnownTargets{$Target}{HawkFiles}} )
	{
	    die "'$File' of target '$Target' not found\n" if ( ! -f $File );
	}
    }
    # And, verify that the requested targets exist...
    foreach my $Target ( @Targets )
    {
	die "$Target is not a valid target"
	    if ( ! exists $KnownTargets{$Target} );
    }

    # List
    if ( $DumpList || $DumpDepend || $DumpDependFull )
    {
	foreach my $Target ( @Targets )
	{
	    if ( $DumpDepend )
	    {
		print "$Target: ";
	    }
	    elsif ( $DumpDependFull )
	    {
		my $Version = $KnownTargets{$Target}{Version};
		my $OS = $KnownTargets{$Target}{OS};
		my $TarBall = $ModulePrefix . $Target . "-" . $Version .
		    "-".  $OS . ".tar.gz";
		my $TarBallFull = "$TargetDir/$TarBall";
		print "$TarBallFull: ";
	    }
	    elsif ( $#Targets > 0 )
	    {
		print "$Target: ";
	    }
	    List( $DumpDepend, @{$KnownTargets{$Target}{HawkFiles}} );
	}
    }

    # Version dump
    if ( $DumpVersion )
    {
	foreach my $Target ( @Targets )
	{
	    my $Version = $KnownTargets{$Target}{Version};

	    # Do it
	    print "$Target: " if ( $#Targets > 0 );
	    print "$Version\n";
	}
    }

    exit 0 if ( ! $Exec );

    # Ok, now do the work
    print "Target directory = $TargetDir\n";
    foreach my $Target ( @Targets )
    {
	my $Version = $KnownTargets{$Target}{Version};
	my $OS = $KnownTargets{$Target}{OS};
	my $TarBall =
	    $ModulePrefix . $Target . "-" . $Version . "-".  $OS . ".tar.gz";
	my $TarBallFull = "$TargetDir/$TarBall";

	# Does it already exist?
	if ( ( 0 == $Force ) && ( -f $TarBallFull ) )
	{
	    print "\n$TarBall exists; skipping\n";
	    print "  Use -f to force overwrite\n";
	    next;
	}

	# Do it
	print "\nBuilding $Target $Version -> '$TarBall'\n";
	BuildTarball( "$TargetDir/$TarBall",
		      @{$KnownTargets{$Target}{HawkFiles}} );
    }

    # All done: ok
    exit 0;

} # main()
# ******************************************************

# ******************************************************
# List files
# ******************************************************
sub List( $@ )
{
    my $Depend = shift;
    my @HawkFiles = @_;

    # Walk through the files..
    my @AllFiles;
    foreach my $HawkFile ( @HawkFiles )
    {
	die "$HawkFile does not exist" if ( ! -f $HawkFile );
	push( @AllFiles, $HawkFile ) if ( $Depend );

	open( HAWKFILE, $HawkFile ) || die "Can't read $HawkFile";
	while( <HAWKFILE> )
	{
	    # All we care about is the ModuleFiles line(s)...
	    if ( /MODULEFILES:\s*(.+)/i )
	    {
		my @Files = split( /\s+/, $1 );
		foreach my $File ( @Files )
		{
		    die "$HawkFile line $.: $File does not exist"
			if ( ! -f $File );
		}
		push( @AllFiles, @Files );
	    }
	}
	close( HAWKFILE );
    }

    # Ok, now just build the tarball...
    print join( " ", @AllFiles ) . "\n";

    return 0;

} # List ()
# ******************************************************

# ******************************************************
# Build a single TarBall
# ******************************************************
sub BuildTarball( $@ )
{
    my $TarBall = shift @_;
    my @HawkFiles = @_;

    # Walk through the files..
    my @AllFiles;
    foreach my $HawkFile ( @HawkFiles )
    {
	die "$HawkFile does not exist" if ( ! -f $HawkFile );
	push @AllFiles, $HawkFile;

	open( HAWKFILE, $HawkFile ) || die "Can't read $HawkFile";
	while( <HAWKFILE> )
	{
	    # All we care about is the ModuleFiles line(s)...
	    if ( /MODULEFILES:\s*(.+)/i )
	    {
		my @Files = split( /\s+/, $1 );
		foreach my $File ( @Files )
		{
		    die "$HawkFile line $.: $File does not exist"
			if ( ! -f $File );
		}
		push @AllFiles, @Files;
	    }
	}
	close( HAWKFILE );
    }

    # Ok, now just build the tarball...
    my $Cmd = "tar cvfhz $TarBall " . join( " ", @AllFiles );
    system( $Cmd ) == 0 || die "system '$Cmd' failed: $?";

    return 0;

} # BuildTarball ()
# ******************************************************

# ******************************************************
# Dump out usage
# ******************************************************
sub Usage ( $ )
{
    my $Unknown = shift;

    print "$Program: unknown option '$Unknown'\n" if ( $Unknown ne "" );
    printf "usage: $Program %s\n", join (" ", sort keys %Options);
    print "use '-h' for more help\n";
    exit 1;

} # usage ()
# ******************************************************

# ******************************************************
# Dump out help
# ******************************************************
sub Help ( )
{
    my ($opt, $text);

    printf "usage: $Program %s\n", join (" ", sort keys %Options);
    foreach $opt (sort {lc($a) cmp lc($b) } keys %Options)
    {
	printf ("  %15s : %-40s\n", $opt, $Options{$opt} );
    }
    exit 0;

} # help ()
# ******************************************************
