File Coverage

blib/lib/Term/ProgressBar.pm
Criterion Covered Total %
statement 210 249 84.3
branch 97 142 68.3
condition 33 47 70.2
subroutine 23 25 92.0
pod 5 9 55.5
total 368 472 77.9


line stmt bran cond sub pod time code
1             package Term::ProgressBar;
2              
3 12     12   233295 use strict;
  12         46  
  12         322  
4 12     12   55 use warnings;
  12         20  
  12         1166  
5              
6             our $VERSION = '2.23';
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.23
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 12     12   85 use Carp qw( croak );
  12         23  
  12         649  
250 12     12   5629 use Class::MethodMaker 1.02 qw( );
  12         183526  
  12         361  
251 12     12   6771 use Fatal qw( open sysopen close seek );
  12         150672  
  12         56  
252 12     12   28084 use POSIX qw( ceil strftime );
  12         54207  
  12         76  
253              
254 12     12   14820 use constant MINUTE => 60;
  12         24  
  12         862  
255 12     12   68 use constant HOUR => 60 * MINUTE;
  12         22  
  12         593  
256 12     12   62 use constant DAY => 24 * HOUR;
  12         22  
  12         573  
257              
258             # The point past which to give ETA of just date, rather than time
259 12     12   73 use constant ETA_DATE_CUTOFF => 3 * DAY;
  12         20  
  12         663  
260             # The point past which to give ETA of time, rather time left
261 12     12   64 use constant ETA_TIME_CUTOFF => 10 * MINUTE;
  12         20  
  12         571  
262             # The ratio prior to which to not dare any estimates
263 12     12   62 use constant PREDICT_RATIO => 0.01;
  12         23  
  12         961  
264              
265 12         1026 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 12     12   69 };
  12         102  
284              
285 12     12   72 use constant ETA_TYPES => { map { $_ => 1 } qw( linear ) };
  12         33  
  12         26  
  12         716  
