# -*- perl -*-
# vim: syntax=perl

# $Id: listincludes.plm,v 1.9 2005/02/21 20:56:31 thomas Exp $



# Generate a description file from an existing system

# $Log: listincludes.plm,v $
# Revision 1.9  2005/02/21 20:56:31  thomas
# Help out the stinking pile known as help
#
# Revision 1.8  2004/10/13 16:01:09  thomas
# db version
#
# Revision 1.7  2004/07/22 19:12:10  thomas
# use global help function
#
# Revision 1.6  2004/04/12 16:29:43  thomas
# sort data before printing
#
# Revision 1.5  2004/04/06 21:19:26  thomas
# doc update
#
# Revision 1.4  2004/03/22 17:38:54  thomas
# Include tree search and management
#
# Revision 1.3  2004/03/17 21:19:21  thomas
# Support variables in includes
#
# Revision 1.2  2004/03/05 15:14:03  thomas
# misc updates
#
# Revision 1.1  2004/02/10 16:40:11  thomas
# pre-0.1.5 fork
#
# Revision 1.1.1.1  2003/12/02 14:47:34  thomas
# Initial version before export to 0.1.1
#

=head1 NAME

What::Command::listincludes - list files included in configurations

=head1 SYNOPSIS

what listincludes [--help] [--live] [--allhosts] I<host...>

what listincludes [--file|-f] I<file-name>

what listincludes [--basename|-b] I<base-name>

what listincludes [--name|-n] I<include-name>

=head1 DESCRIPTION

In normal usage, B<listincludes> will query the B<What>
include database for information about a list of hosts, or a
combination of included file names, target names, and/or target base
names.

It can also attempt to load a given xml file and print the list of
included files.

=over 4

=item --help

Print out help information and exit.

=item --live

Find and read the list of B<host>s and print out the include
information, rather than querying the database.

=back

The following options only pertain to querying the database (B<--live> is not present).

=over 4

=item --allhosts

Print information for all hosts in the include database

=item --file|-f I<file-name>

Print a list of hosts for which an include directive resolved to the
exact B<file-name>.

=item --basename|-b I<base-name>

Print a list of hosts for which the B<name> attribute of an include
directive contained the given B<base-name>.

=item --name|-n I<include-name>

Print a list of hosts for which the B<name> attribute of an include
directive exactly matched the given B<include-name>.

=back

=head1 SEE ALSO

What::Command::buildincludedb

What::DepDB

=cut

package What::Command::listincludes;

use strict;
use Getopt::Long;
use Sys::Hostname;
use Data::Dumper;
use XML::Simple;
use Pod::Usage;

use What::DepDB;

use base qw(What::Command);

our $helpmsg = "list files included in configurations";

###############################################################################

sub main {
  my $self = shift;
  my $what = shift;
  local (@ARGV) = @_;

  my ($res);
  my $args = {
	      help => 0,
	      me   => 0,
	      maxdepth => -1,
	      live     => 0,
	      allhosts => 0,
	     };
  my $help = 0;
  my $inctree = {};
  my ($host);
  my @cmds = ('file', 'basename', 'name');

  Getopt::Long::Configure ("bundling");
  if (!($res = GetOptions (
                           'help|h',     \$help,
			   'me',         \$args->{me},
			   'maxdepth=i', \$args->{maxdepth},
			   'live',       \$args->{live},
			   'allhosts',   \$args->{allhosts},
			   # These next enable alternate search indicies
			   'file|f=s',   \$args->{file},
			   'basename|b=s',   \$args->{basename},
			   'name|n=s',   \$args->{name},
                          ))) {
    $what->err ("Bad option passed to listincludes command!\n");
    return 0;
  }

  $help and return $self->help;

  foreach (@cmds) {
    defined ($args->{$_}) and return listindex ($args, $_);
  }
  $args->{live} and return listlive ($what, $args, @ARGV);
  return listdb ($what, $args, @ARGV);
}

