###
###  Copyright 2000-2007 University of Illinois Board of Trustees
###  All rights reserved. 
###
###  Packages.pm - Packages module for psgconf
###
###  Campus Information Technologies and Educational Services
###  University of Illinois at Urbana-Champaign
###


package PSGConf::Control::Packages;

use strict;

use PSGConf::Data::Boolean;
use PSGConf::Data::Hash;
use PSGConf::Data::List;
use PSGConf::Data::Integer;


###############################################################################
###  Utility function to be called from other Control modules
###############################################################################

require Exporter;
our @ISA = qw (Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw( _add_pkgs) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} });
our @EXPORT = qw();

sub _add_pkgs
{
	my ($self, $psgconf) = @_;

	if (!exists($self->{enable}) || $self->{enable} eq '' ||
		!exists($self->{packages}) || $self->{packages} eq '') {
		warn "\t!!!Control::Packages->_add_pkgs(): no enable/packages attribute\n";
		return;
	}

	### If we have a Boolean type call equals(), if a List/Hash, call count()
     return
		if ( ( $psgconf->data_obj($self->{enable})->can('equals') &&
			$psgconf->data_obj($self->{enable})->equals('false')) ||
			( $psgconf->data_obj($self->{enable})->can('count') &&
			! $psgconf->data_obj($self->{enable})->count()) ||
			! $psgconf->data_obj($self->{enable})->get());

     map {
          $psgconf->data_obj('pkg_install_list')->insert(
			{ $_ => undef }
		) if (! defined $psgconf->data_obj('pkg_install_list')->find($_));
     } @{$psgconf->data_obj($self->{packages})->get()};
}


###############################################################################
###  constructor
###############################################################################

sub new
{
	my ($class, $psgconf, @args) = @_;
	my ($self, $arg, $opt, $value);

	$self = {};
	bless($self, $class);

     $self->{name} = 'pkg';
	$self->{enable} = $self->{name} . '_enable';

	foreach $arg (@args)
	{
		($opt, $value) = split(/=/, $arg);

		if ($opt eq 'PackageManager')
		{
			$self->{pkg_action} = $value;
			next;
		}

		die "PSGConf::Control::Packages: unknown option '$opt'\n";
	}

	$self->{pkg_action} = 'PSGConf::Action::PackageManager'
		if (!defined($self->{pkg_action}));

	eval "use $self->{pkg_action}";
	die "PSGConf::Control::Packages: cannot load PackageManager '$self->{pkg_action}': $@\n"
		if ($@);

	$psgconf->register_data(
		pkg_enable	=> PSGConf::Data::Boolean->new(
						value => 'true'
					),
		pkg_default_versions	=> PSGConf::Data::Hash->new(
						value_optional => 1
					),
		pkg_install_list	=> PSGConf::Data::Hash->new(
						value_optional => 1
					),
		pkg_warn_unselected	=> PSGConf::Data::Boolean->new(
						value => 'false'
					),
		pkg_seperator		=> PSGConf::Data::List->new(),
		pkg_seperator_regex	=> PSGConf::Data::List->new(),
		pkg_remove_unselected	=> PSGConf::Data::Boolean->new(
						value => 'false'
					),
		pkg_number_of_versions => PSGConf::Data::Integer->new(
						value => 0
					)
	);

	$psgconf->register_policy($self,
		package_default_versions	=> '_policy_default_versions'
	);

	###
	### Enable package specific directives and policies
	###
	$self->{pkg_action}->conf($psgconf)
		if ( $self->{pkg_action}->can('conf') );

	return $self;
}


###############################################################################
###  policy methods
###############################################################################

sub _policy_default_versions
{
	my ($self, $psgconf) = @_;
	my ($pkg, $install_list, $default_list);

	$install_list = $psgconf->data_obj('pkg_install_list')->get();
	$default_list = $psgconf->data_obj('pkg_default_versions')->get();

	foreach $pkg (keys %$install_list)
	{
		$install_list->{$pkg} = $default_list->{$pkg}
			if (!defined($install_list->{$pkg})
			    && exists($default_list->{$pkg}));
	}
}


###############################################################################
###  decide() method
###############################################################################

