<commit_before>package Smolder::DB::SmokeReport;
use strict;
use warnings;
use base 'Smolder::DB';
use Smolder::Conf qw(InstallRoot);
use Smolder::Email;
use File::Spec::Functions qw(catdir catfile);
use File::Path qw(mkpath);
use File::Temp;
use DateTime::Format::MySQL;
use Test::TAP::XML;
use Test::TAP::HTMLMatrix;
use Test::TAP::Model::Visual;
use YAML;
use Carp qw(croak);
use IO::Zlib;

$SIG{__DIE__} = \*Carp::confess;

__PACKAGE__->set_up_table('smoke_report');

=head1 NAME

Smolder::DB::SmokeReport

=head1 DESCRIPTION

L<Class::DBI> based model class for the 'smoke_report' table in the database.

=head1 METHODS

=head2 ACCESSSOR/MUTATORS

Each column in the borough table has a method with the same name
that can be used as an accessor and mutator.

The following columns will return objects instead of the value contained in the table:

=cut

__PACKAGE__->has_a(
    added   => 'DateTime',
    inflate => sub { DateTime::Format::MySQL->parse_datetime(shift) },
    deflate => sub { DateTime::Format::MySQL->format_datetime(shift) },
);
__PACKAGE__->has_a( developer => 'Smolder::DB::Developer' );
__PACKAGE__->has_a( project   => 'Smolder::DB::Project' );

# when a new object is created, set 'added' to now()
__PACKAGE__->add_trigger(
    before_create => sub {
        my $self = shift;
        $self->_attribute_set( added => DateTime->now( time_zone => 'local' ), );
    },
);

=over

=item added

A L<DateTime> object representing the datetime stored.

=item developer

The L<Smolder::DB::Developer> object who added this report

=item project

The L<Smolder::DB::Project> object that this report is about

=back

=head2 OBJECT METHODS

=head3 file

This returns the file name of where the full XML file for this
smoke report does (or will) reside. If the directory does not
yet exist, it will be created.

=cut

sub file {
    my $self = shift;
    my $date = $self->added()->strftime('%Y%m');
    my $dir  = catdir( InstallRoot, 'data', 'smoke_reports', $self->project->id, $date, );

    # create it if it doesn't exist
    mkpath($dir) if ( !-d $dir );

    return catfile( $dir, $self->id . '.xml.gz' );
}

=head3 html

A reference to the HTML text of this Test Report.

=cut

sub html {
    my $self = shift;

    # if we already have the file then use it
    if ( $self->html_file && -e $self->html_file ) {
        return $self->_slurp_file( $self->html_file );
    }

    # else we need to generate a new HTML file
    my $model = Test::TAP::Model::Visual->new_with_struct( $self->model_obj->structure );

    # create some header text based on the info of the smoke_report
    my $extra = <<END_EXTRA;

Project:      %s
Uploaded:     %s by %s
Platform:     %s
Architecture: %s
Duration      %i secs
Comments:     %s

END_EXTRA
    $extra = sprintf( $extra,
        $self->project->name,       $self->added->strftime('%A, %B %e %Y, %l:%M:%S %p'),
        $self->developer->username, $self->platform || 'Unknown',
        $self->architecture || 'Unknown', $self->duration,
        $self->comments     || 'none', );

    my $v = Test::TAP::HTMLMatrix->new( $model, $extra );
    $v->has_inline_css(1);
    my $html = $v->html;

    # save this to a file
    my $dir = catdir( InstallRoot, 'tmp', 'html_smoke_reports' );
    unless ( -d $dir ) {
        mkpath($dir) or croak "Could not create directory '$dir'! $!";
    }
    my $tmp = new File::Temp(
        UNLINK => 0,
        SUFFIX => '.html',
        DIR    => $dir,
    );
    print $tmp $html
      or croak "Could not print to $tmp! $!";
    close($tmp);
    $self->html_file( $tmp->filename );
    $self->update();
    Smolder::DB->dbi_commit();

    return \$html;
}

=head3 html_nonref 

The L<html> method returns a reference to the full HTML report and this
is almost always what you want. However, in templates, you cannot use
a scalar reference. So instead, this convenience method is supplied to
allow calling it within a template.

=cut

sub html_nonref {
    my $self = shift;
    my $html = $self->html;
    return $$html;
}

sub _slurp_file {
    my ( $self, $file_name ) = @_;
    my $text;
    local $/;
    open( my $IN, $file_name )
      or croak "Could not open file '$file_name' for reading! $!";

    $text = <$IN>;
    close($IN)
      or croak "Could not close file '$file_name'! $!";
    return \$text;
}

=head3 xml

A reference to the XML text of this Test Report.

=cut

sub xml {
    my $self = shift;
    return $self->_slurp_file( $self->file );
}<commit_msg>uncompress the xml going out to the browser<commit_after>package Smolder::DB::SmokeReport;
use strict;
use warnings;
use base 'Smolder::DB';
use Smolder::Conf qw(InstallRoot);
use Smolder::Email;
use File::Spec::Functions qw(catdir catfile);
use File::Path qw(mkpath);
use File::Temp;
use DateTime::Format::MySQL;
use Test::TAP::XML;
use Test::TAP::HTMLMatrix;
use Test::TAP::Model::Visual;
use YAML;
use Carp qw(croak);
use IO::Zlib;

