Group
Extension

Devel-QuickCover/bin/qc-html.pl

#!/usr/bin/perl

use strict;
use warnings;

# Generate a Devel::Cover-compatible report file from cover data.

use Digest::MD5 qw(md5_hex);
use File::Path qw(make_path);
use Path::Tiny qw(path);
use Getopt::Long;
use JSON::MaybeXS;
use Sereal qw(encode_sereal decode_sereal);
use Devel::QuickCover::Report;

my $QC_DATABASE   = 'qc.dat';
my $COVERDB       = './cover_db/';
my $VERBOSE       = 0;
my %PATH_REWRITES = ();
my $HELP;
my $HELP_MSG =<<END;
qc-html.pl - Generate a Devel::Cover-compatible report file from cover data.

USE:

    qc-html.pl [OPTION...]

By default, qc-html.pl reads data from the Devel::QuickCover database
$QC_DATABASE and writes its output to the folder $COVERDB.

OPTIONS:

    --input         Devel::QuickCover database to read from. Default $QC_DATABASE.
    --cover-db      Devel::Cover database to write to. Default $COVERDB.
    --verbose       Verbose level. Default 0.
    -h, --help      Print this message and exit.
END

GetOptions('input=s'         => \$QC_DATABASE,
           'cover-db=s'      => \$COVERDB,
           'verbose=i'       => \$VERBOSE,
           'path-rewrite=s%' => \%PATH_REWRITES,
           'h|help'          => \$HELP,
);

my $DIGESTS       = "$COVERDB/digests";
my $STRUCTURE     = "$COVERDB/structure/";
my $RUNS          = "$COVERDB/runs/";

my $JSON          = JSON::MaybeXS->new->utf8->indent;
my $DEVEL_COVER_DB_FORMAT = 'Sereal';
$ENV{DEVEL_COVER_DB_FORMAT}
    and $DEVEL_COVER_DB_FORMAT = 'JSON';

exit main();

sub main {
    if (defined $HELP) {
        print $HELP_MSG;
        return 0;
    }

    my $report = load_data($QC_DATABASE);

    make_coverdb_directories();
    generate_cover_db($report->coverage);

    return 0;
}

sub make_coverdb_directories {
    -d $COVERDB
        or make_path $COVERDB;

    -d $STRUCTURE
        or make_path $STRUCTURE;

    -d $RUNS
        or make_path $RUNS;
}

sub load_data {
    my $file = shift;
    my $report = Devel::QuickCover::Report->new;

    $report->load($file);

    return $report;
}

sub coverdb_decode {
    if ($DEVEL_COVER_DB_FORMAT eq 'JSON') {
       return $JSON->decode(shift);
    }
    return decode_sereal(shift);
}

sub coverdb_encode {
    if ($DEVEL_COVER_DB_FORMAT eq 'JSON') {
        return $JSON->encode(shift);
    }
    return encode_sereal(shift);
}

sub generate_cover_db {
    my $data     = shift;
    my $digests  = {};

    if (-r $DIGESTS) {
        my $digests_data = path($DIGESTS)->slurp_raw;
        $digests //= coverdb_decode( $digests_data );
    }

    my $run = {
        OS        => 'xx',
        collected => [ 'statement' ],
        count     => {},
        digests   => {},
        start     => 0,
        run       => 'xx',
    };

    for my $file (keys %{ $data }) {
        my $original_filename = $file;
        while ( my ($from, $to) = each %PATH_REWRITES ) {
            $file =~ s/$from/$to/;
        }
        if (!-r $file) {
            $VERBOSE and
                print "Skipping $file for now. Probably an eval\n";
            next;
        }

        my $hits       = $data->{ $original_filename };
        my $statements = [ sort { $a <=> $b } keys %$hits ];
        my $md5        = process_file_structure($file, $statements, $digests);

        $run->{count}{$file}{statement} = [ @{$hits}{@$statements}  ];
        $run->{digests}{$file}          = $md5;
    }

    path($DIGESTS)->spew_raw( coverdb_encode($digests) );

    my $run_id = rand(1000);
    my $run_structure = { runs => { $run_id => $run } };
    mkdir ( "$RUNS/$run_id" );

    path("$RUNS/$run_id/cover.14")->spew_raw(
        coverdb_encode( $run_structure )
    );
}

sub process_file_structure {
    my ($file, $statements, $digests) = @_;

    my $content = path($file)->slurp_raw;
    my $md5     = md5_hex( $content );

    if (! exists($digests->{ $md5 })) {
        $digests->{ $md5 } = $file;
        write_structure($file, $md5, $statements);
    }
    return $md5;
}

sub write_structure {
    my ($file, $md5, $statements) = @_;

    my $structure = {
        file       => $file,
        digest     => $md5,
        start      => {},
        statement  => $statements,
        subroutine => [],
    };

    path("$STRUCTURE/$md5")->spew_raw( coverdb_encode( $structure ) );
}


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.