The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#
# (c) Jan Gehring <jan.gehring@gmail.com>
#
# vim: set ts=2 sw=2 tw=0:
# vim: set expandtab:

=head1 NAME

Rex::Commands::Tail - Tail a file

Version <= 1.0: All these functions will not be reported.

All these functions are not idempotent.

=head1 DESCRIPTION

With this module you can tail a file

=head1 SYNOPSIS

 tail "/var/log/syslog";


=head1 EXPORTED FUNCTIONS

=over 4

=cut

package Rex::Commands::Tail;
{
  $Rex::Commands::Tail::VERSION = '0.55.3';
}

use strict;
use warnings;

require Rex::Exporter;
use Data::Dumper;
use Rex::Commands::Fs;
use Rex::Commands::File;

use vars qw(@EXPORT);
use base qw(Rex::Exporter);

@EXPORT = qw(tail);

=item tail($file)

This function will tail the given file.

 task "syslog", "server01", sub {
   tail "/var/log/syslog";
 };

Or, if you want to format the output by yourself, you can define a callback function.

 task "syslog", "server01", sub {
   tail "/var/log/syslog", sub {
    my ($data) = @_;
 
    my $server = Rex->get_current_connection()->{'server'};
 
    print "$server>> $data\n";
   };
 };



=cut

sub tail {
  my $file     = shift;
  my $callback = shift;

  if ( Rex::is_sudo() and ref( Rex::get_sftp() ) ne 'Net::SFTP::Foreign' ) {
    die("Can't use tail within sudo environment.");
  }

  Rex::Logger::debug("Tailing: $file");

  if ( my $ssh = Rex::is_ssh() ) {
    my %stat      = stat $file;
    my $orig_size = $stat{'size'};
    my $new_pos   = $stat{'size'} - 1024;
    if ( $new_pos < 0 ) { $new_pos = 0; }

    my %new_stat;
    my $old_pos;
    while (1) {
      if ( !%new_stat || $new_stat{'size'} > $stat{'size'} ) {
        my $fh = file_read $file;
        unless ($fh) {
          die("Error opening $file for reading");
        }
        my $data;

        if ( !%new_stat ) {
          $fh->seek( $stat{'size'} - 1024 );
          $data = $fh->read(1024);
        }
        else {
          $fh->seek($old_pos);
          $data = $fh->read( $new_stat{'size'} - $old_pos );
        }

        my @lines = split( /\n/, $data );
        shift @lines unless $old_pos;

        if ($callback) {
          for my $line (@lines) {
            &$callback($line);
          }
        }
        else {
          print join( "\n", @lines ) . "\n";
        }

        $fh->close;
        $old_pos = $new_stat{'size'} || $stat{'size'};
      }

      select undef, undef, undef, 0.3;
      %stat = %new_stat if %new_stat;
      %new_stat = stat $file;
    }

  }
  else {
    system("tail -f $file");
  }

}

=back

=cut

1;