###
### Copyright 2000-2007 University of Illinois Board of Trustees
### All rights reserved.
###
### PSGConf::Action::PackageManager::Encap - Encap pkg action type for psgconf
###
###
### Campus Information Technologies and Educational Services
### University of Illinois at Urbana-Champaign
###
package PSGConf::Action::PackageManager::Encap;
use strict;
use PSGConf::Action::PackageManager::FTPArchive;
use PSGConf::Data::String;
use PSGConf::Data::Integer;
use PSGConf::Util;
use File::Path;
use File::Basename;
use Cwd;
our @ISA = qw(PSGConf::Action::PackageManager::FTPArchive);
###############################################################################
### configuration constructor
###############################################################################
sub conf
{
my ($class, $psgconf) = @_;
my ($p) = '-share|-' . $psgconf->data_obj('platform')->get();
### FIXME: An ugly hack to covert back the platform name to
### the ambigous sparc-solarisX tag
$p =~ s/-sun4[^-]-/-sparc-/
if ( $p =~ /-sun4/ );
my ($a) = join ('|', @{$psgconf->{platform_suffixes}});
PSGConf::Action::PackageManager::FTPArchive->conf($psgconf);
$psgconf->register_data(
pkg_encap_dir => PSGConf::Data::String->new(
value => "/usr/local/encap"
),
pkg_epkg_umask => PSGConf::Data::Integer->new(
value => 022
),
pkg_epkg_cmd => PSGConf::Data::String->new(
value => "/usr/local/bin/epkg"
),
pkg_tar_cmd => PSGConf::Data::String->new(
value => "/usr/local/bin/tar"
),
pkg_gzip_cmd => PSGConf::Data::String->new(
value => "/usr/local/bin/gzip"
),
pkg_regex => PSGConf::Data::String->new(
value => "(\-encap($p(\-$a)?))?\.tar\.(Z|gz)"
),
);
}
###############################################################################
### pkg_get_installed() method
###############################################################################
sub pkg_get_installed
{
my ($self, $psgconf) = @_;
my (%pkg_installed_list);
my (@pkgname, $dir, $pkg, $ver);
local *DIR;
if (!opendir(DIR, $psgconf->data_obj('pkg_encap_dir')->get())) {
warn "\t!!! cannot open Encap source directory (" . $psgconf->data_obj('pkg_encap_dir')->get() . "): $!\n";
return undef;
}
map {
my ($pkg) = $self->Parse($_);
my ($ver) = $_; $ver =~ s/^\Q${pkg}\E$self->{seperator}->[0]//;
push (@{$pkg_installed_list{$pkg}}, $ver);
} grep { -d $psgconf->data_obj('pkg_encap_dir')->get() . '/' . $_ && !/^\.\.?$/; } readdir(DIR);
closedir(DIR);
return \%pkg_installed_list;
}
###############################################################################
### pkg_get_latest_version() method
###############################################################################
sub pkg_get_latest_version
{
my ($self, $psgconf, $pkg) = @_;
my ($regex) = "(\Q${pkg}\E\-[^-]+)" . $psgconf->data_obj('pkg_regex')->get();
my ($path, $platform);
###
### Deal with the %p in the path.
###
$platform = $psgconf->data_obj('platform')->get();
### FIXME: An ugly hack to covert back the platform name to
### the ambigous sparc-solarisX tag
$platform =~ s/sun4[^-]-/sparc-/
if ( $platform =~ /^sun4/ );
$path = $psgconf->data_obj('env_vars')->find('ENCAP_UPDATE_PATH');
$path =~ s/%p/$platform/g
if ( $path =~ /%p/ );
return $self->get_latest_version ( $psgconf, $pkg, $path, qr{$regex} );
}
###############################################################################
### pkg_get_dependencies() method
###############################################################################
sub pkg_get_dependencies
{
my ($self, $psgconf, $pkg) = @_;
my (@pkgs, @files, $file, $ftp, $path, $platform);
my ($regex) = "\Q${pkg}\E" . $psgconf->data_obj('pkg_regex')->get();
# First see if the package is already locally installed
if ( -d $psgconf->data_obj('pkg_encap_dir')->get() . '/' . $pkg ) {
@pkgs = &_extract_deps($psgconf, $psgconf->data_obj('pkg_encap_dir')->get(), $pkg);
} else {
###
### Deal with the %p in the path.
###
$path = $psgconf->data_obj('env_vars')->find('ENCAP_UPDATE_PATH');
### FIXME: An ugly hack to covert back the platform name to
### the ambigous sparc-solarisX tag
$platform = $psgconf->data_obj('platform')->get();
$platform =~ s/sun4[^-]-/sparc-/
if ( $platform =~ /^sun4/ );
$path =~ s/%p/$platform/g
if ( $path =~ /%p/ );
# Else find the package on the server
# Need to escape the + and . in the package name, hence \Q and \E
@files = $self->list_files_from_url($psgconf, $path, qr{$regex});
# we should have only found one entry
if ( scalar @files == 1 ) {
# See if we have the encap tarball 'cached'.
$file = &basename ($files[0]);
$file = $self->get_file_from_url($psgconf, $files[0])
if ( ! -f "$psgconf->{tmpdir}/$file" );
if ( -f "$psgconf->{tmpdir}/$file" ) {
&_unpack_encap ($psgconf, $pkg, $file);
@pkgs = &_extract_deps($psgconf, $psgconf->{tmpdir}, $pkg);
# Remove the encapinfo and directory.
my ($dir) = $psgconf->{tmpdir} . '/' . $pkg;
if ( -d $dir ) {
warn "\t!!! unlink('$dir'): $!\n"
if ( $psgconf->{rm_tmpfiles} && !rmtree ($dir) );
}
}
} elsif ( ! scalar @files ) {
warn "\tCould not find URL for ($pkg)\n";
} else {
warn "\tFound too many URLs for ($pkg)\n";
}
}
return @pkgs;
}
sub _unpack_encap {
my ($psgconf, $pkg, $file) = @_;
my ($cmd, $dir, $err);
$dir = getcwd;
chdir($psgconf->{tmpdir});
$cmd = $psgconf->data_obj('pkg_tar_cmd')->get() . ' --use-compress-program=' . $psgconf->data_obj('pkg_gzip_cmd')->get() . ' -xf ';
$cmd .= $psgconf->{tmpdir} . '/' . $file;
$cmd .= ' ' . $pkg . '/encapinfo';
$err=&PSGConf::Util::RunCommand($cmd);
warn "\tCould not unpack encapinfo file\n"
if ( $err );
chdir($dir);
}
sub _extract_deps {
my ($psgconf, $dir, $pkg) = @_;
my (@deps);
local *FP;
if (open(FP, "<$dir/$pkg/encapinfo")) {
grep (/prereq pkgspec [^\s]+ ([^\s]*)$/o
&& (push @deps, $1),
<FP>);
close FP;
} else {
warn "\t!!! encapinfo file for ($pkg) could not be found\n";
}
return @deps;
}
###############################################################################
### pkg_install() method
###############################################################################
sub pkg_install
{
my ($self, $psgconf, $pkg) = @_;
my ($err, $umask, $cmd, $tarball);
$tarball = glob ($psgconf->{tmpdir} . '/'
. "\Q${pkg}\E" . $psgconf->data_obj('pkg_regex')->get());
$cmd = 'ENCAP_UPDATE_PATH="';
$cmd .= $psgconf->data_obj('env_vars')->find('ENCAP_UPDATE_PATH');
$cmd .= '" ' . $psgconf->data_obj('pkg_epkg_cmd')->get() . ' -S';
### If the package is already on disk,
### then just make it the linked in version.
$cmd .= 'u'
if ( ! -d $psgconf->data_obj('pkg_encap_dir')->get() . '/' . $pkg
&& ! -f $tarball );
$cmd .= 'q'
if (! $psgconf->{verbose});
map { $cmd .= " -A $_"; } @{$psgconf->{platform_suffixes}};
$cmd .= ' ' . ((-f $tarball) ? $tarball: $pkg);
### Force the umask to be something that everyone will be
### able to read and execute the files that are being installed
### and not rely on the default enviroment to set.
$umask = umask $psgconf->data_obj('pkg_epkg_umask')->get();
$err=&PSGConf::Util::RunCommand($cmd);
### Be nice and reset the umask back to what the Administrator had
umask $umask;
print "\n"
if ($psgconf->{verbose});
return $err;
}
###############################################################################
### pkg_remove() method
###############################################################################
sub pkg_remove
{
my ($self, $psgconf, $pkg, $force) = @_;
my ($err, $cmd);
$cmd = $psgconf->data_obj('pkg_epkg_cmd')->get() . ' -rS';
$cmd .= 'q'
if (! $psgconf->{verbose});
$cmd .= 'f'
if ($force);
$cmd .= " $pkg";
if (! ($err=&PSGConf::Util::RunCommand($cmd)))
{
### Now clean up the removed encap package
rmtree ($psgconf->data_obj('pkg_encap_dir')->get() . '/' . $pkg);
}
print "\n"
if ($psgconf->{verbose});
return $err;
}
###############################################################################
### documentation
###############################################################################
1;
__END__
=head1 NAME
PSGConf::Action::PackageManager::Encap - install Encap packages
=head1 SYNOPSIS
use PSGConf::Action::PackageManager::Encap;
$psgconf->register_actions(
PSGConf::Action::PackageManager::Encap->new(
'quiet' => 1
),
...
);
=head1 DESCRIPTION
The B<PSGConf::Action::PackageManager::Encap> module provides a B<PSGConf>
action class for updating Encap packages.
The B<PSGConf::Action::PackageManager::Encap> class is derived from the
B<PSGConf::Action::PackageManager::FTPArchive> 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_get_latest_version($pkg)>
A method that will return a B<PSGConf::Data::String> that contains
the latest version of $pkg from the package repository. Called from the
B<PSGConf::Action::PackageManager::check()> method. It uses the
environment variable B<ENCAP_UPDATE_PATH> to determine where to look
for these updated packages.
=item I<pkg_get_dependencies($pkg)>
A method that will return a B<PSGConf::Data::List> that contains
all the packages that $pkg will depend upon, regardless
if they have been installed or not. This is for the package on
the package repository and $pkg will have the version in it as well.
Called from the B<PSGConf::Action::PackageManager::diff()> method.
=item I<pkg_install($pkg)>
A method that will install a $pkg on the system. Returns 0 for a
successfull install, non-zero for a failure. Called from
B<PSGConf::Action::PackageManager::do()> method. It uses the
environment variable B<ENCAP_UPDATE_PATH> to determine where to get
these packages from.
=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.
=back
The constructor also registers the following data objects:
=over 4
=item I<pkg_encap_dir>
A B<PSGConf::Data::String> object that determines where Encap packages
are installed. The default is I</usr/local/encap>.
=item I<pkg_epkg_umask>
A B<PSGConf::Data::Integer> object that determines the default umask
for epkg to use. The default is I<022>.
=item I<pkg_epkg_cmd>
A B<PSGConf::Data::String> object that determines where epkg is located.
The default is I</usr/local/bin/epkg>.
=item I<pkg_tar_cmd>
A B<PSGConf::Data::String> object that determines where tar is located.
Used to extract dependencies from the encap tarball.
The default is I</usr/local/bin/tar>.
=item I<pkg_gzip_cmd>
A B<PSGConf::Data::String> object that determines where gzip is located.
Used to extract dependencies from the encap tarball.
The default is I</usr/local/bin/gzip>.
=item I<pkg_regex>
A B<PSGConf::Data::String> object that determines what the regex is to
match against the FTPArchive listing.
The default is I<(\-encap($p(\-$a)?))?\.tar\.(Z|gz)>.
=back
=head1 SEE ALSO
C<CE<lt>epkg(1)E<gt>>
L<perl>
L<PSGConf>
L<PSGConf::Action>
L<PSGConf::Action::PackageManager::FTPArchive>
L<PSGConf::Data::String>
L<PSGConf::Data::Integer>
L<PSGConf::Util>
L<File::Path>
L<File::Basename>
L<Cwd>
=cut
syntax highlighted by Code2HTML, v. 0.9.1