sub listlive {
  my $what = shift;
  my $args = shift;
  my @hosts = @_;

  my ($dh, $host, $res, $inctree, $maxdepth, @depdata);

  my $default_section = $what->find_section ('default', 1);

  if ($args->{me}) {
    my $hostname = hostname;
    $res = $default_section->include ($what,
				      $inctree,
				      $maxdepth,
				      {},
				      $hostname);
    $res or $res = $default_section->include ($what,
					      $inctree,
					      $maxdepth,
					      {},
					      'default');
    if (!$res) {
      $what->err("Can't find valid config file for host $hostname!\n");
      exit 1;
    }
    print_include_tree ($inctree);
  } else {
    if($args->{allhosts}) {
      opendir $dh, "/s/what-0.1.31/xml/csdb" or die "Couldn't list the hosts dir";
      my @hosts = sort (map { s/\.xml$//;  $_; } grep { /\.xml$/ } readdir $dh);
      closedir $dh;
    }
    foreach $host (@hosts) {
      delete $what->{sections};
      $default_section = $what->find_section ('default', 1);
      $default_section->include ($what,
				 $inctree,
				 $maxdepth,
				 {},
				 $host);
      print_include_tree ($inctree);
    }
  }
}


sub listdb {
  my $what = shift;
  my $args = shift;
  my @hosts = @_;

  my ($dep, $host, $h1, $data, $depdata);
  if (!defined ($dep = new What::DepDB)) {
    print STDERR "Failed to open dependency database!\n";
    return -1;
  }

  if ($args->{me}) {
    my $hostname = hostname;
    if (!defined ($data = $dep->find ($hostname))) {
      print STDERR "Failed to look up $hostname\n";
      ($hostname) = gethostbyname($hostname);
      if (!defined ($data = $dep->find ($hostname))) {
	print STDERR "Failed to look up $hostname\n";
	chomp (my $sys = `/s/what-0.1.31/depend/sys`);
	$hostname = "default.$sys";
	if (!defined ($data = $dep->find ($hostname))) {
	  print STDERR "Failed to look up $hostname.  Giving up.\n";
	  return -1;
	}
      }
    }
    print_depdata ($hostname, @$data);
  } else {
    if ($args->{allhosts}) {
      @hosts = $dep->find;
    }
    foreach $host (sort @hosts) {
      $depdata = $dep->find ($host);
      if (defined ($depdata) && scalar (@$depdata)) {
	print_depdata ($host, @$depdata);
      } else {
	# Try fqdn
	($h1) = gethostbyname ($host);
	if (defined ($h1) && ($h1 ne $host)) {
	  $depdata = $dep->find ($h1);
	  if (defined ($depdata) && scalar (@$depdata)) {
	    print_depdata ($h1, @$depdata);
	  }
	}
      }
    }
  }
}


sub print_include_tree {
  my $inctree = shift;

  my $host = ($inctree->{kids})[0];
  my @depdata = What::DepDB::inc_2_dep ($inctree);
  print_depdata ($host, @depdata);

}

sub print_depdata {
  my $host = shift;
  my @depdata = @_;

  print "Object $host includes:\n";
  foreach (sort @depdata) {
    printf "%-24s FROM_FILE %s\n",  $_->{name}, $_->{file};
  }
  print "\n";
}


sub get_includes {
  my $hash = shift;
  my $tree = shift;

  exists ($tree->{kids}) or return;
  foreach (sort keys %{$tree->{kids}}) {
    $hash->{$_} = $tree->{kids}->{$_}->{filename};
    get_includes ($hash, $tree->{kids}->{$_});
  }
}


sub listindex {
  my $args = shift;
  my $index = shift;

  my $dep;

  if (!defined ($dep = new What::DepDB)) {
    print STDERR "Failed to open dependency database!\n";
    return -1;
  }
  # print "Hosts matching $index = $args->{$index}:\n";
  my $count=0;
  my @hosts = sort $dep->find_index ($index, $args->{$index});
  print join ("\n", @hosts, '');
  return scalar (@hosts);
}


###############################################################################

1;
