#!/usr/bin/perl

eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
    if 0; # not running under some shell
#
# check out all of the perl binaries in the user's path and see which
# one is a valid 5.005 interpreter.  if a match is found, substitute
# that interpreter's full pathname into all of the gpt sbin scripts.
#

use Getopt::Long;
use Cwd;
use Config;

#
# read in the main GPT environment variables
#

my $gpath = $ENV{GPT_LOCATION};

if (!defined($gpath))
{
   $gpath = $ENV{GLOBUS_LOCATION};
}

if (!defined($gpath))
{
     die "GPT_LOCATION or GLOBUS_LOCATION needs to be set before running this script";
}

#
# alter the include path
#

@INC = ("$gpath/lib/perl", "$gpath/lib/perl/$Config{'archname'}", @INC);

if ( ! ( defined eval "require Grid::GPT::GPTObject" ) )
{
    die("$gpath does not appear to hold a valid GPT installation\n");
}

my ($path, @pathdirs);

$path = $ENV{PATH};
@pathdirs = split(/:/, $path);

my $version = 
  {
    'name' => "gpt-translate-interpreter",
    'id' => "0.1",
  };

require Pod::Usage;

my ($mode, $perl, $force);

GetOptions( 'dir=s' => \$dir,
            'help|?' =>
              sub { setmode("help"); },
            'information' =>
              sub { setmode("info"); },
            'version' =>
              sub { setmode("version"); },
            'man' =>
              sub { setmode("man"); },
            'perl=s' => \$perl,
            'force' => \$force,
          ) or Pod::Usage::pod2usage(2);

#
# do our directory picking magic here
#

$dir =~ s|\s+||g;

if ( !defined($dir) || (length($dir) == 0) )
{
    $dir = $gpath;
}

#
# make sure that the directory we've chosen appears to be a valid GPT installation
#

if ( ! -e "$dir/sbin/gpt-build" )
{
    die("'$dir' does not appear to be a valid GPT installation!\n");
}

#
# these are the files requiring interpreter substitution
#

@files = (
    "gpt-build",
    "gpt_build_config",
    "gpt-bundle",
    "gpt_create_automake_rules",
    "gpt-edit",
    "gpt_extract_data",
    "gpt-flavor-configuration",
    "gpt_generate_bin_pkg_data",
    "gpt_get_lib_names",
    "gpt-install",
    "gpt-pkg",
    "gpt-postinstall",
    "gpt-query",
    "gpt_save_flavor",
    "gpt-setup",
    "gpt_sort_filelist",
    "gpt-undefines",
    "gpt-uninstall",
    "gpt-verify",
    "gpt-virtual-pkg",
    "ptar",
         );

enactProgram($mode);

exit;

#
# subroutines
#

### absolutePath( )
#
# accept a list of files and, based on our current directory, make their pathnames absolute
#

