#! perl

use strict;
use Config;
use Cwd;

my $gpath;
my $version;

#
# 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";
}

#
# dig the globus and gpt paths out of the user's environment variables
#

my $gpt_path = $ENV{GPT_LOCATION};
my $globus_path = $ENV{GLOBUS_LOCATION};

if ( !defined($gpt_path) && !defined($globus_path) )
{
    die("GPT_LOCATION needs to be set before running this script");
}

if ( defined($gpt_path) )
{
    $gpath = $gpt_path;
}

if ( defined($globus_path) && !defined($gpath) )
{
    $gpath = $globus_path;
}

@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");
}

#
# standard includes
#

use Getopt::Long;


require Pod::Usage;
require Grid::GPT::V1::Bundle;

#
# argument specification
#


my %queryargs = ();
# sub pod2usage {
#   print "gpt-query [-name=Name -flavor=Flavor -pkgtype=Type --help -sdk -deps=<run|sdk>] [-file=Name] [pkgname-flavor-pkgtype+] \n";
#   exit shift;
# }

my ($deps, $help, $man, $lookupfile, $bundle, $whatBundles, $location, 
    $verBndl, $bndlPack, $bndl_style, $tmpdir);

GetOptions(
		
		'name|pkgname=s' =>
                sub
                {
                    my ($optname, $optval) = @_;


                   if ( defined($optval) && ( length($optval) > 0 ) )
                    {
                        $queryargs{'pkgname'} = $optval;
                    }
		  
                },
            'flavor|flavour=s' =>
                sub
                {
                    my ($optname, $optval) = @_;

                    if ( defined($optval) && ( length($optval) > 0 ) )
                    {
                        $queryargs{'flavor'} = $optval;
                    }
		   
                },
            'type|pkgtype=s' =>
                sub
                {
                    my ($optname, $optval) = @_;

                   if ( defined($optval) && ( length($optval) > 0 ) )
                    {
                        $queryargs{'pkgtype'} = $optval;
                    }
		 
                },

           'file=s'            => \$lookupfile,
           'help|?'            => \$help,
           'man'               => \$man,
           'deps=s'            => \$deps,
           'version'           => \$version,
           'bundle'            => \$bundle,
           'what-bundles'      => \$whatBundles,
           'location=s'        => \$location,
           'tmpdir=s'        => \$tmpdir,
           'verify-bundle=s'   => \$verBndl,
           'bundle-style'      => \$bndl_style,
           'bundle-packages=s' => \$bndlPack
          )
  or Pod::Usage::pod2usage(0);

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

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

# require Grid::GPT::Query;
require Grid::GPT::Installation;
require Grid::GPT::PkgFileName;
require Grid::GPT::BundleInstallation;
require Grid::GPT::Locations;

my $locations = new Grid::GPT::Locations(
                                         installdir => $location,
                                         tmpdir => $tmpdir,
                                        );
my $namematch = new Grid::GPT::PkgFileName(
                                           locations => $locations,
                                          );
$locations->create_dirs(mode => 'tmp');

main(\%queryargs, @ARGV);

###print_pkgs($i_pkg)
sub print_pkgs
{
  my ($i_pkg) = @_;
 printf("packages found that matched your query \n");
 for my $i (@$i_pkg)
 {
   if (defined $deps) {
     print $i->printnode(pretty=>1), "\n";
   } else {
     printf("\t");
     print $i->label(full=>1), "\n";
   }
 }
  $locations->cleantmp();
exit;
}

### main( $queryargs )
#
# query the installed base to get the matching packages against the passed query arguments
#