286              
287 12     12   78 use constant ALREADY_FINISHED => 'progress bar already finished';
  12         28  
  12         31414  
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   5595 my $class = shift;
304 9         30 ($__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 26     26 0 43210 my $self = shift;
466              
467             # V1 Compatibility
468 26 100       153 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 21         37 my $target;
477              
478 21 50       64 croak
479             sprintf("Term::ProgressBar::new We don't handle this many arguments: %d",
480             scalar @_)
481             if @_ != 1;
482              
483 21         36 my %config;
484              
485 21 100       95 if ( UNIVERSAL::isa ($_[0], 'HASH') ) {
486 15         27 ($target) = @{$_[0]}{qw(count)};
  15         36  
487 15         26 %config = %{$_[0]}; # Copy in, so later playing does not tinker externally
  15         70  
488             } else {
489 6         14 ($target) = @_;
490             }
491              
492 21 50       133 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 21 50       67 croak "Target count required for Term::ProgressBar new\n"
498             unless defined $target;
499              
500             $config{$_} = DEFAULTS->{$_}
501 21         45 for grep ! exists $config{$_}, keys %{DEFAULTS()};
  21         324  
502 21         62 delete $config{count};
503              
504             $config{term} = -t $config{fh}
505 21 100       173 unless defined $config{term};
506              
507 21 100 66     93 if ( $__FORCE_TERM ) {
    50          
508 16         32 $config{term} = 1;
509 16         27 $config{term_width} = $__FORCE_TERM;
510             die "term width $config{term_width} (from __force_term) too small"
511 16 50       52 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 21 100       82 unless ( defined $config{bar_width} ) {
518 16 100       44 if ( defined $config{term_width} ) {
519             # 5 for the % marker
520 12         32 $config{bar_width} = $config{term_width} - 5;
521             $config{bar_width} -= $_
522 12 100       111 for map(( defined $config{$_} ? length($config{$_}) : 0),
523             qw( lbrack rbrack name ));
524             $config{bar_width} -= 2 # Extra for ': '
525 12 100       46 if defined $config{name};
526             $config{bar_width} -= 10
527 12 100       32 if defined $config{ETA};
528 12 50       35 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 4         6 $config{bar_width} = $target;
537             die "configured bar_width $config{bar_width} < 1"
538 4 50       9 if $config{bar_width} < 1;
539             }
540             }
541              
542 21         103 $config{start} = time;
543              
544 21         166 select(((select $config{fh}), $| = 1)[0]);
545              
546 21         108 $self->ETA(delete $config{ETA});
547              
548 21         541 $self->hash_init (%config,
549              
550             offset => 0,
551             scale => 1,
552              
553             last_update => 0,
554             last_position => 0,
555             );
556 21         8411 $self->target($target);
557 21   100     608 $self->minor($config{term} && $target > $config{bar_width} ** 1.5);
558              
559 21         271 $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 1006     1006 0 12469 my $self = shift;
686 1006 100       4693 return $self->{bar_width} if not @_;
687 21 50       73 croak 'wrong number of arguments' if @_ != 1;
688 21 50       79 croak 'bar_width < 1' if $_[0] < 1;
689 21         430 $self->{bar_width} = $_[0];
690             }
691             sub term_width {
692 167     167 1 9093 my $self = shift;
693 167 100       2423 return $self->{term_width} if not @_;
694 21 50       58 croak 'wrong number of arguments' if @_ != 1;
695 21 50 66     429 croak 'term_width must be at least 5' if $self->term and $_[0] < 5;
696 21         687 $self->{term_width} = $_[0];
697             }
698              
699             sub target {
700 599     599 1 3763 my $self = shift;
701              
702 599 100       995 if ( @_ ) {
703 22         45 my ($target) = @_;
704              
705 22 100       69 if ( $target ) {
706 20         51 $self->major_units($self->bar_width / $target);
707 20         211 $self->minor_units($self->bar_width ** 2 / $target);
708 20   100     227 $self->minor ( defined $self->term_width and
709             $self->term_width < $target );
710             }
711 22         286 $self->{target} = $target;
712             }
713              
714 599         1060 return $self->{target};
715             }
716              
717             sub ETA {
718 331     331 1 436 my $self = shift;
719 331 50       6460 return if $self->silent;
720 331 100       2953 if (@_) {
721 21         48 my ($type) = @_;
722             croak "Invalid ETA type: $type\n"
723 21 50 66     94 if defined $type and ! exists ETA_TYPES->{$type};
724 21         51 $self->{ETA} = $type;
725             }
726              
727 331         497 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 575     575 1 8024470 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 575 100       11331 return $self->target+1 if $self->silent;
790              
791 460         4141 my ($so_far) = @_;
792              
793 460 100       764 if ( ! defined $so_far ) {
794 101         1802 $so_far = $self->last_update + 1;
795             }
796              
797 460         3476 my $input_so_far = $so_far;
798 460 50       8393 $so_far *= $self->scale
799             unless $self->scale == 1;
800 460         11704 $so_far += $self->offset;
801              
802 460         3643 my $target = my $next = $self->target;
803 460         8394 my $name = $self->name;
804 460         11489 my $fh = $self->fh;
805              
806              
807 460 100       3838 if ( $target < 0 ) {
    100          
808 24 100 66     376 if($input_so_far <= 0 or $input_so_far == $self->last_update) {
809 4         21 print $fh "\r", ' ' x $self->term_width, "\r";
810              
811 4 50       18 if(defined $name) {
812 4 100 100     106 if(!$self->remove or $input_so_far >= 0) {
813 3         69 print $fh "$name...";
814             }
815 4 50 66     100 if(!$self->remove and $input_so_far < 0) {
816 0         0 print $fh "\n";
817             }
818             }
819             }
820 24         1061 $self->last_update($input_so_far);
821 24         1502 return 2**32-1;
822             } elsif ( $target == 0 ) {
823 22         319 print $fh "\r";
824 22 50       270 printf $fh "$name: "
825             if defined $name;
826 22         206 print $fh "(nothing to do)\n";
827 22         133 return 2**32-1;
828             }
829              
830 414         871 my @chars = (' ') x $self->bar_width;
831 414 100       777 if ( $so_far >= $target ) {
832 12         246 @chars = ($self->major_char) x $self->bar_width;
833             }
834             else {
835 402         7594 my $biggies = $self->major_units * $so_far;
836             $chars[$_] = $self->major_char
837 402         10402 for 0..$biggies-1;
838             }
839              
840 414 100       194632 if ( $self->minor ) {
841 3         73 my $smally = $self->minor_units * $so_far % $self->bar_width;
842 3 50       57 $chars[$smally] = $self->minor_char
843             unless $so_far == $target;
844 3         73 $next *= ($self->minor_units * $so_far + 1) / ($self->bar_width ** 2);
845             } else {
846 411         10372 $next *= ($self->major_units * $so_far + 1) / $self->bar_width;
847             }
848              
849 414         1182 local $\ = undef;
850              
851 414 100       7962 if ( $self->term > 0 ) {
852 310         2728 local $\ = undef;
853 310         406 my $to_print = "\r";
854 310 100       561 $to_print .= "$name: "
855             if defined $name;
856 310         385 my $ratio = $so_far / $target;
857             # Rounds down %
858 310         5912 $to_print .= (sprintf ("%3d%% %s%s%s",
859             $ratio * 100,
860             $self->lbrack, join ('', @chars), $self->rbrack));
861 310         5561 my $ETA = $self->ETA;
862 310 100 100     586 if ( defined $ETA and $ratio > 0 ) {
863 11 50       36 if ( $ETA eq 'linear' ) {
864 11 100       40 if ( $ratio == 1 ) {
    50          
865 1         23 my $taken = time - $self->start;
866 1         10 my $ss = $taken % 60;
867 1         3 my $mm = int(($taken % 3600) / 60);
868 1         3 my $hh = int($taken / 3600);
869 1 50       4 if ( $hh > 99 ) {
870 0         0 $to_print .= sprintf('D %2dh%02dm', $hh, $mm, $ss);
871             } else {
872 1         5 $to_print .= sprintf('D%2dh%02dm%02ds', $hh, $mm, $ss);
873             }
874             } elsif ( $ratio < PREDICT_RATIO ) {
875             # No safe prediction yet
876 0         0 $to_print .= 'ETA ------';
877             } else {
878 10         22 my $time = time;
879 10         210 my $left = (($time - $self->start) * ((1 - $ratio) / $ratio));
880 10 50       108 if ( $left < ETA_TIME_CUTOFF ) {
881 10         46 $to_print .= sprintf '%1dm%02ds Left', int($left / 60), $left % 60;
882             } else {
883 0         0 my $eta = $time + $left;
884 0         0 my $format;
885 0 0       0 if ( $left < DAY ) {
    0          
886 0         0 $format = 'ETA %H:%M';
887             } elsif ( $left < ETA_DATE_CUTOFF ) {
888 0         0 $format = sprintf('ETA %%l%%p+%d',$left/DAY);
889             } else {
890 0         0 $format = 'ETA %e%b';
891             }
892 0         0 $to_print .= strftime($format, localtime $eta);
893             }
894             # Calculate next to be at least SEC_PER_UPDATE seconds away
895 10 100       29 if ( $left > 0 ) {
896 9         257 my $incr = ($target - $so_far) / ($left / $self->max_update_rate);
897 9 50       101 $next = $so_far + $incr
898             if $so_far + $incr > $next;
899             }
900             }
901             } else {
902 0         0 croak "Bad ETA type: $ETA\n";
903             }
904             }
905 310         516 for ($self->{last_printed}) {
906 310 100 100     899 unless (defined and $_ eq $to_print) {
907 305         5448 print $fh $to_print;
908             }
909 310         1043 $_ = $to_print;
910             }
911              
912 310         7844 $next -= $self->offset;
913 310 50       8290 $next /= $self->scale
914             unless $self->scale == 1;
915              
916 310 50 66     3288 if ( $so_far >= $target and $self->remove and ! $self->pb_ended) {
      33        
917 0         0 print $fh "\r", ' ' x $self->term_width, "\r";
918 0         0 $self->pb_ended;
919             }
920              
921             } else {
922 104         957 local $\ = undef;
923              
924 104 100       1860 if ( $self->term ) { # special case for backwards compat.
925 102 50 66     832 if ( $so_far == 0 and defined $name and ! $self->name_printed ) {
      66        
926 1         61 print $fh "$name: ";
927 1         29 $self->set_name_printed;
928             }
929              
930 102         182 my $position = int($self->bar_width * ($input_so_far / $target));
931 102         1918 my $add = $position - $self->last_position;
932 102 100       4062 $self->last_position_incr ($add)
933             if $add;
934              
935 102         6381 print $fh $self->major_char x $add;
936              
937 102         3738 $next -= $self->offset;
938 102 50       2597 $next /= $self->scale
939             unless $self->scale == 1;
940             } else {
941 2         19 my $pc = int(100*$input_so_far/$target);
942 2   50     151 printf $fh "[%s] %s: %3d%%\n", scalar(localtime), ($name || ''), $pc;
943              
944 2         17 $next = ceil($target * ($pc+1)/100);
945             }
946              
947 104 100       950 if ( $input_so_far >= $target ) {
948 2 100       40 if ( $self->pb_ended ) {
949 1         163 croak ALREADY_FINISHED;
950             } else {
951 1 50       31 if ( $self->term ) {
952 1         21 print $fh "\n"
953             }
954 1         27 $self->set_pb_ended;
955             }
956             }
957             }
958              
959              
960 413 100       844 $next = $target if $next > $target;
961              
962 413         8005 $self->last_update($input_so_far);
963 413         27084 return $next;
964             }
965              
966             # -------------------------------------
967              
968             =head2 message
969              
970             Output a message. This is very much like print, but we try not to disturb the
971             terminal.
972              
973             =over 4
974              
975             =item ARGUMENTS
976              
977             =over 4
978              
979             =item string
980              
981             The message to output.
982              
983             =back
984              
985             =back
986              
987             =cut
988              
989             sub message {
990 209     209 1 1008417 my $self = shift;
991 209 100       3864 return if $self->silent;
992 106         976 my ($string) = @_;
993 106         157 chomp ($string);
994              
995 106         1957 my $fh = $self->fh;
996 106         901 local $\ = undef;
997 106 50       1933 if ( $self->term ) {
998 106         949 print $fh "\r", ' ' x $self->term_width;
999 106         1129 print $fh "\r$string\n";
1000             } else {
1001 0         0 print $fh "\n$string\n";
1002 0         0 print $fh $self->major_char x $self->last_position;
1003             }
1004 106         339 undef $self->{last_printed};
1005 106         2613 $self->update($self->last_update);
1006             }
1007              
1008              
1009             # ----------------------------------------------------------------------
1010              
1011             =head1 REPORTING BUGS
1012              
1013             via RT: L
1014              
1015             =head1 COMPATIBILITY
1016              
1017             If exactly two arguments are provided, then L operates in v1
1018             compatibility mode: the arguments are considered to be name, and item count.
1019             Various other defaults are set to emulate version one (e.g., the major output
1020             character is '#', the bar width is set to 50 characters and the output
1021             filehandle is not treated as a terminal). This mode is deprecated.
1022              
1023             =head1 AUTHOR
1024              
1025             Martyn J. Pearce fluffy@cpan.org
1026              
1027             Significant contributions from Ed Avis, amongst others.
1028              
1029             =head1 MAINTAINER
1030              
1031             Gabor Szabo L L
1032              
1033             =head1 LICENSE AND COPYRIGHT
1034              
1035             Copyright (c) 2001, 2002, 2003, 2004, 2005 Martyn J. Pearce. This program is
1036             free software; you can redistribute it and/or modify it under the same terms
1037             as Perl itself.
1038              
1039             =cut
1040              
1041             1;
1042              
1043             __END__