#! perl

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

#
# Do a perl check for version >= 5.005.  See 'gpt-translate-interpreter' should you
# need to alter the invocation path to a valid perl interpreter in the GPT front-end
# programs.
#

if ( ! ( defined eval "require 5.005" ) )
{
    die "GPT requires at least Perl version 5.005";
}


my $gpath = $ENV{GPT_LOCATION};

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

}

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

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

system("$gpath/sbin/gpt_version") == 0
         or die "GPT died due to Version mismatch.  Check PATH and GPT_LOCATION\n" ;

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

require Pod::Usage;

my $tmpdir="/tmp";
my ($verbose, $location, $version, $debug, $force, $help, $loose, $man, $noaction);


GetOptions( 'force'=> \$force, 
            'help|?' => \$help, 
            'man' => \$man,
            'verbose' => \$verbose, 
            'debug' => \$debug, 
            'tmpdir=s'=> \$tmpdir,
            'location=s'=> \$location,
            'installdir=s'=> \$location,
            'noaction|n' => \$noaction,
            'version' => \$version)
  or Pod::Usage::pod2usage(0);

Pod::Usage::pod2usage(0) if $help;
Pod::Usage::pod2usage(-verbose => 2) if $man;


require Grid::GPT::GPTIdentity;
Grid::GPT::GPTIdentity::print_gpt_version() if defined $version;

my @files = @ARGV;

Pod::Usage::pod2usage(-verbose => 0, 
                      -exitval => 1,
                      -output =>  \*STDERR,
                      -message => "ERROR: please specify at least one file to install\n") 
  if @files == 0;

require Grid::GPT::Algorithms;
require Grid::GPT::PkgMngmt;
require Grid::GPT::Locations;
require Grid::GPT::PkgMngmt::Inform;

my $log = new Grid::GPT::PkgMngmt::Inform(verbose => $verbose, 
                                          debug => $debug);

my $locations = new Grid::GPT::Locations(
                                         installdir => $location,
                                         tmpdir => $tmpdir,
                                        );

$locations->create_dirs(mode => 'tmp');


my $checks = 
  new Grid::GPT::Algorithms(
                            log => $log,
                            force => $force,
                            locations => $locations,
                           );

my $pkgmngr = new Grid::GPT::PkgMngmt(
                                      log => $log,
                                      locations => $locations,
                                     );

my $results = $checks->update(files => \@files);

if (! defined $results) {
  $locations->cleantmp();
  die $checks->{'error_msg'} if ! defined $results;
}

if (defined $noaction) {

  print "The following bundles would be removed\n" if @{$results->{'removed_bundles'}};

  for my $b (@{$results->{'removed_bundles'}}) {
    print "\t$b->{'Name'} ver: ", $b->version_label(), "\n";
  }

  print "The following bundles would be installed\n" if @{$results->{'new_bundles'}};

  for my $b (@{$results->{'new_bundles'}}) {
    print "\t$b->{'Name'} ver: ", $b->version_label(), "\n";
  }

  print "The following packages would be removed\n" if @{$results->{'removed_packages'}};

  for my $p (@{$results->{'removed_packages'}}) {
    print "\t",$p->label()," ver: ", 
      $p->{'depnode'}->{'Version'}->label(), "\n";
  }

  print "The following packages would be installed\n" if @{$results->{'new_packages'}};

  for my $p (@{$results->{'new_packages'}}) {
    print "\t",$p->label()," ver: ", 
      $p->{'depnode'}->{'Version'}->label(), "\n";
  }


  $locations->cleantmp();
  exit 0;
}

$locations->create_dirs(mode => 'install');

$pkgmngr->remove(bndls => $results->{'removed_bundles'}, 
                 pkgs => $results->{'removed_packages'}
                );

my $ret = $pkgmngr->install(bndls => $results->{'new_bundles'}, 
                             pkgs => $results->{'new_packages'});
if( !($ret) )
{
  print "ERROR: problem with pkgmngr->install()\n";
  clean_n_exit();
} 

clean_n_exit();