sub decide
{
	my ($self, $psgconf) = @_;
	my ($name);

	return
		if ( !$psgconf->{update_pkgs}
			|| $psgconf->data_obj('pkg_enable')->equals('false') );

	$name = $self->{pkg_action};
	$name =~ s/.*:://g;

	$psgconf->register_actions(
		$self->{pkg_action}->new(
			name		=> $name . ' Packages',
			quiet		=> 1,
			seperator	=> $psgconf->data_obj('pkg_seperator')->get(),
			sep_regex	=> $psgconf->data_obj('pkg_seperator_regex')->get(),
			install_list	=> $psgconf->data_obj('pkg_install_list')->get(),
			warn_unselected	=> $psgconf->data_obj('pkg_warn_unselected')->get(),
			remove_unselected	=> $psgconf->data_obj('pkg_remove_unselected')->get(),
			number_of_versions	=> $psgconf->data_obj('pkg_number_of_versions')->get()
		)
	);
}


###############################################################################
###  documentation
###############################################################################

1;

__END__

=head1 NAME

PSGConf::Control::Packages - psgconf control class for installing software

=head1 SYNOPSIS

In F<psgconf_modules>:

  Control PSGConf::Control::Packages PackageManager=PSGConf::Action::PackageManager::Encap

=head1 DESCRIPTION

The B<PSGConf::Control::Packages> module provides a B<psgconf> control
object for controlling what software packages are installed on the system.
It supports the following methods:

=over 4

=item new()

The constructor.  Its parameter is a reference to the B<PSGConf>
object.

The constructor processes the arguments specified in the
F<psgconf_modules> file.  The only supported argument is
C<PackageManager>, which specifies the class of the Action object that
will be instantiated to update the system's packages.  This allows for
the use of different Action objects to support different package
management systems.  Note that the C<PackageManager> argument is
mandatory.

The constructor also registers the following data objects:

=over 4

=item I<pkg_enable>

A B<PSGConf::Data::Boolean> object that determines whether packages
should be processed by B<psgconf>.  The default is true.

=item I<pkg_default_versions>

A B<PSGConf::Data::Hash> object that sets the default version for each
package.  The hash key is the name of the package, and the value is the
version to install.  If no version is listed, the latest version
available will be installed.

This allows the administrator to define what version of a
package would be used without actually determining if the package should
be installed.  A different control module may then request the package
without worrying about what specific version it should use.

=item I<pkg_install_list>

A B<PSGConf::Data::Hash> object that sets the list of packages to be
installed.  The hash key is the name of the package, and the value is
the package version.  If the value is not defined, the version will come
from the I<pkg_default_versions> object.

=item I<pkg_warn_unselected>

A B<PSGConf::Data::Boolean> object that determines whether warnings
should be printed when packages are present on the system that are not
listed in the I<pkg_install_list> object.

=item I<pkg_remove_unselected>

A B<PSGConf::Data::Boolean> object that determines whether packages
should be removed when they are not listed in the I<pkg_install_list>
object.

=item I<pkg_seperator>

A B<PSGConf::Data::List> object that determines what value the 
seperator characters are between a package name and it's version,
release, revision or epoch.  Default is I<[ '-' ]>.

=item I<pkg_seperator_regex>

A B<PSGConf::Data::List> object that determines what a correct value
for the version, release, revision or epoch is in a package name.

=item I<pkg_number_of_versions>

A B<PSGConf::Data::Integer> object that determines how many versions of
a package we can have installed before a warning is printed.  The default
is 0, which means do not print any warnings.  If the value is 1, that
has special meaning that the Package Management system cannot handle
multiple versions of packages installed at the same time, and that the
old package will be removed before an install is attempted.

=back

It also registers the following policy methods:

=over 4

=item B<package_default_versions>

Sets the values of the hash contained in the I<pkg_install_list> Data
object to those from the hash contained in the I<pkg_default_versions>
Data object.

=back

=item decide()

The decide() method registers an Action object to perform the requested
package management tasks based on the value of the C<PackageManager>
argument in the F<psgconf_modules> file.

=back

=head1 SEE ALSO

L<perl>

L<PSGConf>

L<PSGConf::Control::ShellStartupFiles>

L<PSGConf::Data::Boolean>

L<PSGConf::Data::List>

L<PSGConf::Data::Hash>

L<PSGConf::Data::Integer>

L<psgconf-intro>

=cut



syntax highlighted by Code2HTML, v. 0.9.1