File Coverage

blib/lib/Term/ProgressBar.pm
Criterion Covered Total %
statement 205 247 83.0
branch 94 140 67.1
condition 32 45 71.1
subroutine 23 25 92.0
pod 5 9 55.5
total 359 466 77.0


line stmt bran cond sub pod time code
1             package Term::ProgressBar;
2              
3 11     11   123701 use strict;
  11         27  
  11         261  
4 11     11   51 use warnings;
  11         17  
  11         785  
5              
6             our $VERSION = '2.21';
7              
8             #XXX TODO Redo original test with count=20
9             # Amount Output
10             # Amount Prefix/Suffix
11             # Tinker with $0?
12             # Test use of last_update (with update(*undef*)) with scales
13             # Choice of FH other than STDERR
14             # If no term, output no progress bar; just progress so far
15             # Use of simple term with v2.0 bar
16             # If name is wider than term, trim name
17             # Don't update progress bar on new?
18              
19             =head1 NAME
20              
21             Term::ProgressBar - provide a progress meter on a standard terminal
22              
23             =head1 VERSION
24              
25             Version 2.21
26              
27             =head1 SYNOPSIS
28              
29             use Term::ProgressBar;
30              
31             my $progress = Term::ProgressBar->new ({count => 10_000});
32             $progress->update(5_000);
33              
34             =head1 DESCRIPTION
35              
36             Term::ProgressBar provides a simple progress bar on the terminal, to let the
37             user know that something is happening, roughly how much stuff has been done,
38             and maybe an estimate at how long remains.
39              
40             A typical use sets up the progress bar with a number of items to do, and then
41             calls L to update the bar whenever an item is processed.
42              
43             Often, this would involve updating the progress bar many times with no
44             user-visible change. To avoid unnecessary work, the update method returns a
45             value, being the update value at which the user will next see a change. By
46             only calling update when the current value exceeds the next update value, the
47             call overhead is reduced.
48              
49             Remember to call the C<< $progress->update($max_value) >> when the job is done
50             to get a nice 100% done bar.
51              
52             A progress bar by default is simple; it just goes from left-to-right, filling
53             the bar with '=' characters. These are called B characters. For
54             long-running jobs, this may be too slow, so two additional features are
55             available: a linear completion time estimator, and/or a B character:
56             this is a character that I from left-to-right on the progress bar (it
57             does not fill it as the major character does), traversing once for each
58             major-character added. This exponentially increases the granularity of the
59             bar for the same width.
60              
61             =head1 EXAMPLES
62              
63             =head2 A really simple use
64              
65             #!/usr/bin/perl
66              
67             use Term::ProgressBar 2.00;
68             use constant MAX => 100_000;
69              
70             my $progress = Term::ProgressBar->new(MAX);
71              
72             for (0..MAX) {
73             my $is_power = 0;
74             for (my $i = 0; 2**$i <= $_; $i++) {
75             $is_power = 1 if 2**$i == $_;
76             }
77              
78             if ($is_power) {
79             $progress->update($_);
80             }
81             }
82              
83             see eg/simle_use.pl
84              
85             Here is a simple example. The process considers all the numbers between 0 and
86             MAX, and updates the progress bar whenever it finds one. Note that the
87             progress bar update will be very erratic. See below for a smoother example.
88             Note also that the progress bar will never complete; see below to solve this.
89              
90             The complete text of this example is in F in the
91             distribution set (it is not installed as part of the module).
92              
93             =head2 A smoother bar update
94              
95             my $progress = Term::ProgressBar->new($max);
96              
97             for (0..$max) {
98             my $is_power = 0;
99             for (my $i = 0; 2**$i <= $_; $i++) {
100             $is_power = 1 if 2**$i == $_;
101             }
102              
103             $progress->update($_)
104             }
105              
106             See eg/smooth_bar.pl
107              
108             This example calls update for each value considered. This will result in a
109             much smoother progress update, but more program time is spent updating the bar
110             than doing the "real" work. See below to remedy this. This example does
111             I call C<< $progress->update($max); >> at the end, since it is
112             unnecessary, and ProgressBar will throw an exception at an attempt to update a
113             finished bar.
114              
115             The complete text of this example is in F in the
116             distribution set (it is not installed as part of the module.
117              
118             =head2 A (much) more efficient update
119              
120             my $progress = Term::ProgressBar->new({name => 'Powers', count => $max, remove => 1});
121             $progress->minor(0);
122             my $next_update = 0;
123              
124             for (0..$max) {
125             my $is_power = 0;
126             for (my $i = 0; 2**$i <= $_; $i++) {
127             $is_power = 1 if 2**$i == $_;
128             }
129              
130             $next_update = $progress->update($_) if $_ >= $next_update;
131             }
132              
133             $progress->update($max) if $max >= $next_update;
134              
135             This example does two things to improve efficiency: firstly, it uses the value
136             returned by L to only call it again when needed; secondly, it
137             switches off the use of minor characters to update a lot less frequently (C<<
138             $progress->minor(0); >>. The use of the return value of L
139             means that the call of C<< $progress->update($max); >> at the end is required
140             to ensure that the bar ends on 100%, which gives the user a nice feeling.
141              
142             This example also sets the name of the progress bar.
143              
144             This example also demonstrates the use of the 'remove' flag, which removes the
145             progress bar from the terminal when done.
146              
147             The complete text of this example is in F in the
148             distribution set (it is not installed as part of the module.
149              
150             =head2 When the maximum number of items is sometimes unknown
151              
152             Sometimes you may wish to use the progress bar when the number of items may or
153             may not be known. One common example is when you write a script that can take
154             input piped from the output of another command, and then pipe the output to yet
155             another command. eg:
156              
157             some_command --arg value | my_script.pl | some_other_command
158              
159             Or ...
160              
161             my_script.pl input_file output_file
162              
163             This example shows how you can iterate over a file specified on the command line
164             with the progress bar. Since the input file may be read from STDIN, the number
165             of lines may not be known. Term::ProgressBar handles this by just taking '-1' as
166             the count value and with no further changes to the code. By calling update
167             with the same count value, you ensure the progress bar is removed afterwards.
168              
169             my $input_file = shift;
170             my $output_file = shift;
171             my $in_fh = \*STDIN;
172             my $out_fh = \*STDOUT;
173             my $message_fh = \*STDERR;
174             my $num_lines = -1;
175              
176             if (defined($input_file) and $input_file ne '-') {
177             open($in_fh, $input_file) or die "Couldn't open file, '$input_file': $!";
178             my $wc_output = `wc -l $input_file`;
179             chomp($wc_output);
180             $wc_output =~ /^\s*(\d+)(\D.*)?/ or die "Couldn't parse wc output: $wc_output";
181             $num_lines = $1;
182             }
183              
184             if(defined($output_file)) {
185             !-f $output_file or die "Specified output file, '$output_file', already exists";
186             open($out_fh, '>', $output_file) or die "Couldn't open output file, '$output_file': $!";
187             }
188              
189             my $progress = Term::ProgressBar->new({
190             name => 'file processor',
191             count => $num_lines,
192             remove => 1,
193             fh => $message_fh,
194             });
195              
196             while (my $line = <$in_fh>) {
197             chomp($line);
198             print $out_fh "I found a line: $line\n";
199             $progress->message("Found 10000!") if($line =~ /10000/);
200             $progress->update();
201             }
202              
203             $progress->update($num_lines);
204              
205             print $message_fh "Finished\n";
206              
207             When the file is defined explicitly, the progress bar displays the linewise
208             progress through the file. Since the progress bar by default prints output to
209             stderr, your scripts output to STDOUT will not be affected.
210              
211             =head2 Using Completion Time Estimation
212              
213             my $progress = Term::ProgressBar->new({
214             name => 'Powers',
215             count => $max,
216             ETA => 'linear',
217             });
218             $progress->max_update_rate(1);
219             my $next_update = 0;
220              
221             for (0..$max) {
222             my $is_power = 0;
223             for (my $i = 0; 2**$i <= $_; $i++) {
224             if ( 2**$i == $_ ) {
225             $is_power = 1;
226             $progress->message(sprintf "Found %8d to be 2 ** %2d", $_, $i);
227             }
228             }
229              
230             $next_update = $progress->update($_)
231             if $_ > $next_update;
232             }
233             $progress->update($max)
234             if $max >= $next_update;
235              
236             This example uses the L option to switch on completion estimation.
237             Also, the update return is tuned to try to update the bar approximately once
238             per second, with the L call. See the
239             documentation for the L method for details of the format(s) used.
240              
241             This example also provides an example of the use of the L
242             function to output messages to the same filehandle whilst keeping the progress bar intact
243              
244             The complete text of this example is in F in the
245             distribution set (it is not installed as part of the module.
246              
247             =cut
248              
249 11     11   55 use Carp qw( croak );
  11         17  
  11         550  
250 11     11   3367 use Class::MethodMaker 1.02 qw( );
  11         130118  
  11         313  
251 11     11   4010 use Fatal qw( open sysopen close seek );
  11         109913  
  11         45  
252 11     11   21977 use POSIX qw( ceil strftime );
  11         39755  
  11         55  
253              
254 11     11   12236 use constant MINUTE => 60;
  11         21  
  11         696  
255 11     11   61 use constant HOUR => 60 * MINUTE;
  11         21  
  11         504  
256 11     11   56 use constant DAY => 24 * HOUR;
  11         38  
  11         558  
257              
258             # The point past which to give ETA of just date, rather than time
259 11     11   73 use constant ETA_DATE_CUTOFF => 3 * DAY;
  11         22  
  11         495  
260             # The point past which to give ETA of time, rather time left
261 11     11   58 use constant ETA_TIME_CUTOFF => 10 * MINUTE;
  11         22  
  11         424  
262             # The ratio prior to which to not dare any estimates
263 11     11   50 use constant PREDICT_RATIO => 0.01;
  11         22  
  11         718  
264              
265 11         731 use constant DEFAULTS => {
266             lbrack => '[',
267             rbrack => ']',
268             minor_char => '*',
269             major_char => '=',
270             fh => \*STDERR,
271             name => undef,
272             ETA => undef,
273             max_update_rate => 0.5,
274              
275             # The following defaults are never used, but the keys
276             # are valuable for error checking
277             count => undef,
278             bar_width => undef,
279             term_width => undef,
280             term => undef,
281             remove => 0,
282             silent => 0,
283 11     11   57 };
  11         18  
284              
285 11     11   54 use constant ETA_TYPES => { map { $_ => 1 } qw( linear ) };
  11         19  
  11         19  
  11         465  
286              
287 11     11   49 use constant ALREADY_FINISHED => 'progress bar already finished';
  11         21  
  11         24292  
288              
289              
290             # This is here to allow testing to redirect away from the terminal but still
291             # see terminal output, IYSWIM
292             my $__FORCE_TERM = 0;
293              
294             # ----------------------------------
295             # CLASS HIGHER-LEVEL FUNCTIONS
296             # ----------------------------------
297              
298             # ----------------------------------
299             # CLASS HIGHER-LEVEL PROCEDURES
300             # ----------------------------------
301              
302             sub __force_term {
303 9     9   3876 my $class = shift;
304 9         32 ($__FORCE_TERM) = @_;
305             }
306              
307             # ----------------------------------
308             # CLASS UTILITY FUNCTIONS
309             # ----------------------------------
310              
311             sub term_size {
312 0     0 0 0 my ( $self, $fh ) = @_;
313 0 0       0 return if $self->silent;
314              
315 0         0 eval {
316 0         0 require Term::ReadKey;
317 0 0       0 }; if ($@) {
318 0         0 warn "Guessing terminal width due to problem with Term::ReadKey\n";
319 0         0 return 50;
320             }
321              
322 0         0 my $result;
323 0         0 eval {
324 0         0 $result = (Term::ReadKey::GetTerminalSize($fh))[0];
325 0 0 0     0 $result-- if ($^O eq "MSWin32" or $^O eq "cygwin");
326 0 0       0 }; if ( $@ ) {
327 0         0 warn "error from Term::ReadKey::GetTerminalSize(): $@";
328             }
329              
330             # If GetTerminalSize() failed it should (according to its docs)
331             # return an empty list. It doesn't - that's why we have the eval {}
332             # above - but also it may appear to succeed and return a width of
333             # zero.
334             #
335 0 0       0 if ( ! $result ) {
336 0         0 $result = 50;
337 0         0 warn "guessing terminal width $result\n";
338             }
339              
340 0         0 return $result;
341             }
342              
343             # Don't document hash keys until tested that the give the desired affect!
344              
345             =head1 INSTANCE CONSTRUCTION
346              
347             =head2 new
348              
349             Create & return a new Term::ProgressBar instance.
350              
351             =over 4
352              
353             =item ARGUMENTS
354              
355             If one argument is provided, and it is a hashref, then the hash is treated as
356             a set of key/value pairs, with the following keys; otherwise, it is treated as
357             a number, being equivalent to the C key.
358              
359             =over 4
360              
361             =item count
362              
363             The item count. The progress is marked at 100% when update I is
364             invoked, and proportionally until then.
365              
366             If you specify a count less than zero, just the name (if specified) will be
367             displayed and (if the remove flag is set) removed when the progress bar is
368             updated with a number lower than zero. This allows you to use the progress bar
369             when the count is sometimes known and sometimes not without making multiple
370             changes throughout your code.
371              
372             =item name
373              
374             A name to prefix the progress bar with.
375              
376             =item fh
377              
378             The filehandle to output to. Defaults to stderr. Do not try to use
379             *foo{THING} syntax if you want Term capabilities; it does not work. Pass in a
380             globref instead.
381              
382             =item term_width
383              
384             Sometimes we can't correctly determine the terminal width. You can use this
385             parameter to force a term width of a particular size. Use a positive integer,
386             please :)
387              
388             =item silent
389              
390             If passed a true value, Term::ProgressBar will do nothing at all. Useful in
391             scripts where the progress bar is optional (or just plain doesn't work due to
392             issues with modules it relies on).
393              
394             Instead, tell the constructor you want it to be silent and you don't need to
395             change the rest of your program:
396              
397             my $progress = Term::ProgressBar->new( { count => $count, silent => $silent } );
398             # later
399             $progress->update; # does nothing
400              
401             =item ETA
402              
403             A total time estimation to use. If enabled, a time finished estimation is
404             printed on the RHS (once sufficient updates have been performed to make such
405             an estimation feasible). Naturally, this is an I; no guarantees are
406             made. The format of the estimate
407              
408             Note that the format is intended to be as compact as possible while giving
409             over the relevant information. Depending upon the time remaining, the format
410             is selected to provide some resolution whilst remaining compact. Since the
411             time remaining decreases, the format typically changes over time.
412              
413             As the ETA approaches, the format will state minutes & seconds left. This is
414             identifiable by the word C<'Left'> at the RHS of the line. If the ETA is
415             further away, then an estimate time of completion (rather than time left) is
416             given, and is identifiable by C<'ETA'> at the LHS of the ETA box (on the right
417             of the progress bar). A time or date may be presented; these are of the form
418             of a 24 hour clock, e.g. C<'13:33'>, a time plus days (e.g., C<' 7PM+3'> for
419             around in over 3 days time) or a day/date, e.g. C<' 1Jan'> or C<'27Feb'>.
420              
421             If ETA is switched on, the return value of L is also
422             affected: the idea here is that if the progress bar seems to be moving quicker
423             than the eye would normally care for (and thus a great deal of time is spent
424             doing progress updates rather than "real" work), the next value is increased
425             to slow it. The maximum rate aimed for is tunable via the
426             L component.
427              
428             The available values for this are:
429              
430             =over 4
431              
432             =item undef
433              
434             Do not do estimation. The default.
435              
436             =item linear
437              
438             Perform linear estimation. This is simply that the amount of time between the
439             creation of the progress bar and now is divided by the current amount done,
440             and completion estimated linearly.
441              
442             =back
443              
444             =back
445              
446             =item EXAMPLES
447              
448             my $progress = Term::ProgressBar->new(100); # count from 1 to 100
449             my $progress = Term::ProgressBar->new({ count => 100 }); # same
450              
451             # Count to 200 thingies, outputting to stdout instead of stderr,
452             # prefix bar with 'thingy'
453             my $progress = Term::ProgressBar->new({ count => 200,
454             fh => \*STDOUT,
455             name => 'thingy' });
456              
457             =back
458              
459             =cut
460              
461             Class::MethodMaker->import (new_with_init => 'new',
462             new_hash_init => 'hash_init',);
463              
464             sub init {
465 25     25 0 44725 my $self = shift;
466              
467             # V1 Compatibility
468 25 100       152 return $self->init({count => $_[1], name => $_[0],
469             term_width => 50, bar_width => 50,
470             major_char => '#', minor_char => '',
471             lbrack => '', rbrack => '',
472             term => '0 but true',
473             silent => 0,})
474             if @_ == 2;
475              
476 20         37 my $target;
477              
478 20 50       60 croak
479             sprintf("Term::ProgressBar::new We don't handle this many arguments: %d",
480             scalar @_)
481             if @_ != 1;
482              
483 20         36 my %config;
484              
485 20 100       99 if ( UNIVERSAL::isa ($_[0], 'HASH') ) {
486 14         71 ($target) = @{$_[0]}{qw(count)};
  14         36  
487 14         50 %config = %{$_[0]}; # Copy in, so later playing does not tinker externally
  14         96  
488             } else {
489 6         42 ($target) = @_;
490             }
491              
492 20 50       119 if ( my @bad = grep ! exists DEFAULTS->{$_}, keys %config ) {
493 0         0 croak sprintf("Input parameters (%s) to %s not recognized\n",
494             join(':', @bad), 'Term::ProgressBar::new');
495             }
496              
497 20 50       67 croak "Target count required for Term::ProgressBar new\n"
498             unless defined $target;
499              
500             $config{$_} = DEFAULTS->{$_}
501 20         49 for grep ! exists $config{$_}, keys %{DEFAULTS()};
  20         219  
502 20         77 delete $config{count};
503              
504             $config{term} = -t $config{fh}
505 20 100       111 unless defined $config{term};
506              
507 20 100 66     66 if ( $__FORCE_TERM ) {
    50          
508 16         41 $config{term} = 1;
509 16         25 $config{term_width} = $__FORCE_TERM;
510             die "term width $config{term_width} (from __force_term) too small"
511 16 50       48 if $config{term_width} < 5;
512             } elsif ( $config{term} and ! defined $config{term_width}) {
513 0         0 $config{term_width} = $self->term_size($config{fh});
514 0 0       0 die if $config{term_width} < 5;
515             }
516              
517 20 100       58 unless ( defined $config{bar_width} ) {
518 15 100       39 if ( defined $config{term_width} ) {
519             # 5 for the % marker
520 12         30 $config{bar_width} = $config{term_width} - 5;
521             $config{bar_width} -= $_
522 12 100       88 for map(( defined $config{$_} ? length($config{$_}) : 0),
523             qw( lbrack rbrack name ));
524             $config{bar_width} -= 2 # Extra for ': '
525 12 100       62 if defined $config{name};
526             $config{bar_width} -= 10
527 12 100       34 if defined $config{ETA};
528 12 50       32 if ( $config{bar_width} < 1 ) {
529 0         0 warn "terminal width $config{term_width} too small for bar; defaulting to 10\n";
530 0         0 $config{bar_width} = 10;
531             }
532             # } elsif ( ! $config{term} ) {
533             # $config{bar_width} = 1;
534             # $config{term_width} = defined $config{ETA} ? 12 : 5;
535             } else {
536 3         4 $config{bar_width} = $target;
537             die "configured bar_width $config{bar_width} < 1"
538 3 50       11 if $config{bar_width} < 1;
539             }
540             }
541              
542 20         47 $config{start} = time;
543              
544 20         123 select(((select $config{fh}), $| = 1)[0]);
545              
546 20         95 $self->ETA(delete $config{ETA});
547              
548 20         556 $self->hash_init (%config,
549              
550             offset => 0,
551             scale => 1,
552              
553             last_update => 0,
554             last_position => 0,
555             );
556 20         7839 $self->target($target);
557 20   100     528 $self->minor($config{term} && $target > $config{bar_width} ** 1.5);
558              
559 20         239 $self->update(0); # Initialize the progress bar
560             }
561              
562              
563             # ----------------------------------
564             # INSTANCE FINALIZATION
565             # ----------------------------------
566              
567             # ----------------------------------
568             # INSTANCE COMPONENTS
569             # ----------------------------------
570              
571             =head1 INSTANCE COMPONENTS
572              
573             =cut
574              
575             =head2 Scalar Components.
576              
577             See L for usage.
578              
579             =over 4
580              
581             =item target
582              
583             The final target. Updates are measured in terms of this. Changes will have
584             no effect until the next update, but the next update value should be relative
585             to the new target. So
586              
587             $p = Term::ProgressBar({count => 20});
588             # Halfway
589             $p->update(10);
590             # Double scale
591             $p->target(40)
592             $p->update(21);
593              
594             will cause the progress bar to update to 52.5%
595              
596             =item max_update_rate
597              
598             This value is taken as being the maximum speed between updates to aim for.
599             B It defaults to 0.5, being the
600             number of seconds between updates.
601              
602             =back
603              
604             =head2 Boolean Components
605              
606             See L for usage.
607              
608             =over 4
609              
610             =item minor
611              
612             Default: set. If unset, no minor scale will be calculated or updated.
613              
614             Minor characters are used on the progress bar to give the user the idea of
615             progress even when there are so many more tasks than the terminal is wide that
616             the granularity would be too great. By default, Term::ProgressBar makes a
617             guess as to when minor characters would be valuable. However, it may not
618             always guess right, so this method may be called to force it one way or the
619             other. Of course, the efficiency saving is minimal unless the client is
620             utilizing the return value of L.
621              
622             See F and F to see minor characters in
623             action, and not in action, respectively.
624              
625             =back
626              
627             =head2 Configuration
628              
629             =over 4
630              
631             =item lbrack
632              
633             Left bracket ( defaults to [ )
634              
635             $progress->lbrack('<');
636              
637             =item rbrack
638              
639             Right bracket ( defaults to ] )
640              
641             $progress->rbrack('>');
642              
643             =back
644              
645             =cut
646              
647             # Private Scalar Components
648             # offset ) Default: 0. Added to any value supplied to update.
649             # scale ) Default: 1. Any value supplied to update is multiplied by
650             # this.
651             # major_char) Default: '='. The character printed for the major scale.
652             # minor_char) Default: '*'. The character printed for the minor scale.
653             # name ) Default: undef. The name to print to the side of the bar.
654             # fh ) Default: STDERR. The filehandle to output progress to.
655              
656             # Private Counter Components
657             # last_update ) Default: 0. The so_far value last time update was invoked.
658             # last_position) Default: 0. The number of the last progress mark printed.
659              
660             # Private Boolean Components
661             # term ) Default: detected (by C).
662             # If unset, we assume that we are not connected to a terminal (or
663             # at least, not a suitably intelligent one). Then, we attempt
664             # minimal functionality.
665              
666             Class::MethodMaker->import
667             (
668             get_set => [qw/ major_units major_char
669             minor_units minor_char
670             lbrack rbrack
671             name
672             offset scale
673             fh start
674             max_update_rate
675             silent
676             /],
677             counter => [qw/ last_position last_update /],
678             boolean => [qw/ minor name_printed pb_ended remove /],
679             # let it be boolean to handle 0 but true
680             get_set => [qw/ term /],
681             );
682              
683             # We generate these by hand since we want to check the values.
684             sub bar_width {
685 987     987 0 12049 my $self = shift;
686 987 100       4510 return $self->{bar_width} if not @_;
687 20 50       56 croak 'wrong number of arguments' if @_ != 1;
688 20 50       48 croak 'bar_width < 1' if $_[0] < 1;
689 20         363 $self->{bar_width} = $_[0];
690             }
691             sub term_width {
692 165     165 1 8205 my $self = shift;
693 165 100       1787 return $self->{term_width} if not @_;
694 20 50       56 croak 'wrong number of arguments' if @_ != 1;
695 20 50 66     384 croak 'term_width must be at least 5' if $self->term and $_[0] < 5;
696 20         602 $self->{term_width} = $_[0];
697             }
698              
699             sub target {
700 596     596 1 2803 my $self = shift;
701              
702 596 100       1063 if ( @_ ) {
703 21         43 my ($target) = @_;
704              
705 21 100       48 if ( $target ) {
706 19         42 $self->major_units($self->bar_width / $target);
707 19         211 $self->minor_units($self->bar_width ** 2 / $target);
708 19   100     185 $self->minor ( defined $self->term_width and
709             $self->term_width < $target );
710             }
711 21         262 $self->{target} = $target;
712             }
713              
714 596         1408 return $self->{target};
715             }
716              
717             sub ETA {
718 330     330 1 453 my $self = shift;
719 330 50       6366 return if $self->silent;
720 330 100       2982 if (@_) {
721 20         57 my ($type) = @_;
722             croak "Invalid ETA type: $type\n"
723 20 50 66     68 if defined $type and ! exists ETA_TYPES->{$type};
724 20         46 $self->{ETA} = $type;
725             }
726              
727 330         555 return $self->{ETA};
728             }
729              
730             # ----------------------------------
731             # INSTANCE HIGHER-LEVEL FUNCTIONS
732             # ----------------------------------
733              
734             # ----------------------------------
735             # INSTANCE HIGHER-LEVEL PROCEDURES
736             # ----------------------------------
737              
738             =head1 INSTANCE HIGHER-LEVEL PROCEDURES
739              
740             Z<>
741              
742             =cut
743              
744             sub no_minor {
745 0     0 0 0 warn sprintf("%s: This method is deprecated. Please use %s instead\n",
746             (caller (0))[3], '$x->minor (0)',);
747 0         0 $_[0]->clear_minor (0);
748             }
749              
750             # -------------------------------------
751              
752             =head2 update
753              
754             Update the progress bar.
755              
756             =over 4
757              
758             =item ARGUMENTS
759              
760             =over 4
761              
762             =item so_far
763              
764             Current progress point, in whatever units were passed to C.
765              
766             If not defined, assumed to be 1+ whatever was the value last time C
767             was called (starting at 0).
768              
769             =back
770              
771             =item RETURNS
772              
773             =over 4
774              
775             =item next_call
776              
777             The next value of so_far at which to call C.
778              
779             =back
780              
781             =back
782              
783             =cut
784              
785             sub update {
786 573     573 1 8022681 my $self = shift;
787             # returning target+1 as next value should avoid calling update
788             # method in the smooth form of using the progress bar
789 573 100       11302 return $self->target+1 if $self->silent;
790              
791 458         4066 my ($so_far) = @_;
792              
793 458 100       806 if ( ! defined $so_far ) {
794 101         1916 $so_far = $self->last_update + 1;
795             }
796              
797 458         3853 my $input_so_far = $so_far;
798 458 50       8572 $so_far *= $self->scale
799             unless $self->scale == 1;
800 458         11533 $so_far += $self->offset;
801              
802 458         3667 my $target = my $next = $self->target;
803 458         8425 my $name = $self->name;
804 458         11358 my $fh = $self->fh;
805              
806              
807 458 100       3959 if ( $target < 0 ) {
    100          
808 24 100 66     370 if($input_so_far <= 0 or $input_so_far == $self->last_update) {
809 4         9 print $fh "\r", ' ' x $self->term_width, "\r";
810              
811 4 50       15 if(defined $name) {
812 4 100 100     104 if(!$self->remove or $input_so_far >= 0) {
813 3         66 print $fh "$name...";
814             }
815 4 50 66     92 if(!$self->remove and $input_so_far < 0) {
816 0         0 print $fh "\n";
817             }
818             }
819             }
820 24         1035 $self->last_update($input_so_far);
821 24         1463 return 2**32-1;
822             } elsif ( $target == 0 ) {
823 22         224 print $fh "\r";
824 22 50       123 printf $fh "$name: "
825             if defined $name;
826 22         82 print $fh "(nothing to do)\n";
827 22         93 return 2**32-1;
828             }
829              
830 412         7622 my $biggies = $self->major_units * $so_far;
831 412         3636 my @chars = (' ') x $self->bar_width;
832             $chars[$_] = $self->major_char
833 412         8000 for 0..$biggies-1;
834              
835 412 100       210467 if ( $self->minor ) {
836 3         85 my $smally = $self->minor_units * $so_far % $self->bar_width;
837 3 50       74 $chars[$smally] = $self->minor_char
838             unless $so_far == $target;
839 3         73 $next *= ($self->minor_units * $so_far + 1) / ($self->bar_width ** 2);
840             } else {
841 409         10599 $next *= ($self->major_units * $so_far + 1) / $self->bar_width;
842             }
843              
844 412         1313 local $\ = undef;
845              
846 412 100       7931 if ( $self->term > 0 ) {
847 310         2774 local $\ = undef;
848 310         480 my $to_print = "\r";
849 310 100       551 $to_print .= "$name: "
850             if defined $name;
851 310         388 my $ratio = $so_far / $target;
852             # Rounds down %
853 310         5806 $to_print .= (sprintf ("%3d%% %s%s%s",
854             $ratio * 100,
855             $self->lbrack, join ('', @chars), $self->rbrack));
856 310         5673 my $ETA = $self->ETA;
857 310 100 100     649 if ( defined $ETA and $ratio > 0 ) {
858 11 50       48 if ( $ETA eq 'linear' ) {
859 11 100       51 if ( $ratio == 1 ) {
    50          
860 1         27 my $taken = time - $self->start;
861 1         9 my $ss = $taken % 60;
862 1         5 my $mm = int(($taken % 3600) / 60);
863 1         2 my $hh = int($taken / 3600);
864 1 50       4 if ( $hh > 99 ) {
865 0         0 $to_print .= sprintf('D %2dh%02dm', $hh, $mm, $ss);
866             } else {
867 1         6 $to_print .= sprintf('D%2dh%02dm%02ds', $hh, $mm, $ss);
868             }
869             } elsif ( $ratio < PREDICT_RATIO ) {
870             # No safe prediction yet
871 0         0 $to_print .= 'ETA ------';
872             } else {
873 10         24 my $time = time;
874 10         257 my $left = (($time - $self->start) * ((1 - $ratio) / $ratio));
875 10 50       137 if ( $left < ETA_TIME_CUTOFF ) {
876 10         60 $to_print .= sprintf '%1dm%02ds Left', int($left / 60), $left % 60;
877             } else {
878 0         0 my $eta = $time + $left;
879 0         0 my $format;
880 0 0       0 if ( $left < DAY ) {
    0          
881 0         0 $format = 'ETA %H:%M';
882             } elsif ( $left < ETA_DATE_CUTOFF ) {
883 0         0 $format = sprintf('ETA %%l%%p+%d',$left/DAY);
884             } else {
885 0         0 $format = 'ETA %e%b';
886             }
887 0         0 $to_print .= strftime($format, localtime $eta);
888             }
889             # Calculate next to be at least SEC_PER_UPDATE seconds away
890 10 100       38 if ( $left > 0 ) {
891 9         244 my $incr = ($target - $so_far) / ($left / $self->max_update_rate);
892 9 50       114 $next = $so_far + $incr
893             if $so_far + $incr > $next;
894             }
895             }
896             } else {
897 0         0 croak "Bad ETA type: $ETA\n";
898             }
899             }
900 310         522 for ($self->{last_printed}) {
901 310 100 100     885 unless (defined and $_ eq $to_print) {
902 305         3878 print $fh $to_print;
903             }
904 310         747 $_ = $to_print;
905             }
906              
907 310         6671 $next -= $self->offset;
908 310 50       8078 $next /= $self->scale
909             unless $self->scale == 1;
910              
911 310 50 66     3309 if ( $so_far >= $target and $self->remove and ! $self->pb_ended) {
      33        
912 0         0 print $fh "\r", ' ' x $self->term_width, "\r";
913 0         0 $self->pb_ended;
914             }
915              
916             } else {
917 102         967 local $\ = undef;
918              
919 102 50       1923 if ( $self->term ) { # special case for backwards compat.
920 102 50 66     866 if ( $so_far == 0 and defined $name and ! $self->name_printed ) {
      66        
921 1         72 print $fh "$name: ";
922 1         27 $self->set_name_printed;
923             }
924              
925 102         167 my $position = int($self->bar_width * ($input_so_far / $target));
926 102         1952 my $add = $position - $self->last_position;
927 102 100       4085 $self->last_position_incr ($add)
928             if $add;
929              
930 102         6467 print $fh $self->major_char x $add;
931              
932 102         3450 $next -= $self->offset;
933 102 50       2550 $next /= $self->scale
934             unless $self->scale == 1;
935             } else {
936 0         0 my $pc = int(100*$input_so_far/$target);
937 0         0 printf $fh "[%s] %s: %3d%%\n", scalar(localtime), $name, $pc;
938              
939 0         0 $next = ceil($target * ($pc+1)/100);
940             }
941              
942 102 100       944 if ( $input_so_far >= $target ) {
943 2 100       41 if ( $self->pb_ended ) {
944 1         175 croak ALREADY_FINISHED;
945             } else {
946 1 50       28 if ( $self->term ) {
947 1         15 print $fh "\n"
948             }
949 1         22 $self->set_pb_ended;
950             }
951             }
952             }
953              
954              
955 411 100       919 $next = $target if $next > $target;
956              
957 411         8111 $self->last_update($input_so_far);
958 411         27021 return $next;
959             }
960              
961             # -------------------------------------
962              
963             =head2 message
964              
965             Output a message. This is very much like print, but we try not to disturb the
966             terminal.
967              
968             =over 4
969              
970             =item ARGUMENTS
971              
972             =over 4
973              
974             =item string
975              
976             The message to output.
977              
978             =back
979              
980             =back
981              
982             =cut
983              
984             sub message {
985 209     209 1 1008404 my $self = shift;
986 209 100       3835 return if $self->silent;
987 106         933 my ($string) = @_;
988 106         164 chomp ($string);
989              
990 106         1903 my $fh = $self->fh;
991 106         902 local $\ = undef;
992 106 50       1884 if ( $self->term ) {
993 106         917 print $fh "\r", ' ' x $self->term_width;
994 106         493 print $fh "\r$string\n";
995             } else {
996 0         0 print $fh "\n$string\n";
997 0         0 print $fh $self->major_char x $self->last_position;
998             }
999 106         217 undef $self->{last_printed};
1000 106         2086 $self->update($self->last_update);
1001             }
1002              
1003              
1004             # ----------------------------------------------------------------------
1005              
1006             =head1 REPORTING BUGS
1007              
1008             via RT: L
1009              
1010             =head1 COMPATIBILITY
1011              
1012             If exactly two arguments are provided, then L operates in v1
1013             compatibility mode: the arguments are considered to be name, and item count.
1014             Various other defaults are set to emulate version one (e.g., the major output
1015             character is '#', the bar width is set to 50 characters and the output
1016             filehandle is not treated as a terminal). This mode is deprecated.
1017              
1018             =head1 AUTHOR
1019              
1020             Martyn J. Pearce fluffy@cpan.org
1021              
1022             Significant contributions from Ed Avis, amongst others.
1023              
1024             =head1 MAINTAINER
1025              
1026             Gabor Szabo L L
1027              
1028             =head1 LICENSE AND COPYRIGHT
1029              
1030             Copyright (c) 2001, 2002, 2003, 2004, 2005 Martyn J. Pearce. This program is
1031             free software; you can redistribute it and/or modify it under the same terms
1032             as Perl itself.
1033              
1034             =cut
1035              
1036             1;
1037              
1038             __END__