+sub BUILD {
+ my ($self,$args) = @_;
+ if (not ($self->_has_bug_num or
+ $self->_has_logfh or
+ $self->_has_log_name)) {
+ croak "Exactly one of bug_num, logfh, or log_name ".
+ "must be passed and must be defined";
+ }
+}
+
+has 'bug_num' =>
+ (is => 'ro',
+ isa => 'Int',
+ predicate => '_has_bug_num',
+ );
+
+has 'logfh' =>
+ (is => 'ro',
+ lazy => 1,
+ builder => '_build_logfh',
+ predicate => '_has_logfh',
+ );
+
+sub _build_logfh {
+ my $self = shift;
+ my $bug_log =
+ $self->log_name;
+ my $log_fh;
+ if ($bug_log =~ m/\.gz$/) {
+ my $oldpath = $ENV{'PATH'};
+ $ENV{'PATH'} = '/bin:/usr/bin';
+ open($log_fh,'-|','gzip','-dc',$bug_log) or
+ die "Unable to open $bug_log for reading: $!";
+ $ENV{'PATH'} = $oldpath;
+ } else {
+ open($log_fh,'<',$bug_log) or
+ die "Unable to open $bug_log for reading: $!";
+ }
+ return $log_fh;
+}
+
+has 'log_name' =>
+ (is => 'ro',
+ isa => 'Str',
+ lazy => 1,
+ builder => '_build_log_name',
+ predicate => '_has_log_name',
+ );
+
+sub _build_log_name {
+ my $self = shift;
+ my $location = getbuglocation($self->bug_num,'log');
+ return getbugcomponent($self->bug_num,'log',$location);
+}
+
+has 'inner_file' =>
+ (is => 'ro',
+ isa => 'Bool',
+ default => 0,
+ );
+
+has 'state' =>
+ (is => 'ro',
+ isa => 'Str',
+ default => 'kill-init',
+ writer => '_state',
+ );
+
+sub state_transition {
+ my $self = shift;
+ my $new_state = shift;
+ my $old_state = $self->state;
+ local $_ = "$old_state $new_state";
+ unless (/^(go|go-nox|html) kill-end$/ or
+ /^(kill-init|kill-end) (incoming-recv|autocheck|recips|html)$/ or
+ /^autocheck autowait$/ or
+ /^autowait go-nox$/ or
+ /^recips kill-body$/ or
+ /^(kill-body|incoming-recv) go$/) {
+ confess "transition from $old_state to $new_state at $self->linenum disallowed";
+ }
+ $self->_state($new_state);
+}
+
+sub increment_linenum {
+ my $self = shift;
+ $self->_linenum($self->_linenum+1);