###
###  Copyright 2000-2004 University of Illinois Board of Trustees
###  All rights reserved. 
###
###  PSGConf::Action::PackageManager::FreeBSD - FreeBSD pkg action type for psgconf
###
###  Campus Information Technologies and Educational Services
###  University of Illinois at Urbana-Champaign
###


package PSGConf::Action::PackageManager::FreeBSD;

use strict;

use PSGConf::Action::PackageManager;
use PSGConf::Data::String;
use PSGConf::Util;

use version;

our @ISA = qw(PSGConf::Action::PackageManager);

###############################################################################
###  configuration constructor
###############################################################################

sub conf
{
     my ($class, $psgconf) = @_;

     $psgconf->register_data(
          pkg_cmd_path     => PSGConf::Data::String->new(
                              value => "/usr/sbin/"
                         ),
          pkg_db_dir     => PSGConf::Data::String->new(
                              value => "/var/db/pkg/"
                         )
	);
}

###############################################################################
###  pkg_get_installed() method
###############################################################################

sub pkg_get_installed
{
	my ($self, $psgconf) = @_;
	my (%pkg_installed_list);
	my ($cmd, $pkg, $ver);
	local *FP;

	$cmd = $psgconf->data_obj('pkg_cmd_path')->get() . 'pkg_info';

	if (open (FP, "$cmd |")) {
		while (<FP>) {
			chomp;
			s/ .*$//;

			($pkg) = $self->Parse($_);
			$ver = $_; $ver =~ s/^\Q${pkg}\E$self->{seperator}->[0]//;
          	push (@{$pkg_installed_list{$pkg}}, $ver) 
				if ( length $pkg && length $ver );

		}
		close FP;
	} else {
          warn "\t!!! pkg_info failed: $!\n";
	}
	
	return \%pkg_installed_list;
}

sub _extract_deps
{
     my ($self, @info) = @_;
     my (@pkgs);

     grep (/\@pkgdep (.*)$/o && (push @pkgs, $1), @info);
     return @pkgs;
}

###############################################################################
###  pkg_get_installed_dependencies() method
###############################################################################
          
sub pkg_get_installed_dependencies
{
     my ($self, $psgconf, $pkg) = @_;
	my (@pkgs, $cmd);
	local *FP;

	$cmd = $psgconf->data_obj('pkg_cmd_path')->get() . 'pkg_info -rq';
	$cmd .= ' ' . $pkg;

	if (open (FP, "$cmd |")) {
		@pkgs = $self->_extract_deps(<FP>);
		close FP;
	} else {
		warn "\t!!! Could not get dependencies for ($pkg), pkg_info failed: $!\n"; 
	}

	return @pkgs;
}

###############################################################################
###  pkg_remove() method
###############################################################################
          
sub pkg_remove
{    
     my ($self, $psgconf, $pkg, $force) = @_;
     my ($err, $cmd);

     $cmd = $psgconf->data_obj('pkg_cmd_path')->get() . 'pkg_delete ';
     $cmd .= '-v '
          if ($psgconf->{verbose});
     $cmd .= '-f '
          if ($force);
     $cmd .= $pkg;

	$err=&PSGConf::Util::RunCommand($cmd);

     print "\n"
          if ($psgconf->{verbose});

     return $err;
}    
          
###############################################################################
###  ComparePkgs() method
###############################################################################

sub _compare_fields {
	my ($pa, $pb) = @_;
	my ($va, $vb);

	$va = new version 'v' . &PSGConf::Action::PackageManager::AlphaBeta($pa);
	$vb = new version 'v' . &PSGConf::Action::PackageManager::AlphaBeta($pb);

	return $va->numify <=> $vb->numify;
}

sub ComparePkgs {
	my ($self, $pkga, $pkgb) = @_;
	my (@pa, @pb, $res);

	###
	### Parse the package name
	###
	@pa = $self->Parse($pkga);
	@pb = $self->Parse($pkgb);

	###
	### FreeBSD package versions are of the format pkg-<VER>(_<REV>)(,<EPOCH>)
	### WHere EPOCH and REV are optional, but EPOCH takes precidence over
	### everything else, hence the special ComparePkgs routine.
	return $res
		if (($res = &_compare_fields ($pa[3], $pb[3])));

	### Now compare the <VER> field.
	return $res
		if (($res = &_compare_fields ($pa[1], $pb[1])));

	### And lastly compare the <REV> field.
	return &_compare_fields ($pa[2], $pb[2]);
}
          

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

1;

__END__

=head1 NAME

PSGConf::Action::PackageManager::FreeBSD - install FreeBSD packages

=head1 SYNOPSIS

  use PSGConf::Action::PackageManager::FreeBSD;

  $psgconf->register_actions(
		PSGConf::Action::PackageManager::FreeBSD->new(
			'quiet'		=> 1
		),
		...
	);

=head1 DESCRIPTION

The B<PSGConf::Action::PackageManager::FreeBSD> module provides a B<PSGConf>
action class for updating FreeBSD packages.

The B<PSGConf::Action::PackageManager::FreeBSD> class is derived from the
B<PSGConf::Action::PackageManager> class, but it defines/overrides the 
following methods:

=over 4

=item I<pkg_get_installed()>

A method that will assign values to the I<pkg_installed_list>, which
will be all the packages currently installed.  The I<pkg_installed_list>
is a reference to a hash of arrays.  The array is sorted to have
versions in ascending order.  Called from the 
B<PSGConf::Action::PackageManager::check()> method.

=item I<pkg_remove($pkg, $force)>

A method that will remove $pkg from the system, and may have to force
the removal, depending on the value of $force, which will be a
B<PSGConf::Data::Boolean>.  Returns 0 for a successfull install,
non-zero for a failure.  Called from 
B<PSGConf::Action::PackageManager::do()> method.

=item I<ComparePkgs($pkga, $pkgb)>

A method that compares I<$pkga> with I<$pkgb> and returns less than,
equal to or greater than zero if I<$pkga> is less than, equal to or
greater than I<$pkgb>.  This overloaded method is needed because
of the special order that FreeBSD Packages and Ports have in their
package naming.

=back


The constructor also registers the following data objects:

=over 4

=item I<pkg_cmd_path>

A B<PSGConf::Data::String> object that determines where the pkg_*
commands are located.  The default is I</usr/sbin>.

=item I<pkg_db_dir>

A B<PSGConf::Data::String> object that determines where the pkg database
is.  Defaults to F</var/db/pkg>.

=back


=head1 SEE ALSO

L<perl>

L<PSGConf>

L<PSGConf::Action>

L<PSGConf::Action::PackageManager>

L<PSGConf::Data::String>

L<PSGConf::Util>

L<version>

C<CE<lt>pkg_version(1)E<gt>>

=cut



syntax highlighted by Code2HTML, v. 0.9.1