sub absolutePath
{
    my ($file) = @_;
    my $cwd = cwd();

    if ($file !~ /^\//)
    {
        $file = $cwd . "/" . $file;
    }

    return $file;
}

### enactProgram( $mode )
#
# based on the mode with which we were called, enact the program as desired
#

sub enactProgram
{
    my ($mode) = @_;

    #
    # process our different invocation modes
    #

    if ($mode eq "version")
    {
        #
        # if --version is used, we print our current version number
        #

        printf("%s\n", $version->{'id'});
    }
    elsif ($mode eq "info")
    {
        #
        # if --info is used, we print our $version information
        #

        printf("NCSA %s v%s\n", $version->{'name'}, $version->{'id'});
        printf("Copyright 2002 National Center for Supercomputing Applications.\n");
        printf("This program has absolutely no warranty.\n");
    }
    elsif ($mode eq "help")
    {
        #
        # if --help is specified, print the synopsis, options, and/or arguments sections
        #

        Pod::Usage::pod2usage(1);

        #
        # doesn't return
        #
    }
    elsif ($mode eq "man")
    {
        #
        # if --man is specified, exit with value 0 and print the entire pod document
        #

        Pod::Usage::pod2usage('-exitval' => 0, '-verbose' => 2);

        #
        # doesn't return
        #
    }
    else
    {
        #
        # otherwise call main
        #

        main();
    }
}

### main( )
#
# main driver function
#

sub main
{
    my $skgversion = "5.005";

    $perl =~ s|\s+||g;

    if ( !defined($perl) || (length($perl) == 0) )
    {
        $ptp = detValidInterpreters(\@pathdirs, $skgversion);
        if ( !defined($ptp) )
        {
            die("Could not find a valid Perl interpreter that supports version $skgversion!\n");
        }
    }
    else
    {
        $perl = absolutePath($perl);

        if ( !testInterp($perl, $skgversion) )
        {
            die("'$perl' does not support version $skgversion!\n") unless $force;
        }

        $ptp = $perl;
    }

    printf("Using '$ptp' as GPT's interpreter...\n");

    printf("Substituting values in '$dir'... ");
    substituteInterp($ptp);
    printf("done.\n");
}

### substituteInterp( $ptp )
#
# for each file in @files, change /usr/bin/perl to $ptp
#

sub substituteInterp
{
    my ($ptp) = @_;

    $olddir = cwd();
    chdir("$dir/sbin");

    for my $f (@files)
    {
        action("chmod 755 $f");
        $data = readFile($f);
        $data =~ s|^.*\n|#!$ptp\n|;
        writeFile($f, $data);
        action("chmod 555 $f");
    }

    chdir($olddir);
}

### readFile( $filename )
#
# reads and returns $filename's contents
#

sub readFile
{
    my ($filename) = @_;

    open (IN, "$filename") || die "Can't open '$filename': $!";
    $/ = undef;
    $data = <IN>;
    $/ = "\n";
    close(IN);

    return $data;
}

### writeFile( $filename, $fileinput )
#
# writes $fileinput to $filename
#

sub writeFile
{
    my ($filename, $fileinput) = @_;

    #
    # test for a valid $filename
    #

    if ( !defined($filename) || (length($filename) == 0) )
    {
        die "Filename is undefined";
    }

    if ( ( -e $filename ) && ( ! -w $filename ) )
    {
        die "Cannot write to filename '$filename'";
    }

    #
    # write the output to $filename
    #

    open(OUT, ">$filename");
    print OUT $fileinput;
    close(OUT);
}

### detValidInterpreters( $pathdirs, $version )
#
# out of a list of directories in a user's path, find a perl interpreter that supports
# a perl syntax from $version.
#

sub detValidInterpreters
{
    my ($pathdirs, $version) = @_;
    my (@correct, $ptp);

    for my $d (@$pathdirs)
    {
        $possible = "$d/perl";
        if ( testInterp($possible, $version) )
        {
            $ptp = $possible;
            last;
        }
    }

    return $ptp;
}

### testInterp( $possible, $version )
#
# given a possible interpreter, test it to see if it supports our minimum version
# requirement
#

sub testInterp
{
    my ($possible, $version) = @_;

    if ( -e $possible && -f $possible && -x $possible )
    {
        $rc = system("$possible gpt-perl-version $version");
        $rc = $rc / 256;
        if ($rc == 0)
        {
            return 1;
        }
    }

    return 0;
}

### setmode( $modearg )
#
# based on the mode passed into us, set our program's $mode accordingly
#

sub setmode
{
    my ($modearg) = @_;

    if ( !defined($mode) )
    {
        $mode = $modearg;
    }
    else
    {
        die("Can't run in more than one mode at a time!\n");
    }
}

### action( $command, $dir )
#
# perform some command and inform the user
#

sub action
{
    my ($command, $dir) = @_;
    my $pwd;
    if (defined $dir) {
        $pwd = cwd();
        inform("[ Changing to $dir ]");
        chdir($dir);
    }

    # Log the step
    inform($command);

    # Perform the step
    my $result = system("$command 2>&1");

    if ($result or $?)
    {
        # results are bad print them out.
        die("ERROR: Command failed\n");
    }

    if (defined $dir)
    {
        inform("[ Changing to $pwd ]");
        chdir($pwd);
    }
}

### inform( $content, $override )
#
# inform the user of an event
#

sub inform
{
    my ($content, $override) = @_;

    if ( $verbose or defined($override) )
    {
        print "$content\n";
    }
}

__END__

=head1 NAME

B<gpt-translate-interpreter> - Alters the paths to the Perl interpreter embedded within GPT's scripts

=head1 SYNOPSIS

B<gpt-translate-interpreter> [options]

  Help-Related Options:
    --help      brief help message
    --man       full documentation

=head1 OPTIONS

=over 8

=item B<--dir=<dir_name>>

Specify an alternate GPT installation for the script to scan.

=item B<--perl=<path-to-perl>>

Specify the perl interpreter to use for the scripts.

=item B<--force>

Ignore this script's warnings and substitute the user-specified interpreter regardless.

=head2 AUXILIARY MODES

=item B<--version>

=item B<--info>

=item B<--help>

Print a brief help message and exit.

=item B<--man>

Print the manual page and exit.

=back

=head1 DESCRIPTION

B<gpt-translate-interpreter> is designed to alter the paths to the Perl interpreter embedded
within each GPT script used for invocation.  If no specific directory is passed to
the script via the '--dir' flag, then the script will look for a valid GPT installation
in the value of the GPT_LOCATION or GLOBUS_LOCATION variables, respectively.

The script seeks a valid interpreter by looking for Perl binaries ('perl') in your
path serially.  If you wish, you can specify an interpreter to use on the command-line
via the '--perl' flag.  The script will test this interpreter, but if you want to use
it regardless of whether the interpreter passes the test, invoke this script also with
the '--force' flag.

=head1 EXAMPLES

=head2 Invoking Using Default Values

To let the script find a valid Perl interpreter in your PATH, altering the files in
your GPT_LOCATION or GLOBUS_LOCATION environment variable:

B<gpt-translate-interpreter>

=head2 The Unnamed Example

To alter the GPT files in /home/myhome/gpt using /home/myhome/bin/per1 as your Perl
interpreter, and ignoring the test of the interpreter:

B<gpt-translate-interpreter --dir=/home/myhome/gpt --perl=/home/myhome/bin/perl --force>

=head1 AUTHOR

Written by Chase Phillips.

=cut
