App-karr
view release on metacpan or search on metacpan
lib/App/karr/Foundation.pm view on Meta::CPAN
my $sel = IO::Select->new($reader);
while (1) {
my $wait;
if ( $max_runtime > 0 ) {
$wait = $max_runtime - ( time - $started );
if ( $wait <= 0 ) { $timed_out = 1; last }
}
# undef $wait => block indefinitely (max_runtime: 0 disables the timeout).
my @ready = $sel->can_read($wait);
unless (@ready) {
# Spurious wakeup (signal) or deadline. Only the deadline ends the loop.
next unless $max_runtime > 0;
if ( time - $started >= $max_runtime ) { $timed_out = 1; last }
next;
}
my $chunk;
my $n = sysread( $reader, $chunk, 65536 );
last if !defined $n; # read error
last if $n == 0; # EOF â the command closed its output
print {$log_fh} $chunk;
print $chunk if $stream_terms;
$output .= $chunk;
}
my $exit_code;
if ($timed_out) {
my $elapsed = time - $started;
$self->_append_log( $repo, "TIMEOUT after ${elapsed}s â sending SIGTERM to $pid" );
kill 'TERM', $pid;
sleep 2;
kill 'KILL', $pid;
waitpid( $pid, 0 );
$exit_code = -1;
} else {
waitpid( $pid, 0 );
$exit_code = $? >> 8;
}
close $reader;
close $log_fh;
my $elapsed = time - $started;
$self->_append_log( $repo, "END elapsed=${elapsed}s exit=$exit_code" );
return ( $exit_code, $output );
}
# ---------------------------------------------------------------------------
# Lock file
# ---------------------------------------------------------------------------
sub _lock_file { path( $_[1]->child('.karr.lock') ) }
sub _lock_held {
my ( $self, $repo ) = @_;
my $lock = $self->_lock_file( $repo );
return 0 unless $lock->exists;
my $pid = $lock->slurp_utf8;
chomp $pid;
return 0 unless $pid =~ /^\d+$/;
# Check if PID is alive
return kill( 0, $pid ) ? 1 : 0;
}
sub _acquire_lock {
my ( $self, $repo ) = @_;
return if $self->dry_run;
$self->_lock_file( $repo )->spew_utf8( "$$\n" );
}
sub _release_lock {
my ( $self, $repo ) = @_;
return if $self->dry_run;
my $lock = $self->_lock_file( $repo );
$lock->remove if $lock->exists;
}
# ---------------------------------------------------------------------------
# State file
# ---------------------------------------------------------------------------
sub _state_file { path( $_[1]->child('.karr.state') ) }
sub _state_get {
my ( $self, $repo, $key ) = @_;
my $state_file = $self->_state_file( $repo );
return undef unless $state_file->exists;
my $data = try { decode_json( $state_file->slurp_utf8 ) } catch { {} };
return $data->{$key};
}
sub _state_set {
my ( $self, $repo, %kv ) = @_;
return if $self->dry_run;
my $state_file = $self->_state_file( $repo );
my $data = {};
if ( $state_file->exists ) {
$data = try { decode_json( $state_file->slurp_utf8 ) } catch { {} };
}
$data->{$_} = $kv{$_} for keys %kv;
$state_file->spew_utf8( encode_json( $data ) );
}
# ---------------------------------------------------------------------------
# Log file
# ---------------------------------------------------------------------------
sub _append_log {
my ( $self, $repo, $msg ) = @_;
my $ts = localtime->strftime('%Y-%m-%dT%H:%M:%S');
my $line = "[$ts] $$: $msg\n";
print $line if $self->verbose;
return if $self->dry_run;
$repo->child('.karr.log')->append_utf8( $line );
}
sub _say_verbose {
my ( $self, $msg ) = @_;
print "$msg\n" if $self->verbose;
}
( run in 1.071 second using v1.01-cache-2.11-cpan-df04353d9ac )