/usr/lib/pegasus/perl/Pegasus/Properties.pm is in pegasus-wms 4.4.0+dfsg-7.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | package Pegasus::Properties;
#
# Provides parsing of Java property files from Perl.
#
# Copyright 2007-2010 University Of Southern California
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Jens-S. Vöckler voeckler at isi dot edu
# Revision : $Revision$
# $Id$
#
use 5.006;
use strict;
use warnings;
use vars qw(%initial %system);
require Exporter;
our @ISA = qw(Exporter);
# declarations of methods here. Use the commented body to unconfuse emacs
sub pegasusrc(;$); # { }
sub parse_properties($;\%); # { }
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
our $VERSION = '1.0';
$VERSION=$1 if ( '$Revision$' =~ /Revision:\s+([0-9.]+)/o );
our $pegasus_env = 'pegasus.env.';
our $pegasus_len = length($pegasus_env);
our @EXPORT_OK = qw($VERSION parse_properties pegasusrc %initial %system
$pegasus_env);
our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
our @EXPORT = ();
# Preloaded methods go here.
use POSIX qw(uname);
use Carp;
use File::Spec;
sub pegasusrc(;$) {
# purpose: "static" method to determine location of pegasusrc
# paramtr: $home (opt. IN): override home location
# returns: a string
#
my $home = shift() ||
$ENV{HOME} ||
(getpwuid($>))[7] ||
File::Spec->curdir();
File::Spec->catfile( $home, '.pegasusrc' );
}
sub parse_properties($;\%) {
# purpose: "static" method to parse properties from a file.
# paramtr: $fn (IN): is the filename of the property file to read
# $hashref (IN): more properties for substitutions
# warning: dies, if the $fn cannot be opened properly.
# globals: %system (IN): more properties for substitutions
# returns: a hash of properties, possibly empty.
#
my $fn = shift;
my $hashref = shift || {}; # may be undef'd
my %result = ();
open( IN, "<$fn" ) || die "Warning: open $fn: $!\n";
print STDERR "# parsing properties in $fn...\n" if $main::DEBUG;
my $save;
while ( <IN> ) {
next if /^[!\#]/; # comments are skipped
s/[\r\n]*$//; # safe chomp
s/\#(.*)$//; # NEW: chop in-line comments to EOLN
s/\\(.)/$1/g; # replace escaped special characters #!=:
s/^\s*//; # replace all starting whitespace
s/\s*$//; # replace all trailing whitespace
next unless length($_); # skip empty lines
if ( /\\$/ ) {
# continuation line
chop ;
$save .= $_;
} else {
# regular line
$_ = $save . $_ if defined $save;
undef $save;
print STDERR "# Parsing: $_\n" if $main::DEBUG;
if ( /([^:= \t]+)\s*[:=]?\s*(.*)/ ) {
# new fix for auto gen properties
my ($k,$v) = ($1,$2);
# substitutions -- works arbitrarily deep?
while ( $v =~ /(\$\{([A-Za-z0-9._]+)\})/g ) {
my ($a,$b) = ($1,$2);
my $newval = $hashref->{$b} ||
$system{$b} ||
$result{$b} ||
'';
substr($v,index($v,$a),length($a),$newval);
}
print STDERR "# Storing: $k => $v\n" if $main::DEBUG;
# 20110519 (jsv): No key lower-casing requested by FS,KV
$result{$k} = $v;
} else {
carp "Illegal content in $fn:$.\n";
}
}
}
close(IN);
%result;
}
BEGIN {
#
# Part 1: Assemble %system properties emulating some Java properties
#
%system = (); # start empty
# assemble some default Java properties
$system{'file.separator'} = File::Spec->catfile('','');
$system{'java.home'} = $ENV{'JAVA_HOME'} if exists $ENV{'JAVA_HOME'};
$system{'java.class.path'} = $ENV{CLASSPATH} if exists $ENV{CLASSPATH};
$system{'java.io.tmpdir'} = $ENV{TMP} || File::Spec->tmpdir();
# $system{'line.separator'} = "\n"; # Unix
@system{'os.name','os.version','os.arch'} = (POSIX::uname())[0,2,4];
$system{'user.dir'} = File::Spec->curdir();
$system{'user.home'} = $ENV{HOME} || (getpwuid($>))[7];
$system{'user.language'} = $ENV{LANG} || 'en';
$system{'user.name'} = $ENV{USER} || $ENV{LOGNAME} || scalar getpwuid($>);
$system{'user.timezone'} = $ENV{TZ}; # can be undef'd
# not required, but useful
$system{'pegasus.home'} = $ENV{'PEGASUS_HOME'}; # can be undef'd
#
# Part 2: Assemble commandline properties from initial -D argument
#
%initial = (); # start empty
# Extracts -Dk=v properties from @ARGV before Getopt sees it
# This will remove *only* the initial -D arguments from the CLI!
if ( @ARGV > 0 ) {
while ( defined $ARGV[0] && substr( $ARGV[0], 0, 2 ) eq '-D' ) {
my $arg = shift(@ARGV);
my ($k,$v) = split( /=/,
($arg eq '-D' ? shift(@ARGV) : substr($arg,2)),
2 );
# 20110519 (jsv): No key lower-casing requested by FS,KV
#$k = lc $k;
if ( $k eq 'pegasus.properties' || $k eq 'pegasus.user.properties' ) {
carp "Warning: $k is no longer supported, ignoring, please use --conf\n";
} else {
$initial{$k} = $v if length($k);
}
}
}
# CLI properties extend (and overwrite) system properties
%system = ( %system, %initial );
}
#
# ctor
#
sub new {
# purpose: Initialize an instance variable
# paramtr: $conffile (IN): --conf filename (or undef)
# $runprops (IN): properties from rundir (or undef)
# warning: exceptions from parse_properties() may be propagated
# returns: reference to blessed self
#
my $proto = shift;
my $class = ref($proto) || $proto || __PACKAGE__;
my $conffile = shift;
my $rundirpfn = shift;
my $pegasusrc = pegasusrc();
my %config = ();
if ( defined $conffile ) {
croak "FATAL: $conffile does not exist" unless -e $conffile;
croak "FATAL: $conffile is not readable" unless -r _;
if ( -s _ ) {
print STDERR "# priority level 1: $conffile\n" if $main::DEBUG;
%config = parse_properties($conffile);
} else {
carp "Warning: $conffile is empty, trying next";
goto LEVEL2;
}
} elsif ( defined $rundirpfn ) {
LEVEL2:
croak "FATAL: $rundirpfn does not exist" unless -e $rundirpfn;
croak "FATAL: $rundirpfn is not readable" unless -r _;
if ( -s _ ) {
print STDERR "# priority level 2: $rundirpfn\n" if $main::DEBUG;
%config = parse_properties($rundirpfn);
} else {
carp "Warning: $rundirpfn is empty, trying next priority";
goto LEVEL3;
}
} else {
LEVEL3:
# $HOME/.pegasusrc may safely not exist, no failures here
if ( -s $pegasusrc ) {
print STDERR "# priority level 3: $pegasusrc\n" if $main::DEBUG;
%config = parse_properties($pegasusrc);
} else {
warn "Warning: No property files parsed whatsoever\n";
}
}
# create instance and return handle to self.
# last one in chain below has highest priority.
my $self = bless { m_config => { %config, %initial } }, $class;
$self->setenv();
$self;
}
sub setenv {
# purpoes: merge properties starting in $pegasus_key into %ENV
#
my $self = shift || croak;
foreach my $k ( keys %{ $self->{'m_config'} } ) {
$ENV{substr($k,$pegasus_len)}=$self->{'m_config'}{$k}
if substr($k,0,$pegasus_len) eq $pegasus_env;
}
}
sub reinit {
# purpose: ensure that %initial has highest priority
#
my $self = shift;
%{ $self->{'m_config'} } = ( %{ $self->{'m_config'} }, %initial );
}
sub merge {
# purpose: Read and merge a file into the current property set
# paramtr: $fn (IN): where to read properties from.
# warning: Properties from the file will overwrite existing ones.
# If the instance has keys (a,b), and the file has (b,c)
# the updated instance has keys (a,b,c) with b from file.
# warning: use reinit() to give CLI properties precedence again.
# warning: exceptions from parse_properties() will be propagated.
# returns: hash of all new (merged) properties.
#
my $self = shift;
my $where = shift || croak "need a filename";
# the new props from the file will merge with the existing properties,
# where duplicate keys take precedence from the file.
%{ $self->{'m_config'} } = ( %{ $self->{'m_config'} },
parse_properties($where) );
}
sub property {
# purpose: Accessor, simultaneous get (1arg) and set (2arg) method
# paramtr: $key (IN): property name to access
# $val (IN): if specified, the new value to set
# returns: in get mode, the current value,
# in set mode, the old value.
my $self = shift;
my $key = shift || croak "need a property key";
my $oldv = $self->{'m_config'}{$key};
$self->{'m_config'}{$key} = shift if ( @_ );
$oldv;
}
sub has {
# purpose: Checks for the existence of a given property key
# paramtr: $key (IN): property name to access
# returns: true, if a property with this key exists
#
my $self = shift;
my $key = shift || croak "need a property key";
exists $self->{'m_config'}{$key};
}
sub all {
# purpose: Return all known properties as simple hash
# returns: hash
#
my $self = shift;
%{ $self->{'m_config'} };
}
sub keyset {
# purpose: finds a subset of keys that matches a RE predicate
# paramtr: $predicate (opt. IN): predicate to match against
# returns: a set of keys that match a predicate, or all w/o predicate
my $self = shift;
my $predicate = shift;
if ( defined $predicate ) {
grep { /$predicate/ } keys %{ $self->{'m_config'} };
} else {
keys %{ $self->{'m_config'} };
}
}
sub propertyset {
# purpose: finds a subset of keys that matches a prefix
# paramtr: $predicate (IN): predicate to match against
# paramtr: $remove (IN): if true, remove prefix
# returns: a hash containing the matching keys and respective values
my $self = shift;
my $prefix = shift || croak "need a prefix to match";
my $length = length($prefix);
my $remove = shift;
my %result = ();
foreach my $key ( grep { substr($_,0,$length) eq $prefix }
keys %{ $self->{'m_config'} } ) {
my $newkey = $remove ? substr($key,$length) : $key;
$result{$newkey} = $self->{'m_config'}->{$key}
if ( length($newkey) > 0 );
}
%result;
}
sub _quote($) {
local $_ = shift;
s{\015}{\\r}g;
s{\011}{\\n}g;
s{([:= \t\f])}{\\$1}g;
"$_";
}
sub dump {
# purpose: prints the key set in property format
# paramtr: $fn (opt. IN): Name of file to print into
# returns: number of things printed, undef for error.
local(*OUT);
my $self = shift;
my $fn = shift || '-'; # defaults to stdout
my $count = 0;
if ( open( OUT, ">$fn" ) ) {
print OUT "# generated ", scalar localtime(), "\n";
foreach my $key ( sort keys %{ $self->{'m_config'} } ) {
print OUT _quote($key), '=',
_quote($self->{'m_config'}->{$key}), "\n";
}
close OUT;
} else {
carp "open $fn: $!";
undef $count;
}
$count;
}
#
# return 'true' to package loader
#
1;
__END__
=head1 NAME
Pegasus::Properties - parsing of Java property files from Perl.
=head1 SYNOPSIS
use Pegasus::Properties qw(:parse);
$p = Pegasus::Properties->new( $conffile, undef );
$p->merge( $fn );
$p->reinit();
$p->dump('-'); # dump all known properties on stdout
something() if $p->property('pegasus.db');
$p->property('pegasus.tc.file') = "/some/where";
foreach my $key ( $p->keyset('^pegasus\.rc') ) { ... }
%x = $p->propertyset('pegasus.rc.');
do( $p->property('asdf') ) if $p->has('asdf');
=head1 DESCRIPTION
The Pegasus::Properties module reads Java properties for the GriPhyN
Virtual Data System. It permits commandline-based overwrites of
properties using Java's C<-Dprop=val> syntax in Perl by removing initial
definitions from C<@ARGV> during module initialization time. Thus, it is
recommended to use this module before parsing commandline arguments.
Up to three property files from the GriPhyN Virtual Data System are read
from the constructor, please refer to the L<new|/"METHODS"> method.
All property keys are lower cased when read as a safety precaution.
=head1 VARIABLES
Variables are not exported by default. They must be explicitely imported
when importing this module.
=over 4
=item %initial
This variable is initialed during module initialization. It parses the
commandline vector C<@ARGV> for initial arguments starting with hyphen
capital D like the following:
perl myprog.pl -Dk1=v1 -Dk2=v2 ...
Such definitions are removed from C<@ARGV>, and the definitions placed
into the initial variable. If your application uses capital-D as a valid
argument switch, you can still use it, alas never as the first argument.
Only property-like definitions that are initial on the commandline will
be removed and put into this variable. Commandline properties have the
highest priority of all properties. You should not write to this
variable.
=item %system
This variable is initialized to mimick some Java system properties.
However, only a smaller subset is provided. These system properties have
the lowest priority. You should not write to this variable. Properties
from C<%initial> are merged with a higher priority into the system
properties, permitting command-line option to overwrite system
properties.
=back
=head1 STATIC METHODS
=over 4
=item Pegasus::Properties::parse_properties( $fn )
=item Pegasus::Properties::parse_properties( $fn, $hashref )
The static method reads a property file, located by $fn, into a
single-level Perl hash. If the optional second argument is specified,
the hash will be used to do variable substitutions from the the second
argument properties or system properties. Not found properties are
replaced by an empty string.
Please note that the method throws an error, if the file does not exist
or cannot be opened properly. It is up to the caller to catch this
exception.
=item Pegasus::Properties::pegasusrc( )
=item Pegasus::Properties::pegasusrc( $home )
This simple static method constructs a filename where to find the
C<$HOME/.pegasusrc> file. The location of the home directory can
be passed as optional argument, or auto-detected otherwise.
=back
=head1 INSTANCE METHODS
=over 4
=item new( $conffile, $rundirpropfn )
The constructor needs to know about the possible I<conf> command-line
option file location, and the property file in the designated run
directory. Either argument may be C<undef> to indicate that it does not
exist. Internally the constructor uses the location of the
C<$HOME/.pegasusrc> file, which is automatically constructed.
The constructor attempts to read from the defined file with the highest
priority first. If the file does not exist or is not readable, it will
throw an exception. If the file is empty (0 byte sized), it will warn
and attempt to read the next lower priority (etc.).
Values from the C<%initial> hash are merged into the instance with the
highest priority.
=item merge( $fn )
The C<merge> method permits you to easily add properties from a file
to the current instance. The new properties from the file take a higher
priority than the existing one, in case keys exist in both.
Typically, you want to follow C<merge> with C<reinit> to give
command-line properties precedence.
=item reinit( )
Will ensure that properties from C<%initial> are merged back into the
instance, overwriting any existing properties with the same key.
=item property( $key )
If used as r-value, the property setting of the specified key is
obtained. If the property does not exist, the value of C<undef> is returned.
If used as l-value, as in an assignment, the property of the specified
value will be set. The old value previously know is the result of the
method.
The emulated system properties will not be considered.
=item has( $key )
This method checks for the existence of a given key in the properties.
Unlike the C<property> method, it will not auto-vivify any key.
=item keyset( $predicate )
Given a regular expression predicate, this method returns all keys that
match the predicate. Please note that it is recommended to match
prefixes by anchoring the expression with an initial roof (C<^>)
character, and that you must backslash-escape the period character that
is literal part of most properties.
foreach my $key ( $p->keyset('^pegasus\.db\.') ) {
xxx( $p->property($key) );
}
The above code snippet will only find properties matching the prefix of
C<pegasus.db.>, but not C<pegasus.db> itself.
If invoked without argument, this method will return all keys.
The emulated system properties will not be considered.
=item propertyset( $prefix, $truncate )
Given a normal string prefix, this method returns a hash starting with
the prefix string. This is not a regular expression match, just plain
string prefix matching.
I
f the optional argument $truncate is specified and true, the prefix
string will be removed from the keys in the result set.
%x = $p->propertyset('pegasus.db.');
foreach my $key ( sort keys %x ) {
xxx( $x{$key} );
}
=item dump( $filename )
This is mostly a debug function. It dumps all properties except the
artificial system properties into the specified file. For convenience,
you can use the hyphen C<-> for I<stdout>.
=back
=head1 SEE ALSO
L<http://www.griphyn.org/>
=head1 AUTHOR
Jens-S. VE<ouml>ckler, C<voeckler at isi dot edu>
Gaurang Mehta, C<gmehta at isi dot edu>
=head1 COPYRIGHT AND LICENSE
Copyright 2007-2011 University Of Southern California
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
L<http://www.apache.org/licenses/LICENSE-2.0>
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=cut
|