sub main
{
    my ($queryargs, @ARGS) = @_;
    my $installation = 
      new Grid::GPT::Installation( locations      => $locations,
                                   with_filelists => 1 );
  my $bndlinst     = 
    new Grid::GPT::BundleInstallation( locations => $locations );

if( defined( $bundle ) )
{
  my $bndl1 = new Grid::GPT::V1::Bundle( tmpdir => $locations->{'tmpdir'} ); 

  $bndl1->read_bundle_from_tar( file => $ARGS[0] );

  if( defined( $ARGS[1] ) )
  {
    my $bndl2 = new Grid::GPT::V1::Bundle( tmpdir => $locations->{'tmpdir'} ); 

    $bndl2->read_bundle_from_tar( file => $ARGS[1] );
    $bndl1->compare_bundle_2_bundle( bundle => $bndl2 );
  }
  else
  {
    $bndl1->compare_bundle_2_installation( inst => $installation );
  }
  $locations->cleantmp();
  exit;
}

if( defined( $whatBundles ) )
{
  print "System Bundles\n"; 
  for my $b (@{$bndlinst->what_bundles()})
  {
    print "\t$b\n";
  }
  $locations->cleantmp();
 exit;
}

if( defined($verBndl) )
{
  $bndlinst->check_bundle_integrity( bundle => $verBndl, 
                                     inst   => $installation );
}

if( defined($bndlPack) )
{
  my @bp = $bndlinst->list_packages_for_bundle( bundle => $bndlPack );
  
  print "Packages in Bundle $bndlPack:\n";
  for my $p (@bp)
  {
    print "\t$p\n";
  }
  $locations->cleantmp();

  exit;
}

if( defined($bndl_style) )
{
  my $bndl = $bndlinst->find_bundle( bundle => $ARGS[0] );
  if( $bndl->{'BundleVersion'} eq 'EMPTY' || 
      !defined($bndl->{'BundleVersion'}) )
  {
    print "Bundle $bndl->{'Name'} is an old style bundle.\n";
  }
  else
  {
    print "Bundle $bndl->{'Name'} is a new style bundle.\n";
  }
  $locations->cleantmp();
  exit;
}

$globus_path = $locations->{'installdir'};

    if (defined $lookupfile) {
      $lookupfile =~ s!^$globus_path!!;
      $lookupfile =~ s!^([^/])!/$1!;


      if (! -f "$globus_path/$lookupfile") {
  $locations->cleantmp();
        die "$globus_path/$lookupfile does not exist\n";
      }
      my $pkg = $installation->find_file($lookupfile);
      if (defined $pkg) {
        print "$lookupfile is owned by ", $pkg->label(), "\n";
  $locations->cleantmp();
        exit 0;
      } else {
  $locations->cleantmp();
        die "$lookupfile is not owned by anyone\n";
      }
    }


    if (defined $deps) {
      $installation->set_depenv($deps eq 'sdk' ? 'Build' : 'RuntimeandSetup');
    }

    my $installed_pkgs = $installation->query(%$queryargs) if keys %$queryargs or ! @ARGS;

    for my $l (@ARGS)
    {
      my $parsed = $namematch->parse_name($l);
      my $pkgs = $installation->query(
                                      pkgname => $parsed->{'pkgname'},
                                      flavor => $parsed->{'flavor'},
                                      pkgtype => $parsed->{'pkgtype'},
                                     );
      push @$installed_pkgs, @$pkgs;
    }

    my $num = scalar(@$installed_pkgs);

    if ($num == 0)
    {
        printf("No packages were found that matched your query.\n");
  $locations->cleantmp();
        exit;
    }

    if ($num == 1)
    {
        printf("1 package was found in $globus_path that matched your query:\n");
    }
    else
    {
        printf("$num packages were found in $globus_path that matched your query:\n");
    }

    printf("\n");

print_pkgs($installed_pkgs);


}


=head1 NAME

B<gpt-query> - Queries an installation for packages

=head1 SYNOPSIS

gpt-query [-name=Name -flavor=Flavor -pkgtype=Type --help -file=name -man -deps=run|sdk] [pkgname-flavor-pkgtype+]

=head1 DESCRIPTION

B<gpt-query> searches installed packages for matches to the query.
I<Name> is the name of the package. I<Flavor> is the
information about linking and compile options used on package.  
I<Type> is the type of the package. I<?> will alow the use to
access system help.

The user may enter a value for any of the options.  These options
can be used in combination or not at all.  The script will take the
options being used and try to find all matching items.


An alternate form is to use the pkgname-flavor-pkgtype tuples.
Multiple of instances of these tuples can be used in a query.

=head1 OPTIONS

=over 4

=item B<-name=NAME>

 Returns all of the packages matching NAME.

=item B<-flavor=FLAVOR>

Returns all of the packages matching FLAVOR.

=item B<-pkgtype=TYPE>

Returns all of the packages matching TYPE.

=item B<-file=FILE>

Returns the package owning the FILE.  FILE needs to be either an
absolute path or referenced to $GLOBUS_LOCATION.

=item B<-deps=run|sdk>

Returns the runtime or build dependencies of a package.

=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.

=item B<-what-bundles>

Prints a list of the installed bundles. 

=item B<-verify-bundle=BUNDLE>

Takes a bundle defintion and checks to see if it matches the installation.

=item B<-bundle-packages=BUNDLE>

List the packages that belong to the desired bundle.

=item B<-bundle BUNDLE 1 [BUNDLE 2]>

If two bundles are given, the bundles will be compared to one another
for equality.  If only one bundle is given, the bundle will be checked
against the installation.  This command works on tar bundles.

=back

=head1 EXAMPLES

  gpt-query

Returns a listing of all of the installed packages.

  gpt-query -name=foo

Returns all flavors and package types with the name "foo".

 gpt-query foo

Also returns all flavors and package types with the name "foo".

  gpt-query 'foo-*-*'

A third way of typing the same query.  Note the single quotes.

  gpt-query '*-noflavor-*'

List all of the packages with a 'noflavor' build flavor.

  gpt-query -file=libexec/globus-build-env-gcc32.sh

Returns "/libexec/globus-build-env-gcc32.sh is owned by globus_core-gcc32-rtl"

  gpt-query -file=$GLOBUS_LOCATION/libexec/globus-build-env-gcc32.sh

Returns the same.

  gpt-query -file=globus-build-env-gcc32.sh

Returns an error because the path is incorrect.

=head1 OUTPUT

Here is an example output:

   gpt-query '*-noflavor-*'

 4 packages were found in /home/mbletzin/work/install that matched your query:

 packages found that matched your query 
        globus_core-noflavor-data ver: 2.1 cmp id: 2.1.0
        globus_core_setup-noflavor-pgm ver: 2.0 cmp id: 2.0.0
        globus_ssl_utils-noflavor-data ver: 2.1 cmp id: 2.1.0
        kca_setup-noflavor-pgm ver: 3.0.2p1 cmp id: 1.0.0

For each package name, flavor, package type, version, and the
compatibility identifier is return.  The compatibility identifier is
what is used to resolve dependencies.

=head1 SEE ALSO

gpt-install(1) gpt-uninstall(1) gpt-verify(1) gpt-postinstall(1)

=head1 AUTHOR

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

=cut
