Mail-SpamAssassin

 view release on metacpan or  search on metacpan

lib/Mail/SpamAssassin/Util/Progress.pm  view on Meta::CPAN

        (Term::ReadKey::GetTerminalSize($self->{fh}))[0];
      1;
    } or do {  # an error will just keep the default
      my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;
      # dbg("progress: Term::ReadKey::GetTerminalSize failed: $eval_stat");
      # GetTerminalSize might have returned an empty array, so check the
      # value and set if it exists, if not we keep the default
      $term_size = $term_readkey_term_size if ($term_readkey_term_size);
    }
  }

  # only viable on Unix based OS, so exclude windows, etc here
  if ($^O !~ /^(mswin|dos|os2)/i) {
    if (!defined $term_size) {
      my $data = `stty -a`;
      if (defined $data && $data =~ /columns (\d+)/) {
        $term_size = $1;
      }
    }

    if (!defined $term_size) {
      my $data = `tput cols`;
      if (defined $data && $data =~ /^(\d+)/) {
        $term_size = $1;
      }
    }
  }

  # fall back on the default
  if (!defined($term_size)) {
    $term_size = 80;
  }


  # Adjust the bar size based on what all is going to print around it,
  # do not forget the trailing space. Here is what we have to deal with
  #1234567890123456789012345678901234567
  # XXX% [] XXX.XX msgs/sec XXmXXs LEFT
  # XXX% [] XXX.XX msgs/sec XXmXXs DONE
  $self->{bar_size} = $term_size - 37;

  my @chars = (' ') x $self->{bar_size};

  print $fh sprintf("\r%3d%% [%s] %6.2f %s/sec %s-%s- LEFT",
		    0, join('', @chars), 0, $self->{itemtype}, '--', '--');

  return;
}

=head2 update

public instance () update ([Integer $num_done])

Description:
This method is what gets called to update the progress bar.  You may optionally pass in
an integer value that indicates how many messages have been processed.  If you do not pass
anything in then the num_done value will be incremented by one.

=cut

sub update {
  my ($self, $num_done) = @_;

  my $fh = $self->{fh};
  my $time_now = time();

  # If nothing is passed in to update assume we are adding one to the prev_num_done value
  unless(defined($num_done)) {
    $num_done = $self->{prev_num_done} + 1;
  }

  my $msgs_since = $num_done - $self->{prev_num_done};
  my $time_since = $time_now - $self->{prev_time};

 # we have to have processed at least one message and moved a little time
  if ($msgs_since > 0 && $time_since > .5) {

    if ($self->{term}) {
      my $percentage = $num_done != 0 ? int(($num_done / $self->{total}) * 100) : 0;

      my @chars = (' ') x $self->{bar_size};
      my $used_bar = $num_done * ($self->{bar_size} / $self->{total});
      for (0..$used_bar-1) {
	$chars[$_] = '=';
      }
      my $rate = $msgs_since/$time_since;
      my $overall_rate = $num_done/($time_now-$self->{start_time});
      
      # semi-complicated calculation here so that we get the avg msg per sec over time
      $self->{avg_msgs_per_sec} = defined($self->{avg_msgs_per_sec}) ? 
	0.5 * $self->{avg_msgs_per_sec} + 0.5 * ($msgs_since / $time_since) : $msgs_since / $time_since;
      
      # using the overall_rate here seems to provide much smoother eta numbers
      my $eta = ($self->{total} - $num_done)/$overall_rate;

      my($t1, $v1, $t2, $v2) = seconds_to_values($eta);

      print $fh sprintf("\r%3d%% [%s] %6.2f %s/sec %2d${t1}%2d${t2} LEFT",
                      $percentage, join('', @chars), $self->{avg_msgs_per_sec},
                      $self->{itemtype}, $v1, $v2);
    }
    else { # we have no term, so fake it
      print $fh '.' x $msgs_since;
    }

    $self->{prev_time} = $time_now;
    $self->{prev_num_done} = $num_done;
  }
  $self->{num_done} = $num_done;
  return;
}

=head2 final

public instance () final ([Integer $num_done])

Description:
This method should be called once all processing has finished.
It will print out the final msgs per sec calculation and the total time taken.
You can optionally pass in a num_done value, otherwise it will use the value
calculated from the last call to update.



( run in 1.575 second using v1.01-cache-2.11-cpan-39bf76dae61 )