File Coverage

Bio/Root/IO.pm
Criterion Covered Total %
statement 235 375 62.6
branch 103 244 42.2
condition 57 150 38.0
subroutine 32 33 96.9
pod 15 15 100.0
total 442 817 54.1


line stmt bran cond sub pod time code
1             package Bio::Root::IO;
2              
3 276     276   2128 use strict;
  276         579  
  276         6579  
4 276     276   1133 use Symbol;
  276         483  
  276         13466  
5 276     276   1314 use IO::Handle;
  276         564  
  276         9047  
6 276     276   75098 use File::Copy;
  276         501009  
  276         13275  
7 276     276   1628 use Fcntl;
  276         444  
  276         51876  
8 276     276   1570 use base qw(Bio::Root::Root);
  276         431  
  276         128231  
9              
10             # as of 2016, worked on most systems, but will test this in a RC
11             my %modes = ( 0 => 'r', 1 => 'w', 2 => 'rw' );
12              
13             =head1 SYNOPSIS
14              
15             # Use stream I/O in your module
16             $self->{'io'} = Bio::Root::IO->new(-file => "myfile");
17             $self->{'io'}->_print("some stuff");
18             my $line = $self->{'io'}->_readline();
19             $self->{'io'}->_pushback($line);
20             $self->{'io'}->close();
21              
22             # obtain platform-compatible filenames
23             $path = Bio::Root::IO->catfile($dir, $subdir, $filename);
24             # obtain a temporary file (created in $TEMPDIR)
25             ($handle) = $io->tempfile();
26              
27             =head1 DESCRIPTION
28              
29             This module provides methods that will usually be needed for any sort
30             of file- or stream-related input/output, e.g., keeping track of a file
31             handle, transient printing and reading from the file handle, a close
32             method, automatically closing the handle on garbage collection, etc.
33              
34             To use this for your own code you will either want to inherit from
35             this module, or instantiate an object for every file or stream you are
36             dealing with. In the first case this module will most likely not be
37             the first class off which your class inherits; therefore you need to
38             call _initialize_io() with the named parameters in order to set file
39             handle, open file, etc automatically.
40              
41             Most methods start with an underscore, indicating they are private. In
42             OO speak, they are not private but protected, that is, use them in
43             your module code, but a client code of your module will usually not
44             want to call them (except those not starting with an underscore).
45              
46             In addition this module contains a couple of convenience methods for
47             cross-platform safe tempfile creation and similar tasks. There are
48             some CPAN modules related that may not be available on all
49             platforms. At present, File::Spec and File::Temp are attempted. This
50             module defines $PATHSEP, $TEMPDIR, and $ROOTDIR, which will always be set,
51             and $OPENFLAGS, which will be set if either of File::Spec or File::Temp fails.
52              
53             The -noclose boolean (accessed via the noclose method) prevents a
54             filehandle from being closed when the IO object is cleaned up. This
55             is special behavior when a object like a parser might share a
56             filehandle with an object like an indexer where it is not proper to
57             close the filehandle as it will continue to be reused until the end of the
58             stream is reached. In general you won't want to play with this flag.
59              
60             =head1 AUTHOR Hilmar Lapp
61              
62             =cut
63              
64             our ($FILESPECLOADED, $FILETEMPLOADED,
65             $FILEPATHLOADED, $TEMPDIR,
66             $PATHSEP, $ROOTDIR,
67             $OPENFLAGS, $VERBOSE,
68             $ONMAC, $HAS_EOL, );
69              
70             my $TEMPCOUNTER;
71             my $HAS_WIN32 = 0;
72              
73             BEGIN {
74 276     276   853 $TEMPCOUNTER = 0;
75 276         410 $FILESPECLOADED = 0;
76 276         388 $FILETEMPLOADED = 0;
77 276         407 $FILEPATHLOADED = 0;
78 276         404 $VERBOSE = 0;
79              
80             # try to load those modules that may cause trouble on some systems
81 276         402 eval {
82 276         1300 require File::Path;
83 276         478 $FILEPATHLOADED = 1;
84             };
85 276 50       1013 if( $@ ) {
86 0 0       0 print STDERR "Cannot load File::Path: $@" if( $VERBOSE > 0 );
87             # do nothing
88             }
89              
90             # If on Win32, attempt to find Win32 package
91 276 50       1434 if($^O =~ /mswin/i) {
92 0         0 eval {
93 0         0 require Win32;
94 0         0 $HAS_WIN32 = 1;
95             };
96             }
97              
98             # Try to provide a path separator. Why doesn't File::Spec export this,
99             # or did I miss it?
100 276 50       1257 if ($^O =~ /mswin/i) {
    50          
101 0         0 $PATHSEP = "\\";
102             } elsif($^O =~ /macos/i) {
103 0         0 $PATHSEP = ":";
104             } else { # unix
105 276         518 $PATHSEP = "/";
106             }
107 276         431 eval {
108 276         895 require File::Spec;
109 276         425 $FILESPECLOADED = 1;
110 276         22481 $TEMPDIR = File::Spec->tmpdir();
111 276         2097 $ROOTDIR = File::Spec->rootdir();
112 276         1191 require File::Temp; # tempfile creation
113 276         608 $FILETEMPLOADED = 1;
114             };
115 276 50       867 if( $@ ) {
116 0 0       0 if(! defined($TEMPDIR)) { # File::Spec failed
117             # determine tempdir
118 0 0 0     0 if (defined $ENV{'TEMPDIR'} && -d $ENV{'TEMPDIR'} ) {
    0 0        
119 0         0 $TEMPDIR = $ENV{'TEMPDIR'};
120             } elsif( defined $ENV{'TMPDIR'} && -d $ENV{'TMPDIR'} ) {
121 0         0 $TEMPDIR = $ENV{'TMPDIR'};
122             }
123 0 0       0 if($^O =~ /mswin/i) {
    0          
124 0 0       0 $TEMPDIR = 'C:\TEMP' unless $TEMPDIR;
125 0         0 $ROOTDIR = 'C:';
126             } elsif($^O =~ /macos/i) {
127 0 0       0 $TEMPDIR = "" unless $TEMPDIR; # what is a reasonable default on Macs?
128 0         0 $ROOTDIR = ""; # what is reasonable??
129             } else { # unix
130 0 0       0 $TEMPDIR = "/tmp" unless $TEMPDIR;
131 0         0 $ROOTDIR = "/";
132             }
133 0 0 0     0 if (!( -d $TEMPDIR && -w $TEMPDIR )) {
134 0         0 $TEMPDIR = '.'; # last resort
135             }
136             }
137             # File::Temp failed (alone, or File::Spec already failed)
138             # determine open flags for tempfile creation using Fcntl
139 0         0 $OPENFLAGS = O_CREAT | O_EXCL | O_RDWR;
140 0         0 for my $oflag (qw/FOLLOW BINARY LARGEFILE EXLOCK NOINHERIT TEMPORARY/){
141 0         0 my ($bit, $func) = (0, "Fcntl::O_" . $oflag);
142 276     276   2184 no strict 'refs';
  276         479  
  276         24548  
143 0 0       0 $OPENFLAGS |= $bit if eval { $bit = &$func(); 1 };
  0         0  
  0         0  
144             }
145             }
146 276         192937 $ONMAC = "\015" eq "\n";
147             }
148              
149              
150             =head2 new
151              
152             Title : new
153             Usage : my $io = Bio::Root::IO->new( -file => 'data.txt' );
154             Function: Create new class instance. It automatically calls C<_initialize_io>.
155             Args : Same named parameters as C<_initialize_io>.
156             Returns : A Bio::Root::IO object
157              
158             =cut
159              
160             sub new {
161 9117     9117 1 21994 my ($caller, @args) = @_;
162 9117         21889 my $self = $caller->SUPER::new(@args);
163 9117         22976 $self->_initialize_io(@args);
164 9110         16156 return $self;
165             }
166              
167              
168             =head2 _initialize_io
169              
170             Title : _initialize_io
171             Usage : $io->_initialize_io(@params);
172             Function: Initializes filehandle and other properties from the parameters.
173             Args : The following named parameters are currently recognized:
174             -file name of file to read or write to
175             -fh file handle to read or write to (mutually exclusive
176             with -file and -string)
177             -input name of file, or filehandle (GLOB or IO::Handle object)
178             to read of write to
179             -string string to read from (will be converted to filehandle)
180             -url name of URL to open
181             -flush boolean flag to autoflush after each write
182             -noclose boolean flag, when set to true will not close a
183             filehandle (must explicitly call close($io->_fh)
184             -retries number of times to try a web fetch before failure
185             -ua_parms when using -url, hashref of key => value parameters
186             to pass to LWP::UserAgent->new(). A useful value might
187             be, for example, {timeout => 60 } (ua defaults to 180s)
188             Returns : True
189              
190             =cut
191              
192             sub _initialize_io {
193 10736     10736   17894 my($self, @args) = @_;
194              
195 10736         31062 $self->_register_for_cleanup(\&_io_cleanup);
196              
197 10736         40614 my ($input, $noclose, $file, $fh, $string,
198             $flush, $url, $retries, $ua_parms) =
199             $self->_rearrange([qw(INPUT NOCLOSE FILE FH STRING FLUSH URL RETRIES UA_PARMS)],
200             @args);
201              
202 10736         18589 my $mode;
203              
204 10736 50       18276 if ($url) {
205 0   0     0 $retries ||= 5;
206              
207 0         0 require LWP::UserAgent;
208 0         0 my $ua = LWP::UserAgent->new(%$ua_parms);
209 0         0 my $http_result;
210 0         0 my ($handle, $tempfile) = $self->tempfile();
211 0         0 CORE::close($handle);
212              
213 0         0 for (my $try = 1 ; $try <= $retries ; $try++) {
214 0         0 $http_result = $ua->get($url, ':content_file' => $tempfile);
215 0 0       0 $self->warn("[$try/$retries] tried to fetch $url, but server ".
216             "threw ". $http_result->code . ". retrying...")
217             if !$http_result->is_success;
218 0 0       0 last if $http_result->is_success;
219             }
220 0 0       0 $self->throw("Failed to fetch $url, server threw ".$http_result->code)
221             if !$http_result->is_success;
222              
223 0         0 $file = $tempfile;
224 0         0 $mode = '>';
225             }
226              
227 10736         13655 delete $self->{'_readbuffer'};
228 10736         15215 delete $self->{'_filehandle'};
229 10736 100       19336 $self->noclose( $noclose) if defined $noclose;
230             # determine whether the input is a file(name) or a stream
231 10736 100       18080 if ($input) {
232 23 50 0     63 if (ref(\$input) eq 'SCALAR') {
    0 0        
233             # we assume that a scalar is a filename
234 23 100 100     54 if ($file && ($file ne $input)) {
235 1         11 $self->throw("Input file given twice: '$file' and '$input' disagree");
236             }
237 22         31 $file = $input;
238             } elsif (ref($input) &&
239             ((ref($input) eq 'GLOB') || $input->isa('IO::Handle'))) {
240             # input is a stream
241 0         0 $fh = $input;
242             } else {
243             # let's be strict for now
244 0         0 $self->throw("Unable to determine type of input $input: ".
245             "not string and not GLOB");
246             }
247             }
248              
249 10735 100 100     23457 if (defined($file) && defined($fh)) {
250 2         8 $self->throw("Providing both a file and a filehandle for reading - ".
251             "only one please!");
252             }
253              
254 10733 100       17265 if ($string) {
255 47 100 100     193 if (defined($file) || defined($fh)) {
256 3         14 $self->throw("File or filehandle provided with -string, ".
257             "please unset if you are using -string as a file");
258             }
259 44 50   4   746 open $fh, '<', \$string or $self->throw("Could not read string: $!");
  4         22  
  4         55  
  4         34  
260             }
261              
262 10730 100 100     26823 if (defined($file) && ($file ne '')) {
263 1143         4585 $self->file($file);
264 1143         3508 ($mode, $file) = $self->cleanfile;
265 1143   100     4734 $mode ||= '<';
266 1143 100       3348 my $action = ($mode =~ m/>/) ? 'write' : 'read';
267 1143         5117 $fh = Symbol::gensym();
268 1143 100       83110 open $fh, $mode, $file or $self->throw("Could not $action file '$file': $!");
269             }
270              
271 10729 100       19281 if (defined $fh) {
272             # check filehandle to ensure it's one of:
273             # a GLOB reference, as in: open(my $fh, "myfile");
274             # an IO::Handle or IO::String object
275             # the UNIVERSAL::can added to fix Bug2863
276 1835 50 66     20438 unless ( ( ref $fh and ( ref $fh eq 'GLOB' ) )
      33        
      66        
      66        
      100        
277             or ( ref $fh and ( UNIVERSAL::can( $fh, 'can' ) )
278             and ( $fh->isa('IO::Handle')
279             or $fh->isa('IO::String') ) )
280             ) {
281 0         0 $self->throw("Object $fh does not appear to be a file handle");
282             }
283 1835 50       4776 if ($HAS_EOL) {
284 0         0 binmode $fh, ':raw:eol(LF-Native)';
285             }
286 1835         6842 $self->_fh($fh); # if $fh not provided, defaults to STDIN and STDOUT
287             }
288              
289 10729 50       33782 $self->_flush_on_write(defined $flush ? $flush : 1);
290              
291 10729         17360 return 1;
292             }
293              
294              
295             =head2 _fh
296              
297             Title : _fh
298             Usage : $io->_fh($newval);
299             Function: Get or set the file handle for the stream encapsulated.
300             Args : Optional filehandle to use
301             Returns : Filehandle for the stream
302              
303             =cut
304              
305             sub _fh {
306 422518     422518   453365 my ($self, $value) = @_;
307 422518 100       532893 if ( defined $value) {
308 1867         4045 $self->{'_filehandle'} = $value;
309             }
310 422518         712499 return $self->{'_filehandle'};
311             }
312              
313              
314             =head2 mode
315              
316             Title : mode
317             Usage : $io->mode();
318             $io->mode(-force => 1);
319             Function: Determine if the object was opened for reading or writing
320             Args : -force: Boolean. Once mode() has been called, the mode is cached for
321             further calls to mode(). Use this argument to override this
322             behavior and re-check the object's mode.
323             Returns : Mode of the object:
324             'r' for readable
325             'w' for writable
326             'rw' for readable and writable
327             '?' if mode could not be determined (e.g. for a -url)
328              
329             =cut
330              
331             sub mode {
332 8     8 1 20 my ($self, %arg) = @_;
333              
334             # Method 1: IO::Handle::fdopen
335             # my $iotest = new IO::Handle;
336             # $iotest->fdopen( dup(fileno($fh)) , 'r' );
337             # if ($iotest->error == 0) { ... }
338             # It did not actually seem to work under any platform, since there would no
339             # error if the filehandle had been opened writable only. It could not be
340             # hacked around when dealing with unseekable (piped) filehandles.
341              
342             # Method 2: readline, a.k.a. the <> operator
343             # no warnings "io";
344             # my $line = <$fh>;
345             # if (defined $line) {
346             # $self->{'_mode'} = 'r';
347             # ...
348             # It did not work well either because <> returns undef, i.e. querying the
349             # mode() after having read an entire file returned 'w'.
350              
351 8 50 33     38 if ( $arg{-force} || not exists $self->{'_mode'} ) {
352             # Determine stream mode
353 8         8 my $mode;
354 8         14 my $fh = $self->_fh;
355 8 50       17 if (defined $fh) {
356             # use fcntl if not Windows-based
357 8 50       23 if ($^O !~ /MSWin32/) {
358 8         30 my $m = fcntl($fh, F_GETFL, 0);
359 8 50       37 $mode = exists $modes{$m & 3} ? $modes{$m & 3} : '?';
360             } else {
361             # Determine read/write status of filehandle
362 276     276   1898 no warnings 'io';
  276         477  
  276         695928  
363 0 0       0 if ( defined( read $fh, my $content, 0 ) ) {
364             # Successfully read 0 bytes
365 0         0 $mode = 'r'
366             }
367 0 0       0 if ( defined( syswrite $fh, '') ) {
368             # Successfully wrote 0 bytes
369 0   0     0 $mode ||= '';
370 0         0 $mode .= 'w';
371             }
372             }
373             } else {
374             # Stream does not have a filehandle... cannot determine mode
375 0         0 $mode = '?';
376             }
377             # Save mode for future use
378 8         18 $self->{'_mode'} = $mode;
379             }
380 8         35 return $self->{'_mode'};
381             }
382              
383              
384             =head2 file
385              
386             Title : file
387             Usage : $io->file('>'.$file);
388             my $file = $io->file;
389             Function: Get or set the name of the file to read or write.
390             Args : Optional file name (including its mode, e.g. '<' for reading or '>'
391             for writing)
392             Returns : A string representing the filename and its mode.
393              
394             =cut
395              
396             sub file {
397 1149     1149 1 2462 my ($self, $value) = @_;
398 1149 100       2680 if ( defined $value) {
399 1143         2324 $self->{'_file'} = $value;
400             }
401 1149         1735 return $self->{'_file'};
402             }
403              
404              
405             =head2 cleanfile
406              
407             Title : cleanfile
408             Usage : my ($mode, $file) = $io->cleanfile;
409             Function: Get the name of the file to read or write, stripped of its mode
410             ('>', '<', '+>', '>>', etc).
411             Args : None
412             Returns : In array context, an array of the mode and the clean filename.
413              
414             =cut
415              
416             sub cleanfile {
417 1149     1149 1 1984 my ($self) = @_;
418 1149         8217 return ($self->{'_file'} =~ m/^ (\+?[><]{1,2})?\s*(.*) $/x);
419             }
420              
421              
422             =head2 format
423              
424             Title : format
425             Usage : $io->format($newval)
426             Function: Get the format of a Bio::Root::IO sequence file or filehandle. Every
427             object inheriting Bio::Root::IO is guaranteed to have a format.
428             Args : None
429             Returns : Format of the file or filehandle, e.g. fasta, fastq, genbank, embl.
430              
431             =cut
432              
433             sub format {
434 12     12 1 82 my ($self) = @_;
435 12         50 my $format = (split '::', ref($self))[-1];
436 12         56 return $format;
437             }
438              
439              
440             =head2 variant
441              
442             Title : format
443             Usage : $io->format($newval)
444             Function: Get the variant of a Bio::Root::IO sequence file or filehandle.
445             The format variant depends on the specific format used. Note that
446             not all formats have variants. Also, the Bio::Root::IO-implementing
447             modules that require access to variants need to define a global hash
448             that has the allowed variants as its keys.
449             Args : None
450             Returns : Variant of the file or filehandle, e.g. sanger, solexa or illumina for
451             the fastq format, or undef for formats that do not have variants.
452              
453             =cut
454              
455             sub variant {
456 70151     70151 1 71029 my ($self, $variant) = @_;
457 70151 100       74353 if (defined $variant) {
458 70         121 $variant = lc $variant;
459 70         165 my $var_name = '%'.ref($self).'::variant';
460 70         3829 my %ok_variants = eval $var_name; # e.g. %Bio::Assembly::IO::ace::variant
461 70 50       316 if (scalar keys %ok_variants == 0) {
462 0         0 $self->throw("Could not validate variant because global variant ".
463             "$var_name was not set or was empty\n");
464             }
465 70 50       168 if (not exists $ok_variants{$variant}) {
466 0         0 $self->throw("$variant is not a valid variant of the " .
467             $self->format . ' format');
468             }
469 70         246 $self->{variant} = $variant;
470             }
471 70151         135085 return $self->{variant};
472             }
473              
474              
475             =head2 _print
476              
477             Title : _print
478             Usage : $io->_print(@lines)
479             Function: Print lines of text to the IO stream object.
480             Args : List of strings to print
481             Returns : True on success, undef on failure
482              
483             =cut
484              
485             sub _print {
486 27585     27585   26275 my $self = shift;
487 27585   50     31262 my $fh = $self->_fh() || \*STDOUT;
488 27585         53028 my $ret = print $fh @_;
489 27585         58645 return $ret;
490             }
491              
492              
493             =head2 _insert
494              
495             Title : _insert
496             Usage : $io->_insert($string,1)
497             Function: Insert some text in a file at the given line number (1-based).
498             Args : * string to write in file
499             * line number to insert the string at
500             Returns : True
501              
502             =cut
503              
504             sub _insert {
505 2     2   7 my ($self, $string, $line_num) = @_;
506             # Line number check
507 2 50       10 if ($line_num < 1) {
508 0         0 $self->throw("Could not insert text at line $line_num: the minimum ".
509             "line number possible is 1.");
510             }
511             # File check
512 2         8 my ($mode, $file) = $self->cleanfile;
513 2 50       8 if (not defined $file) {
514 0         0 $self->throw('Could not insert a line: IO object was initialized with '.
515             'something else than a file.');
516             }
517             # Everything that needs to be written is written before we read it
518 2         10 $self->flush;
519              
520             # Edit the file line by line (no slurping)
521 2         5 $self->close;
522 2         4 my $temp_file;
523 2         4 my $number = 0;
524 2         84 while (-e "$file.$number.temp") {
525 0         0 $number++;
526             }
527 2         7 $temp_file = "$file.$number.temp";
528 2         10 copy($file, $temp_file);
529 2 50       445 open my $fh1, '<', $temp_file or $self->throw("Could not read temporary file '$temp_file': $!");
530 2 50       781 open my $fh2, '>', $file or $self->throw("Could not write file '$file': $!");
531 2         30 while (my $line = <$fh1>) {
532 2 100       10 if ($. == $line_num) { # right line for new data
533 1         7 print $fh2 $string . $line;
534             }
535             else {
536 1         7 print $fh2 $line;
537             }
538             }
539 2         10 CORE::close $fh1;
540 2         45 CORE::close $fh2;
541 2 50       74 unlink $temp_file or $self->throw("Could not delete temporary file '$temp_file': $!");
542              
543             # Line number check (again)
544 2 50 33     17 if ( $. > 0 && $line_num > $. ) {
545 0         0 $self->throw("Could not insert text at line $line_num: there are only ".
546             "$. lines in file '$file'");
547             }
548             # Re-open the file in append mode to be ready to add text at the end of it
549             # when the next _print() statement comes
550 2 50       51 open my $new_fh, '>>', $file or $self->throw("Could not append to file '$file': $!");
551 2         10 $self->_fh($new_fh);
552             # If file is empty and we're inserting at line 1, simply append text to file
553 2 100 66     16 if ( $. == 0 && $line_num == 1 ) {
554 1         6 $self->_print($string);
555             }
556 2         18 return 1;
557             }
558              
559              
560             =head2 _readline
561              
562             Title : _readline
563             Usage : local $Bio::Root::IO::HAS_EOL = 1;
564             my $io = Bio::Root::IO->new(-file => 'data.txt');
565             my $line = $io->_readline();
566             $io->close;
567             Function: Read a line of input and normalize all end of line characters.
568              
569             End of line characters are typically "\n" on Linux platforms, "\r\n"
570             on Windows and "\r" on older Mac OS. By default, the _readline()
571             method uses the value of $/, Perl's input record separator, to
572             detect the end of each line. This means that you will not get the
573             expected lines if your input has Mac-formatted end of line characters.
574             Also, note that the current implementation does not handle pushed
575             back input correctly unless the pushed back input ends with the
576             value of $/. For each line parsed, its line ending, e.g. "\r\n" is
577             converted to "\n", unless you provide the -raw argument.
578              
579             Altogether it is easier to let the PerlIO::eol module automatically
580             detect the proper end of line character and normalize it to "\n". Do
581             so by setting $Bio::Root::IO::HAS_EOL to 1.
582              
583             Args : -raw : Avoid converting end of line characters to "\n" This option
584             has no effect when using $Bio::Root::IO::HAS_EOL = 1.
585             Returns : Line of input, or undef when there is nothing to read anymore
586              
587             =cut
588              
589             sub _readline {
590 379112     379112   467924 my ($self, %param) = @_;
591 379112 100       450794 my $fh = $self->_fh or return;
592 379100         356386 my $line;
593              
594             # if the buffer been filled by _pushback then return the buffer
595             # contents, rather than read from the filehandle
596 379100 100       324471 if( @{$self->{'_readbuffer'} || [] } ) {
  379100 100       808859  
597 1483         1637 $line = shift @{$self->{'_readbuffer'}};
  1483         3041  
598             } else {
599 377617         644650 $line = <$fh>;
600             }
601              
602             # Note: In Windows the "-raw" parameter has no effect, because Perl already discards
603             # the '\r' from the line when reading in text mode from the filehandle
604             # ($line = <$fh>), and put it back automatically when printing
605 379100 100 66     1194565 if( !$HAS_EOL && !$param{-raw} && (defined $line) ) {
      100        
606             # don't strip line endings if -raw or $HAS_EOL is specified
607 378525         494364 $line =~ s/\015\012/\012/g; # Change all CR/LF pairs to LF
608 378525 50       573891 $line =~ tr/\015/\n/ unless $ONMAC; # Change all single CRs to NEWLINE
609             }
610 379100         944091 return $line;
611             }
612              
613              
614             =head2 _pushback
615              
616             Title : _pushback
617             Usage : $io->_pushback($newvalue)
618             Function: Puts a line previously read with _readline back into a buffer.
619             buffer can hold as many lines as system memory permits.
620              
621             Note that this is only supported for pushing back data ending with
622             the current, localized value of $/. Using this method to push
623             modified data back onto the buffer stack is not supported; see bug
624             843.
625              
626             Args : newvalue
627             Returns : True
628              
629             =cut
630              
631             # fix for bug 843, this reveals some unsupported behavior
632              
633             #sub _pushback {
634             # my ($self, $value) = @_;
635             # if (index($value, $/) >= 0) {
636             # push @{$self->{'_readbuffer'}}, $value;
637             # } else {
638             # $self->throw("Pushing modifed data back not supported: $value");
639             # }
640             #}
641              
642             sub _pushback {
643 1504     1504   2757 my ($self, $value) = @_;
644 1504 100       2846 return unless $value;
645 1502         1881 unshift @{$self->{'_readbuffer'}}, $value;
  1502         3779  
646 1502         2711 return 1;
647             }
648              
649              
650             =head2 close
651              
652             Title : close
653             Usage : $io->close()
654             Function: Closes the file handle associated with this IO instance,
655             excepted if -noclose was specified.
656             Args : None
657             Returns : True
658              
659             =cut
660              
661             sub close {
662 11077     11077 1 16324 my ($self) = @_;
663              
664             # do not close if we explicitly asked not to
665 11077 100       21553 return if $self->noclose;
666              
667 11028 100       24249 if( defined( my $fh = $self->{'_filehandle'} )) {
668 1617         5591 $self->flush;
669 1617 50 66     11664 return if ref $fh eq 'GLOB' && (
      66        
670             \*STDOUT == $fh || \*STDERR == $fh || \*STDIN == $fh
671             );
672              
673             # don't close IO::Strings
674 1616 100 66     29180 CORE::close $fh unless ref $fh && $fh->isa('IO::String');
675             }
676 11027         17582 $self->{'_filehandle'} = undef;
677 11027         13687 delete $self->{'_readbuffer'};
678 11027         23422 return 1;
679             }
680              
681              
682             =head2 flush
683              
684             Title : flush
685             Usage : $io->flush()
686             Function: Flushes the filehandle
687             Args : None
688             Returns : True
689              
690             =cut
691              
692             sub flush {
693 2278     2278 1 4125 my ($self) = shift;
694              
695 2278 50       6185 if( !defined $self->{'_filehandle'} ) {
696 0         0 $self->throw("Flush failed: no filehandle was active");
697             }
698              
699 2278 100       11485 if( ref($self->{'_filehandle'}) =~ /GLOB/ ) {
700 1225         5060 my $oldh = select($self->{'_filehandle'});
701 1225         8149 $| = 1;
702 1225         4012 select($oldh);
703             } else {
704 1053         5570 $self->{'_filehandle'}->flush();
705             }
706 2278         5443 return 1;
707             }
708              
709              
710             =head2 noclose
711              
712             Title : noclose
713             Usage : $io->noclose($newval)
714             Function: Get or set the NOCLOSE flag - setting this to true will prevent a
715             filehandle from being closed when an object is cleaned up or
716             explicitly closed.
717             Args : Optional new value (a scalar or undef)
718             Returns : Value of noclose (a scalar)
719              
720             =cut
721              
722             sub noclose {
723 11110     11110 1 13909 my $self = shift;
724 11110 100       20830 return $self->{'_noclose'} = shift if @_;
725 11077         22981 return $self->{'_noclose'};
726             }
727              
728              
729             =head2 _io_cleanup
730              
731             =cut
732              
733             sub _io_cleanup {
734 9404     9404   14372 my ($self) = @_;
735 9404         22467 $self->close();
736 9404         19262 my $v = $self->verbose;
737              
738             # we are planning to cleanup temp files no matter what
739 9404 50 66     22294 if ( exists($self->{'_rootio_tempfiles'})
      66        
740             and ref($self->{'_rootio_tempfiles'}) =~ /array/i
741             and not $self->save_tempfiles
742             ) {
743 34 50       59 if( $v > 0 ) {
744             warn( "going to remove files ",
745 0         0 join(",", @{$self->{'_rootio_tempfiles'}}),
  0         0  
746             "\n");
747             }
748 34         37 unlink (@{$self->{'_rootio_tempfiles'}} );
  34         557  
749             }
750             # cleanup if we are not using File::Temp
751 9404 0 33     48981 if ( $self->{'_cleanuptempdir'}
      0        
      0        
752             and exists($self->{'_rootio_tempdirs'})
753             and ref($self->{'_rootio_tempdirs'}) =~ /array/i
754             and not $self->save_tempfiles
755             ) {
756 0 0       0 if( $v > 0 ) {
757             warn( "going to remove dirs ",
758 0         0 join(",", @{$self->{'_rootio_tempdirs'}}),
  0         0  
759             "\n");
760             }
761 0         0 $self->rmtree( $self->{'_rootio_tempdirs'});
762             }
763             }
764              
765              
766             =head2 exists_exe
767              
768             Title : exists_exe
769             Usage : $exists = $io->exists_exe('clustalw');
770             $exists = Bio::Root::IO->exists_exe('clustalw')
771             $exists = Bio::Root::IO::exists_exe('clustalw')
772             Function: Determines whether the given executable exists either as file
773             or within the path environment. The latter requires File::Spec
774             to be installed.
775             On Win32-based system, .exe is automatically appended to the program
776             name unless the program name already ends in .exe.
777             Args : Name of the executable
778             Returns : 1 if the given program is callable as an executable, and 0 otherwise
779              
780             =cut
781              
782             sub exists_exe {
783 3     3 1 8 my ($self, $exe) = @_;
784 3 50       7 $self->throw("Must pass a defined value to exists_exe") unless defined $exe;
785 3 50 33     9 $exe = $self if (!(ref($self) || $exe));
786 3 50 33     14 $exe .= '.exe' if(($^O =~ /mswin/i) && ($exe !~ /\.(exe|com|bat|cmd)$/i));
787 3 100 100     36 return $exe if ( -f $exe && -x $exe ); # full path and exists
788              
789             # Ewan's comment. I don't think we need this. People should not be
790             # asking for a program with a pathseparator starting it
791             # $exe =~ s/^$PATHSEP//;
792              
793             # Not a full path, or does not exist. Let's see whether it's in the path.
794 2 50       6 if($FILESPECLOADED) {
795 2         49 for my $dir (File::Spec->path()) {
796 18         49 my $f = Bio::Root::IO->catfile($dir, $exe);
797 18 50 33     348 return $f if( -f $f && -x $f );
798             }
799             }
800 2         12 return 0;
801             }
802              
803              
804             =head2 tempfile
805              
806             Title : tempfile
807             Usage : my ($handle,$tempfile) = $io->tempfile();
808             Function: Create a temporary filename and a handle opened for reading and
809             writing.
810             Caveats: If you do not have File::Temp on your system you should
811             avoid specifying TEMPLATE and SUFFIX.
812             Args : Named parameters compatible with File::Temp: DIR (defaults to
813             $Bio::Root::IO::TEMPDIR), TEMPLATE, SUFFIX.
814             Returns : A 2-element array, consisting of temporary handle and temporary
815             file name.
816              
817             =cut
818              
819             sub tempfile {
820 40     40 1 1931 my ($self, @args) = @_;
821 40         54 my ($tfh, $file);
822 40         130 my %params = @args;
823              
824             # map between naming with and without dash
825 40         98 for my $key (keys(%params)) {
826 51 50       110 if( $key =~ /^-/ ) {
827 0         0 my $v = $params{$key};
828 0         0 delete $params{$key};
829 0         0 $params{uc(substr($key,1))} = $v;
830             } else {
831             # this is to upper case
832 51         71 my $v = $params{$key};
833 51         62 delete $params{$key};
834 51         116 $params{uc($key)} = $v;
835             }
836             }
837 40 100       130 $params{'DIR'} = $TEMPDIR if(! exists($params{'DIR'}));
838 40 100 66     140 unless (exists $params{'UNLINK'} &&
      66        
839             defined $params{'UNLINK'} &&
840             ! $params{'UNLINK'} ) {
841 35         78 $params{'UNLINK'} = 1;
842             } else {
843 5         8 $params{'UNLINK'} = 0;
844             }
845              
846 40 50       64 if($FILETEMPLOADED) {
847 40 100       73 if(exists($params{'TEMPLATE'})) {
848 4         6 my $template = $params{'TEMPLATE'};
849 4         4 delete $params{'TEMPLATE'};
850 4         14 ($tfh, $file) = File::Temp::tempfile($template, %params);
851             } else {
852 36         122 ($tfh, $file) = File::Temp::tempfile(%params);
853             }
854             } else {
855 0         0 my $dir = $params{'DIR'};
856             $file = $self->catfile(
857             $dir,
858             (exists($params{'TEMPLATE'}) ?
859             $params{'TEMPLATE'} :
860 0 0 0     0 sprintf( "%s.%s.%s", $ENV{USER} || 'unknown', $$, $TEMPCOUNTER++))
861             );
862              
863             # sneakiness for getting around long filenames on Win32?
864 0 0       0 if( $HAS_WIN32 ) {
865 0         0 $file = Win32::GetShortPathName($file);
866             }
867              
868             # Try to make sure this will be marked close-on-exec
869             # XXX: Win32 doesn't respect this, nor the proper fcntl,
870             # but may have O_NOINHERIT. This may or may not be in Fcntl.
871 0         0 local $^F = 2;
872             # Store callers umask
873 0         0 my $umask = umask();
874             # Set a known umaskr
875 0         0 umask(066);
876             # Attempt to open the file
877 0 0       0 if ( sysopen($tfh, $file, $OPENFLAGS, 0600) ) {
878             # Reset umask
879 0         0 umask($umask);
880             } else {
881 0         0 $self->throw("Could not write temporary file '$file': $!");
882             }
883             }
884              
885 40 100       10986 if( $params{'UNLINK'} ) {
886 35         46 push @{$self->{'_rootio_tempfiles'}}, $file;
  35         89  
887             }
888              
889 40 100       178 return wantarray ? ($tfh,$file) : $tfh;
890             }
891              
892              
893             =head2 tempdir
894              
895             Title : tempdir
896             Usage : my ($tempdir) = $io->tempdir(CLEANUP=>1);
897             Function: Creates and returns the name of a new temporary directory.
898              
899             Note that you should not use this function for obtaining "the"
900             temp directory. Use $Bio::Root::IO::TEMPDIR for that. Calling this
901             method will in fact create a new directory.
902              
903             Args : args - ( key CLEANUP ) indicates whether or not to cleanup
904             dir on object destruction, other keys as specified by File::Temp
905             Returns : The name of a new temporary directory.
906              
907             =cut
908              
909             sub tempdir {
910 31     31 1 62 my ($self, @args) = @_;
911 31 50 33     275 if ($FILETEMPLOADED && File::Temp->can('tempdir')) {
912 31         94 return File::Temp::tempdir(@args);
913             }
914              
915             # we have to do this ourselves, not good
916             # we are planning to cleanup temp files no matter what
917 0         0 my %params = @args;
918 0         0 print "cleanup is " . $params{CLEANUP} . "\n";
919             $self->{'_cleanuptempdir'} = ( defined $params{CLEANUP} &&
920 0   0     0 $params{CLEANUP} == 1);
921             my $tdir = $self->catfile( $TEMPDIR,
922             sprintf("dir_%s-%s-%s",
923 0   0     0 $ENV{USER} || 'unknown',
924             $$,
925             $TEMPCOUNTER++));
926 0         0 mkdir($tdir, 0755);
927 0         0 push @{$self->{'_rootio_tempdirs'}}, $tdir;
  0         0  
928 0         0 return $tdir;
929             }
930              
931              
932             =head2 catfile
933              
934             Title : catfile
935             Usage : $path = Bio::Root::IO->catfile(@dirs, $filename);
936             Function: Constructs a full pathname in a cross-platform safe way.
937              
938             If File::Spec exists on your system, this routine will merely
939             delegate to it. Otherwise it tries to make a good guess.
940              
941             You should use this method whenever you construct a path name
942             from directory and filename. Otherwise you risk cross-platform
943             compatibility of your code.
944              
945             You can call this method both as a class and an instance method.
946              
947             Args : components of the pathname (directories and filename, NOT an
948             extension)
949             Returns : a string
950              
951             =cut
952              
953             sub catfile {
954 8868     8868 1 22699 my ($self, @args) = @_;
955              
956 8868 50       107309 return File::Spec->catfile(@args) if $FILESPECLOADED;
957             # this is clumsy and not very appealing, but how do we specify the
958             # root directory?
959 0 0       0 if($args[0] eq '/') {
960 0         0 $args[0] = $ROOTDIR;
961             }
962 0         0 return join($PATHSEP, @args);
963             }
964              
965              
966             =head2 rmtree
967              
968             Title : rmtree
969             Usage : Bio::Root::IO->rmtree($dirname );
970             Function: Remove a full directory tree
971              
972             If File::Path exists on your system, this routine will merely
973             delegate to it. Otherwise it runs a local version of that code.
974              
975             You should use this method to remove directories which contain
976             files.
977              
978             You can call this method both as a class and an instance method.
979              
980             Args : roots - rootdir to delete or reference to list of dirs
981              
982             verbose - a boolean value, which if TRUE will cause
983             C to print a message each time it
984             examines a file, giving the name of the file, and
985             indicating whether it's using C or
986             C to remove it, or that it's skipping it.
987             (defaults to FALSE)
988              
989             safe - a boolean value, which if TRUE will cause C
990             to skip any files to which you do not have delete
991             access (if running under VMS) or write access (if
992             running under another OS). This will change in the
993             future when a criterion for 'delete permission'
994             under OSs other than VMS is settled. (defaults to
995             FALSE)
996             Returns : number of files successfully deleted
997              
998             =cut
999              
1000             # taken straight from File::Path VERSION = "1.0403"
1001             sub rmtree {
1002 0     0 1 0 my ($self, $roots, $verbose, $safe) = @_;
1003 0 0       0 if ( $FILEPATHLOADED ) {
1004 0         0 return File::Path::rmtree ($roots, $verbose, $safe);
1005             }
1006              
1007 0   0     0 my $force_writable = ($^O eq 'os2' || $^O eq 'dos' || $^O eq 'MSWin32' ||
1008             $^O eq 'amigaos' || $^O eq 'cygwin');
1009 0         0 my $Is_VMS = $^O eq 'VMS';
1010              
1011 0         0 my @files;
1012 0         0 my $count = 0;
1013 0   0     0 $verbose ||= 0;
1014 0   0     0 $safe ||= 0;
1015 0 0 0     0 if ( defined($roots) && length($roots) ) {
1016 0 0       0 $roots = [$roots] unless ref $roots;
1017             } else {
1018 0         0 $self->warn("No root path(s) specified\n");
1019 0         0 return 0;
1020             }
1021              
1022 0         0 my $root;
1023 0         0 for $root (@{$roots}) {
  0         0  
1024 0         0 $root =~ s#/\z##;
1025 0 0       0 (undef, undef, my $rp) = lstat $root or next;
1026 0         0 $rp &= 07777; # don't forget setuid, setgid, sticky bits
1027 0 0       0 if ( -d _ ) {
1028             # notabene: 0777 is for making readable in the first place,
1029             # it's also intended to change it to writable in case we have
1030             # to recurse in which case we are better than rm -rf for
1031             # subtrees with strange permissions
1032 0 0 0     0 chmod(0777, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
    0          
1033             or $self->warn("Could not make directory '$root' read+writable: $!")
1034             unless $safe;
1035 0 0       0 if (opendir DIR, $root){
1036 0         0 @files = readdir DIR;
1037 0         0 closedir DIR;
1038             } else {
1039 0         0 $self->warn("Could not read directory '$root': $!");
1040 0         0 @files = ();
1041             }
1042              
1043             # Deleting large numbers of files from VMS Files-11 filesystems
1044             # is faster if done in reverse ASCIIbetical order
1045 0 0       0 @files = reverse @files if $Is_VMS;
1046 0 0       0 ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS;
1047 0         0 @files = map("$root/$_", grep $_!~/^\.{1,2}\z/s,@files);
1048 0         0 $count += $self->rmtree([@files],$verbose,$safe);
1049 0 0 0     0 if ($safe &&
    0          
1050             ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
1051 0 0       0 print "skipped '$root'\n" if $verbose;
1052 0         0 next;
1053             }
1054 0 0 0     0 chmod 0777, $root
1055             or $self->warn("Could not make directory '$root' writable: $!")
1056             if $force_writable;
1057 0 0       0 print "rmdir '$root'\n" if $verbose;
1058 0 0       0 if (rmdir $root) {
1059 0         0 ++$count;
1060             }
1061             else {
1062 0         0 $self->warn("Could not remove directory '$root': $!");
1063 0 0       0 chmod($rp, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
    0          
1064             or $self->warn("and can't restore permissions to "
1065             . sprintf("0%o",$rp) . "\n");
1066             }
1067             }
1068             else {
1069 0 0 0     0 if ( $safe
    0 0        
1070             and ($Is_VMS ? !&VMS::Filespec::candelete($root)
1071             : !(-l $root || -w $root))
1072             ) {
1073 0 0       0 print "skipped '$root'\n" if $verbose;
1074 0         0 next;
1075             }
1076 0 0 0     0 chmod 0666, $root
1077             or $self->warn( "Could not make file '$root' writable: $!")
1078             if $force_writable;
1079 0 0       0 warn "unlink '$root'\n" if $verbose;
1080             # delete all versions under VMS
1081 0         0 for (;;) {
1082 0 0       0 unless (unlink $root) {
1083 0         0 $self->warn("Could not unlink file '$root': $!");
1084 0 0       0 if ($force_writable) {
1085 0 0       0 chmod $rp, $root
1086             or $self->warn("and can't restore permissions to "
1087             . sprintf("0%o",$rp) . "\n");
1088             }
1089 0         0 last;
1090             }
1091 0         0 ++$count;
1092 0 0 0     0 last unless $Is_VMS && lstat $root;
1093             }
1094             }
1095             }
1096              
1097 0         0 return $count;
1098             }
1099              
1100              
1101             =head2 _flush_on_write
1102              
1103             Title : _flush_on_write
1104             Usage : $io->_flush_on_write($newval)
1105             Function: Boolean flag to indicate whether to flush
1106             the filehandle on writing when the end of
1107             a component is finished (Sequences, Alignments, etc)
1108             Args : Optional new value
1109             Returns : Value of _flush_on_write
1110              
1111             =cut
1112              
1113             sub _flush_on_write {
1114 11388     11388   18028 my ($self, $value) = @_;
1115 11388 100       21076 if (defined $value) {
1116 10730         17771 $self->{'_flush_on_write'} = $value;
1117             }
1118 11388         16803 return $self->{'_flush_on_write'};
1119             }
1120              
1121              
1122             =head2 save_tempfiles
1123              
1124             Title : save_tempfiles
1125             Usage : $io->save_tempfiles(1)
1126             Function: Boolean flag to indicate whether to retain tempfiles/tempdir
1127             Args : Value evaluating to TRUE or FALSE
1128             Returns : Boolean value : 1 = save tempfiles/tempdirs, 0 = remove (default)
1129              
1130             =cut
1131              
1132             sub save_tempfiles {
1133 34     34 1 50 my $self = shift;
1134 34 50       65 if (@_) {
1135 0         0 my $value = shift;
1136 0 0       0 $self->{save_tempfiles} = $value ? 1 : 0;
1137             }
1138 34   50     135 return $self->{save_tempfiles} || 0;
1139             }
1140              
1141              
1142             1;