1 package Maasha::Common;
4 # Copyright (C) 2006-2007 Martin A. Hansen.
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 # http://www.gnu.org/copyleft/gpl.html
23 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DESCRIPTION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
26 # This module contains commonly used routines
29 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
41 use vars qw( @ISA @EXPORT @EXPORT_OK );
43 @ISA = qw( Exporter ) ;
46 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
51 # Martin A. Hansen, February 2008.
53 # Print error message and exit with stack trace.
55 my ( $msg, # Error message.
56 $no_stack, # disable stack trace - OPTIONAL
61 my ( $script, $error, @lines, $line, $routine, $file, $line_no, @table, $routine_max, $file_max, $line_max );
65 $script = &get_scriptname();
67 $error = &Carp::longmess();
69 @lines = split "\n", $error;
73 push @table, [ "Routine", "File", "Line" ];
74 push @table, [ "-------", "----", "----" ];
76 $routine_max = length "Routine";
77 $file_max = length "File";
78 $line_max = length "Line";
80 if ( $line =~ /^ at (.+) line (\d+)$/ )
85 $file_max = length $file if length $file > $file_max;
86 $line_max = length $line_no if length $line_no > $line_max;
88 push @table, [ "", $file, $line_no ];
92 die qq(ERROR: Unrecognized error line "$line"\n);
95 foreach $line ( @lines )
97 if ( $line =~ /^\s*(.+) called at (.+) line (\d+)\s*$/ )
103 $routine_max = length $routine if length $routine > $routine_max;
104 $file_max = length $file if length $file > $file_max;
105 $line_max = length $line_no if length $line_no > $line_max;
107 push @table, [ $routine, $file, $line_no ];
111 die qq(ERROR: Unrecognized error line "$line"\n);
117 print STDERR qq(\nERROR!\n\nProgram \'$script\' failed: $msg.\n\n);
119 die( "MAASHA_ERROR" ) if $no_stack;
125 foreach $line ( @table ) {
126 printf( STDERR "%-${routine_max}s%-${file_max}s%s\n", @{ $line } );
131 die( "MAASHA_ERROR" );
137 # Martin A. Hansen, January 2004.
139 # read opens a file and returns a filehandle.
141 my ( $path, # full path to file
148 $type = `file $path` if $path;
150 if ( $type =~ /gzip compressed/ ) {
151 $fh = new IO::File "zcat $path|" or &Maasha::Common::error( qq(Could not read-open file "$path": $!) );
153 $fh = new IO::File $path, "r" or &Maasha::Common::error( qq(Could not read-open file "$path": $!) );
162 # Martin A. Hansen, January 2004.
164 # write opens a file and returns a filehandle
166 my ( $path, # full path to file
167 $gzip, # flag if data is to be gzipped - OPRIONAL
175 $fh = new IO::File "|gzip -f>$path" or &Maasha::Common::error( qq(Could not write-open file "$path": $!) );
177 $fh = new IO::File $path, "w" or &Maasha::Common::error( qq(Could not write-open file "$path": $!) );
186 # Martin A. Hansen, February 2006.
188 # append opens file and returns a filehandle
190 my ( $path, # path to file
197 $fh = new IO::File $path, "a" or &Maasha::Common::error( qq(Could not append-open file "$path": $!) );
205 # Martin A. Hansen, January 2007.
207 # opens a pipe and returns a filehandle
211 $fh = new IO::File "-" or &Maasha::Common::error( qq(Could not open pipe: $!) );
219 # Martin A. Hansen, July 2007.
221 # Returns a filehandle to STDIN
225 $fh = new IO::File "<&STDIN" or &Maasha::Common::error( qq(Could not read from STDIN: $!) );
233 # Martin A. Hansen, July 2007.
235 # Returns a filehandle to STDOUT
239 $fh = new IO::File ">&STDOUT" or &Maasha::Common::error( qq(Could not write to STDOUT: $!) );
247 # Martin A. Hansen, December 2004.
249 # writes a data structure to file.
251 my ( $path, # full path to file
252 $data, # data structure
255 &Storable::store( $data, $path ) or &Maasha::Common::error( qq(Could not write-open file "$path": $!) );
261 # Martin A. Hansen, December 2004.
263 # retrieves hash data structure
264 # (this routines needs to test if its a hash, array or else)
266 my ( $path, # full path to data file
271 $data = &Storable::retrieve( $path ) or &Maasha::Common::error( qq(Could not read-open file "$path": $!) );
273 return wantarray ? %{ $data } : $data;
279 # Martin A. Hansen, July 2007.
281 # Creates a directory.
283 my ( $path, # full path to dir
289 &Maasha::Common::error( qq(Directory already exists "$path": $!) );
291 mkdir $path or &Maasha::Common::error( qq(Could not create directory "$path": $!) );
296 sub dir_create_if_not_exists
298 # Martin A. Hansen, May 2008.
300 # Creates a directory if it does not already exists.
302 my ( $path, # full path to dir
307 if ( not -d $path ) {
308 mkdir $path or &Maasha::Common::error( qq(Could not create directory "$path": $!) );
315 # Martin A. Hansen, April 2008.
317 # Removes a directory recursively.
319 my ( $path, # directory
322 &Maasha::Common::run( "rm", "-rf $path" ) if -d $path;
328 # Martin A. Hansen, June 2007.
330 # returns all dirs in a given directory.
332 my ( $path, # full path to directory
335 # returns a list of filenames.
339 $dh = &open_dir( $path );
341 @dirs = &read_dir( $dh );
342 @dirs = grep { -d "$path/$_" } @dirs;
344 map { $_ = "$path/$_" } @dirs;
348 return wantarray ? @dirs : \@dirs;
354 # Martin A. Hansen, June 2007.
356 # returns all files in a given directory.
358 my ( $path, # full path to directory
361 # returns a list of filenames.
365 $dh = &open_dir( $path );
367 @files = &read_dir( $dh );
368 @files = grep { -f "$path/$_" } @files;
370 map { $_ = "$path/$_" } @files;
374 return wantarray ? @files : \@files;
380 # Martin A. Hansen, June 2007.
382 # open a directory and returns a directory handle
386 my ( $path, # full path to directory
393 $dh = IO::Dir->new( $path ) or &Maasha::Common::error( qq(Could not open dir "$path": $!) );
401 # Martin A. Hansen, June 2007.
403 # read all files and directories from a directory.
405 my ( $dh, # directory handle object
410 my ( $elem, @elems );
412 while ( defined( $elem = $dh->read ) ) {
416 return wantarray ? @elems : \@elems;
422 # Martin A. Hansen, December 2006
424 # reads arguments from @ARGV which is strictly formatted.
425 # three kind of argments are accepted:
426 # 1) file names [filename]
427 # 2) options with value [--option=value]
428 # 3) option without value [--option]
430 my ( $args, # list of arguments
431 $ok_args, # list of accepted arguments - OPTIONAL
436 my ( %ok_hash, $arg, @dirs, @files, %hash );
438 foreach $arg ( @{ $args } )
440 if ( $arg =~ /^--([^=]+)=(.+)$/ ) {
442 } elsif ( $arg =~ /^--(.+)$/ ) {
444 } elsif ( -d $arg ) {
446 } elsif ( -f $arg ) {
449 &Maasha::Common::error( qq(Bad syntax in argument->"$arg") );
453 $hash{ "DIRS" } = \@dirs;
454 $hash{ "FILES" } = \@files;
458 map { $ok_hash{ $_ } = 1 } @{ $ok_args };
460 $ok_hash{ "DIRS" } = 1;
461 $ok_hash{ "FILES" } = 1;
463 map { &Maasha::Common::error( qq(Unknown argument->"$_") ) if not exists $ok_hash{ $_ } } keys %hash;
466 return wantarray ? %hash : \%hash;
472 # Martin A. Hansen, April 2008.
474 # Create a session id based on time and pid.
484 # Martin A. Hansen, April 2008.
486 # Create a temporary directory based on
487 # $ENV{ 'BP_TMP' } and sessionid.
491 my ( $user, $sid, $path );
493 &Maasha::Common::error( qq(no BP_TMP set in %ENV) ) if not -d $ENV{ 'BP_TMP' };
495 $user = $ENV{ 'USER' };
498 $sid = &Maasha::Common::get_sessionid();
500 $path = "$ENV{ 'BP_TMP' }/$user\_$sid";
502 &Maasha::Common::dir_create( $path );
510 # Martin A. Hansen, February 2007
512 # returns the script name
514 return ( split "/", $0 )[ -1 ];
520 # Martin A. Hansen, February 2007
522 # Given a full path to a file returns the basename,
523 # which is the part of the name before the last '.'.
525 my ( $path, # full path to filename
530 $basename = ( split "/", $path )[ -1 ];
532 $basename =~ s/(.+)\.?.*/$1/;
540 # Martin A. Hansen, December 2004.
542 # given a file, a seek beg position and
543 # length, returns the corresponding string.
545 my ( $fh, # file handle to file
546 $beg, # read start in file
547 $len, # read length of block
554 &Maasha::Common::error( qq(Negative length: $len) ) if $len < 0;
556 sysseek $fh, $beg, 0;
557 sysread $fh, $string, $len;
565 # Martin A. Hansen, March 2007
567 # returns the file size for a given file
569 my ( $path, # full path to file
574 my $file_size = ( stat ( $path ) )[ 7 ];
582 # Martin A. Hansen, April 2007.
584 # Run an execute with optional arguments.
586 my ( $exe, # executable to run
587 $args, # argument string
593 my ( $command_line, $result );
595 $command_line = &Maasha::Config::get_exe( $exe );
596 $command_line .= " " . $args if $args;
597 $command_line = "nice -n19 " . $command_line if $nice;
599 system( $command_line ) == 0 or &Maasha::Common::error( qq(Could not execute "$command_line": $?) );
605 # Martin A. Hansen, April 2008.
607 # Run an execute with optional arguments returning the output
610 my ( $exe, # executable to run
611 $args, # argument string
617 my ( $command_line, @result );
619 $command_line = &Maasha::Config::get_exe( $exe );
620 $command_line .= " " . $args if $args;
621 $command_line = "nice -n19 " . $command_line if $nice;
623 @result = `$command_line`;
627 return wantarray ? @result : \@result;
633 # Martin A. Hansen, February 2006.
635 # returns timestamp for use in log file.
636 # format: YYYY-MM-DD HH:MM:SS
640 my ( $year, $mon, $day, $time );
642 ( undef, undef, undef, $day, $mon, $year, undef, undef ) = gmtime( time );
644 $mon += 1; # first month is 0, so we correct accordingly
647 $day = sprintf "%02d", $day;
648 $mon = sprintf "%02d", $mon;
652 $time =~ s/.*(\d{2}:\d{2}:\d{2}).*/$1/;
654 return "$year-$mon-$day $time";
660 # Martin A. Hansen, May 2005
662 # Takes a given line and wraps it to a given width,
663 # without breaking any words.
665 my ( $line, # line to wrap
669 # Returns a list of lines.
671 my ( @lines, $substr, $wrap_pos, $pos, $new_line );
675 while ( $pos < length $line )
677 $substr = substr $line, $pos, $width;
679 if ( length $substr == $width )
681 $substr = reverse $substr;
682 $wrap_pos = index $substr, " ";
684 $new_line = substr $line, $pos, $width - $wrap_pos;
687 $pos += $width - $wrap_pos;
696 push @lines, $new_line;
699 return wantarray ? @lines : \@lines;
703 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<