$SIG{__DIE__} = \*Carp::confess;

__PACKAGE__->set_up_table('smoke_report');

=head1 NAME

Smolder::DB::SmokeReport

=head1 DESCRIPTION

L<Class::DBI> based model class for the 'smoke_report' table in the database.

=head1 METHODS

=head2 ACCESSSOR/MUTATORS

Each column in the borough table has a method with the same name
that can be used as an accessor and mutator.

The following columns will return objects instead of the value contained in the table:

=cut

__PACKAGE__->has_a(
    added   => 'DateTime',
    inflate => sub { DateTime::Format::MySQL->parse_datetime(shift) },
    deflate => sub { DateTime::Format::MySQL->format_datetime(shift) },
);
__PACKAGE__->has_a( developer => 'Smolder::DB::Developer' );
__PACKAGE__->has_a( project   => 'Smolder::DB::Project' );

# when a new object is created, set 'added' to now()
__PACKAGE__->add_trigger(
    before_create => sub {
        my $self = shift;
        $self->_attribute_set( added => DateTime->now( time_zone => 'local' ), );
    },
);

=over

=item added

A L<DateTime> object representing the datetime stored.

=item developer

The L<Smolder::DB::Developer> object who added this report

=item project

The L<Smolder::DB::Project> object that this report is about

=back

=head2 OBJECT METHODS

=head3 file

This returns the file name of where the full XML file for this
smoke report does (or will) reside. If the directory does not
yet exist, it will be created.

=cut

sub file {
    my $self = shift;
    my $date = $self->added()->strftime('%Y%m');
    my $dir  = catdir( InstallRoot, 'data', 'smoke_reports', $self->project->id, $date, );

    # create it if it doesn't exist
    mkpath($dir) if ( !-d $dir );

    return catfile( $dir, $self->id . '.xml.gz' );
}

=head3 html

A reference to the HTML text of this Test Report.

=cut

sub html {
    my $self = shift;

    # if we already have the file then use it
    if ( $self->html_file && -e $self->html_file ) {
        return $self->_slurp_file( $self->html_file );
    }

    # else we need to generate a new HTML file
    my $model = Test::TAP::Model::Visual->new_with_struct( $self->model_obj->structure );

    # create some header text based on the info of the smoke_report
    my $extra = <<END_EXTRA;

Project:      %s
Uploaded:     %s by %s
Platform:     %s
Architecture: %s
Duration      %i secs
Comments:     %s

END_EXTRA
    $extra = sprintf( $extra,
        $self->project->name,       $self->added->strftime('%A, %B %e %Y, %l:%M:%S %p'),
        $self->developer->username, $self->platform || 'Unknown',
        $self->architecture || 'Unknown', $self->duration,
        $self->comments     || 'none', );

    my $v = Test::TAP::HTMLMatrix->new( $model, $extra );
    $v->has_inline_css(1);
    my $html = $v->html;

    # save this to a file
    my $dir = catdir( InstallRoot, 'tmp', 'html_smoke_reports' );
    unless ( -d $dir ) {
        mkpath($dir) or croak "Could not create directory '$dir'! $!";
    }
    my $tmp = new File::Temp(
        UNLINK => 0,
        SUFFIX => '.html',
        DIR    => $dir,
    );
    print $tmp $html
      or croak "Could not print to $tmp! $!";
    close($tmp);
    $self->html_file( $tmp->filename );
    $self->update();
    Smolder::DB->dbi_commit();

    return \$html;
}

=head3 html_nonref 

The L<html> method returns a reference to the full HTML report and this
is almost always what you want. However, in templates, you cannot use
a scalar reference. So instead, this convenience method is supplied to
allow calling it within a template.

=cut

sub html_nonref {
    my $self = shift;
    my $html = $self->html;
    return $$html;
}

sub _slurp_file {
    my ( $self, $file_name ) = @_;
    my $text;
    local $/;
    open( my $IN, $file_name )
      or croak "Could not open file '$file_name' for reading! $!";

    $text = <$IN>;
    close($IN)
      or croak "Could not close file '$file_name'! $!";
    return \$text;
}

=head3 xml

A reference to the XML text of this Test Report.

=cut

sub xml {
    my $self = shift;
    my $file = $self->file;

    # return as-is unless compressed
    return $self->_slurp_file( $file )
      unless $file =~ /\.gz$/;

    # uncompress the XML file and return
    my $in_fh = IO::Zlib->new();
    $in_fh->open($file, 'rb')
      or die "Could not open file $file for reading compressed!";

    # IO::Zlib ignores $/ and doesn't support an offset for read(), so
    # the usual faster slurp won't work
    my ($buffer, $xml);
    while(read($in_fh, $buffer, 10240)) {
        $xml .= $buffer;
    }
    $in_fh->close();

    return \$xml;
}
{'fraction_non_alphanumeric': 0.14214963119072707, 'fraction_numerical': 0.002845100105374078, 'mean_word_length': 3.2713771377137713, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 122, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4713003', 'n_tokens_mistral': 3306, 'n_tokens_neox': 3204, 'n_words': 1053}