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, July 2008.
474 # Get current time as a number.
484 # Martin A. Hansen, July 2008.
486 # Get process id for current process.
496 # Martin A. Hansen, April 2008.
498 # Create a session id based on time and pid.
502 return get_time . get_processid;
508 # Martin A. Hansen, July 2008.
510 # Return the user name of the current user.
514 return $ENV{ 'USER' };
520 # Martin A. Hansen, April 2008.
522 # Create a temporary directory based on
523 # $ENV{ 'BP_TMP' } and sessionid.
525 # this thing is a really bad solution and needs to be removed.
529 my ( $user, $sid, $pid, $path );
531 Maasha::Common::error( qq(no BP_TMP set in %ENV) ) if not -d $ENV{ 'BP_TMP' };
533 $user = Maasha::Common::get_user();
534 $sid = Maasha::Common::get_sessionid();
535 $pid = Maasha::Common::get_processid();
537 $path = "$ENV{ 'BP_TMP' }/" . join( "_", $user, $sid, $pid, "bp_tmp" );
539 Maasha::Common::dir_create( $path );
547 # Martin A. Hansen, February 2007
549 # returns the script name
551 return ( split "/", $0 )[ -1 ];
557 # Martin A. Hansen, February 2007
559 # Given a full path to a file returns the basename,
560 # which is the part of the name before the last '.'.
562 my ( $path, # full path to filename
567 $basename = ( split "/", $path )[ -1 ];
569 $basename =~ s/(.+)\.?.*/$1/;
577 # Martin A. Hansen, December 2004.
579 # given a file, a seek beg position and
580 # length, returns the corresponding string.
582 my ( $fh, # file handle to file
583 $beg, # read start in file
584 $len, # read length of block
591 Maasha::Common::error( qq(Negative length: $len) ) if $len < 0;
593 sysseek $fh, $beg, 0;
594 sysread $fh, $string, $len;
602 # Martin A. Hansen, March 2007
604 # returns the file size for a given file
606 my ( $path, # full path to file
611 my $file_size = ( stat ( $path ) )[ 7 ];
619 # Martin A. Hansen, April 2007.
621 # Run an execute with optional arguments.
623 my ( $exe, # executable to run
624 $args, # argument string
630 my ( $command_line, $result );
632 $command_line = Maasha::Config::get_exe( $exe );
633 $command_line .= " " . $args if $args;
634 $command_line = "nice -n19 " . $command_line if $nice;
636 system( $command_line ) == 0 or Maasha::Common::error( qq(Could not execute "$command_line": $?) );
642 # Martin A. Hansen, April 2008.
644 # Run an execute with optional arguments returning the output
647 my ( $exe, # executable to run
648 $args, # argument string
654 my ( $command_line, @result );
656 $command_line = Maasha::Config::get_exe( $exe );
657 $command_line .= " " . $args if $args;
658 $command_line = "nice -n19 " . $command_line if $nice;
660 @result = `$command_line`;
664 return wantarray ? @result : \@result;
670 # Martin A. Hansen, February 2006.
672 # returns timestamp for use in log file.
673 # format: YYYY-MM-DD HH:MM:SS
677 my ( $year, $mon, $day, $time );
679 ( undef, undef, undef, $day, $mon, $year, undef, undef ) = gmtime( time );
681 $mon += 1; # first month is 0, so we correct accordingly
684 $day = sprintf "%02d", $day;
685 $mon = sprintf "%02d", $mon;
689 $time =~ s/.*(\d{2}:\d{2}:\d{2}).*/$1/;
691 return "$year-$mon-$day $time";
697 # Martin A. Hansen, July 2008.
699 # Given a process ID check if it is running
700 # on the system. Return 1 if the process is
703 my ( $pid, # process ID to check.
710 @ps_table = run_and_return( "ps", " a" );
712 if ( grep /^\s*$pid\s+/, @ps_table ) {
722 # Martin A. Hansen, May 2005
724 # Takes a given line and wraps it to a given width,
725 # without breaking any words.
727 my ( $line, # line to wrap
731 # Returns a list of lines.
733 my ( @lines, $substr, $wrap_pos, $pos, $new_line );
737 while ( $pos < length $line )
739 $substr = substr $line, $pos, $width;
741 if ( length $substr == $width )
743 $substr = reverse $substr;
744 $wrap_pos = index $substr, " ";
746 $new_line = substr $line, $pos, $width - $wrap_pos;
749 $pos += $width - $wrap_pos;
758 push @lines, $new_line;
761 return wantarray ? @lines : \@lines;
765 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<