package Util::ParfileTool;
##############################################################################
#
# DESCRIPTION: This sub-class adds functionality for handling FTOOL-style
# DESCRIPTION: parameter files.
#
# HISTORY: 1.0 -> 1.1 2004-02-11
# HISTORY: Moved the environment setup into Tool.pm
# HISTORY:
# HISTORY: 1.1 -> 1.2 2004-03-09
# HISTORY: Moved the HEADASNOQUERY environment variable here from HEAdas.pm,
# HISTORY: since we are starting to see PseudoFtools based on the HEAdas
# HISTORY: libraries instead of the FTOOLS ones.
#
# VERSION: 1.2
#
##############################################################################
use Util::Tool;
@ISA=("Util::Tool");
use strict;
use Util::Parfile;
##########################################################################
# This constructor should be called by subclass constructors after
# sufficient initialization has been done so that the
# bins and syspfiles methods methods will work
##########################################################################
sub new {
my $self = shift;
my $tool = shift;
my $syspfiles = shift;
my $bin_ref = shift;
my $lib_ref = shift;
my @bins=@$bin_ref;
my @libs=@$lib_ref;
####################################################
# find the executable in one of the bin directories
####################################################
my $bin="";
foreach (@bins) {
if( -x "$_/$tool" ) {
###############
# found it
##############
$bin=$_;
last;
}
}
unless($bin) {
#############################
# unknown tool
#############################
my $log = $self->log();
if($log) { $log->error(2,"Unknown tool $tool"); }
else { print STDERR "Unknown tool $tool\n"; }
return $self;
}
########################################
# inherit the generic Tool constructor
########################################
$self=$self->SUPER::new($bin,$tool);
##############################
# remember directories
##############################
$self->{BINS}=$bin_ref;
if($lib_ref) { $self->{LIBS}=$lib_ref }
else { $self->{LIBS}=[] }
$self->{SYSPFILES}=$syspfiles;
#############################################
# copy the parfile to the current directory
#############################################
my $parfile="$tool.par";
if(open IN, "<$syspfiles/$parfile") {
open OUT, ">$parfile";
print OUT <IN>;
close OUT;
close IN;
}
#########################################################
# create the parfile object
# and set the default query mode to "h"
# so FTOOLS won't hang if we forget to set a parameter
#########################################################
$self->{PARFILE} = Util::Parfile->new("$parfile");
$self->{PARFILE}->set({mode=>"h"});
##########################################################
# flag to distinguish scripts from compiled tools
# scripts have different environment requirements
##########################################################
$self->{IS_SCRIPT} = 0;
return $self;
}
######################
# ACCESSORS:
######################
#########################################################################
# return the directory containing the "system" parfiles
#########################################################################
sub syspfiles {
my $self=shift;
return $self->{SYSPFILES};
}
#########################################################################
# return all shared object library directories for this software package
# These will be prepended to LD_LIBRARY_PATH when the tool is run
#########################################################################
sub libs {
my $self=shift;
return @{$self->{LIBS}};
}
#########################################################################
# return all executable directories for this software package
# These will be prepended to PATH when the tool is run
#########################################################################
sub bins {
my $self=shift;
return @{$self->{BINS}};
}
########################################################################
# Returns a hash of environment variables which must
# be set before running this tool
########################################################################
sub environment {
my $self=shift;
return {PFILES =>".;".$self->syspfiles(),
PFCLOBBER =>1 ,
HEADASNOQUERY=>"yes"
};
} # end of environment method
#########################################################################
# set the flag indicating whether this is a script
#########################################################################
sub is_script {
my $self=shift;
$self->{IS_SCRIPT} = shift;
return $self;
}
#################################################################
# get or set the Util::Parfile object for the parameter file.
# This can be used to read values which the program wrote to the
# parfile. Note the parfile is deleted when this object is destroyed
# so you may need to explicitly call DESTROY() so that it will
# stick around long enough to be read.
#################################################################
sub parfile {
my $self=shift;
if (@_) { $self->{PARFILE} = shift }
return $self->{PARFILE};
}
#################################################################
# set the FTOOL input parameters. Note the parameters
# are given as a reference to a hash.
#################################################################
sub params { #({name1=>value1, name2=>value2});
my $self=shift;
my $params=shift;
if(!$self->{PARAMS}) {
#####################################################
# no params defined before, so just take the new set
#####################################################
$self->{PARAMS} = $params;
} else {
##################################################
# merge the new parameters list with the old one
##################################################
my $key;
foreach $key (keys(%$params)) {
$self->{PARAMS}->{$key} = $params->{$key};
}
}
return $self;
}
#############################################################################
# find a file in one of the bin directories
#############################################################################
sub find_bin {
my $self=shift;
my $file=shift;
foreach ($self->bins()) {
if( -f "$_/$file" ) { return $_ }
}
return "";
}
#####################################################
# Special initialization - set the parameters
# in the parfile
#####################################################
sub init {
my $self=shift;
############################
# do the inherited init
############################
$self->SUPER::init();
###################################################
# set the parameters
# Then empty the parfile values stored in memory
# we have to do this because running the tool may
# modify the parameters in an unpredictable way
# which does not use a Parfile object
###################################################
$self->{PARFILE}->set($self->{PARAMS});
$self->{PARFILE}->clear_param_cache();
###################################################
# If this is a script, remember the parfiles
# in the working directory. Scripts can
# leave parfiles behind which we would like to delete
# without touching the already existing parfiles
######################################################
if($self->{IS_SCRIPT}) {
$self->{PRE_EXISTING_PARFILES} = {map { $_ => 1 } glob("*.par")};
}
} # end of init method
###############################################################################
#
###############################################################################
sub cleanup {
my $self = shift;
if($self->{IS_SCRIPT} && $self->{PRE_EXISTING_PARFILES} ) {
########################################################
# delete all the parfiles created by running the script
########################################################
foreach (glob("*.par") ) {
####################################################
# ski pthe parfiles which were already here before
# we ran the script
####################################################
if($self->{PRE_EXISTING_PARFILES}->{$_}) { next; }
unlink;
} # end of loop over parfiles
} # end if this is a script
###################################
# now inherit generic tool stuff
###################################
$self->SUPER::cleanup();
} # end of cleanup method
######################################################
# override the generic tool error routine
# to also dump the parfile to the log if it exists
######################################################
sub error {
my $self=shift;
###########################
# do all the generic stuff
###########################
$self->SUPER::error();
#############################
# dump the parfile
#############################
my $log=$self->log();
my $parfile=$self->{PARFILE}->{NAME};
if($log) {
$log->entry("Contents of $parfile");
$log->file($parfile);
}
} # end of error method
####################################
# destructor - deletes the parfile.
####################################
sub DESTROY {
my $self=shift;
##############################
# delete the parfile
##############################
unlink "$self->{PARFILE}->{NAME}";
}
1;