sub clean_n_exit
{
print "Cleaning up temp locations\n";
  $locations->cleantmp();
  exit 0;
}

=head1 NAME

B<gpt-install> - Installs GPT packages. 

=head1 SYNOPSIS

B<gpt-install> [options] [packages or bundles]

  Options:
     -verbose              Print copious output
     -help                 Print usage
     -man                  Print man page.
     -version              Print GPT version.
     -force                Replace package no matter what.
     -loose                Replace a broader range of packages.
     -installdir=PATH      Override $GLOBUS_LOCATION.
     -tmpdir=PATH          Path to tmp disk space
     [packages or bundles] List of binary packages and bundles to install.

=head1 DESCRIPTION

B<gpt-install> takes a GPT described package or bundle and installs
it. The program can install either RPM's or GPT packages.

=head1 OPTIONS

=over 8

=item B<-force>

forces all action to be taken, regardless of state.

=item B<-tmpdir>

Place to unpack bundles.

=item B<-installdir>

Directory to which files shall be written. Default is $GLOBUS_LOCATION

=item B<-loose>

pgm packages can replace a pgm_static package (and vice versa) or a
pgm package with a different flavor.

=item B<-help>

Print a brief help message and exits.

=item B<-man>

Prints the manual page and exits.

=item B<-version>

Prints the version of GPT and exits.

=back

=head1 EXAMPLES

For the command: 

  gpt-install foo-2.1-gcc32-pgm.tar.gz

  foo-1.1-gcc32-pgm will be replaced.
  foo-2.2-gcc32-pgm will B<not> be replaced. It is newer.
  foo-1.1-vendorcc32-pgm will B<not> be replaced. Wrong flavor.
  foo-1.1-gcc32-pgm_static will B<not> be replaced. Wrong package type
  foo-2.2-gcc32-pgm_static will B<not> be replaced. Wrong package type

For the command: 

  gpt-install -force foo-2.1-gcc32-pgm.tar.gz

  foo-1.1-gcc32-pgm will be replaced.
  foo-2.2-gcc32-pgm will be replaced.
  foo-1.1-vendorcc32-pgm will B<not> be replaced. Wrong flavor
  foo-1.1-gcc32-pgm_static will B<not> be replaced. Wrong package type
  foo-2.2-gcc32-pgm_static will B<not> be replaced. Wrong package type

For the command: 

  gpt-install -loose foo-2.1-gcc32-pgm.tar.gz

  foo-1.1-gcc32-pgm will be replaced.
  foo-2.2-gcc32-pgm will B<not> be replaced. It is newer.
  foo-1.1-vendorcc32-pgm will be replaced.
  foo-1.1-gcc32-pgm_static will be replaced.
  foo-2.2-gcc32-pgm_static will B<not> be replaced. It is newer.

For the command:

  gpt-install -force -loose foo-2.1-gcc32-pgm.tar.gz

  foo-1.1-gcc32-pgm will be replaced.
  foo-2.2-gcc32-pgm will be replaced.
  foo-1.1-vendorcc32-pgm will be replaced.
  foo-1.1-gcc32-pgm_static will be replaced.
  foo-2.2-gcc32-pgm_static will be replaced.


=head1 BUGS

B<gpt-install> currently does not honor static build numbers.  Instead it
will replace any pgm_static package that is the same version or older.  For
example:

  gpt-install -force foo-2.1-2-gcc32-pgm_static.tar.gz

  foo-1.1-5-gcc32-pgm_static will be replaced.
  foo-2.1-1-gcc32-pgm_static will be replaced.
  foo-2.1-5-gcc32-pgm_static will be replaced.
  foo-2.2-1-gcc32-pgm_static will not be replaced.
  foo-2.1-gcc32-pgm will not be replaced.



=head1 SEE ALSO

gpt-uninstall(1) gpt-query(1) gpt-verify(1)

=head1 AUTHOR

Michael Bletzinger E<lt>mbletzin.ncsa.uiuc.eduE<gt> and Eric Blau
E<lt>eblau.ncsa.uiuc.eduE<gt>

=cut
