line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
use 5.010; |
2
|
3
|
|
|
3
|
|
517748
|
use Moose; |
|
3
|
|
|
|
|
36
|
|
3
|
3
|
|
|
3
|
|
1385
|
use MooseX::Types::Path::Class; |
|
3
|
|
|
|
|
1290955
|
|
|
3
|
|
|
|
|
21
|
|
4
|
3
|
|
|
3
|
|
22051
|
use DateTime; |
|
3
|
|
|
|
|
1167617
|
|
|
3
|
|
|
|
|
33
|
|
5
|
3
|
|
|
3
|
|
5839
|
use File::Copy; |
|
3
|
|
|
|
|
1327425
|
|
|
3
|
|
|
|
|
142
|
|
6
|
3
|
|
|
3
|
|
536
|
use HTML::TableExtract; |
|
3
|
|
|
|
|
2034
|
|
|
3
|
|
|
|
|
195
|
|
7
|
3
|
|
|
3
|
|
1766
|
use experimental qw(switch); |
|
3
|
|
|
|
|
37621
|
|
|
3
|
|
|
|
|
18
|
|
8
|
3
|
|
|
3
|
|
1307
|
|
|
3
|
|
|
|
|
2975
|
|
|
3
|
|
|
|
|
16
|
|
9
|
|
|
|
|
|
|
# ABSTRACT: Archive Devel::Cover reports |
10
|
|
|
|
|
|
|
our $VERSION = '1.004'; # VERSION |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
with 'MooseX::Getopt'; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
has [qw(from to)] => (is=>'ro',isa=>'Path::Class::Dir',coerce=>1,required=>1,); |
15
|
|
|
|
|
|
|
has 'project' => (is => 'ro', isa=>'Str', lazy_build=>1); |
16
|
|
|
|
|
|
|
my $self = shift; |
17
|
|
|
|
|
|
|
my @list = $self->from->parent->dir_list; |
18
|
2
|
|
|
2
|
|
5
|
return $list[-1] || 'unknown project'; |
19
|
2
|
|
|
|
|
51
|
} |
20
|
2
|
|
50
|
|
|
280
|
has 'coverage_html' => (is=>'ro',isa=>'Path::Class::File',lazy_build=>1,traits=> ['NoGetopt']); |
21
|
|
|
|
|
|
|
my $self = shift; |
22
|
|
|
|
|
|
|
if (-e $self->from->file('coverage.html')) { |
23
|
|
|
|
|
|
|
return $self->from->file('coverage.html'); |
24
|
4
|
|
|
4
|
|
7
|
} |
25
|
4
|
100
|
|
|
|
92
|
else { |
26
|
3
|
|
|
|
|
404
|
say "Cannot find 'coverage.html' in ".$self->from.'. Aborting'; |
27
|
|
|
|
|
|
|
exit; |
28
|
|
|
|
|
|
|
} |
29
|
1
|
|
|
|
|
142
|
} |
30
|
1
|
|
|
|
|
51
|
has 'runtime' => (is=>'ro',isa=>'DateTime',lazy_build=>1,traits=> ['NoGetopt'],); |
31
|
|
|
|
|
|
|
my $self = shift; |
32
|
|
|
|
|
|
|
return DateTime->from_epoch(epoch=>$self->coverage_html->stat->mtime); |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
has 'archive_html' => (is=>'ro',isa=>'Path::Class::File',lazy_build=>1,traits=> ['NoGetopt']); |
35
|
4
|
|
|
4
|
|
8
|
my $self = shift; |
36
|
4
|
|
|
|
|
105
|
unless (-e $self->to->file('index.html')) { |
37
|
|
|
|
|
|
|
my $tpl = $self->_archive_template; |
38
|
|
|
|
|
|
|
my $fh = $self->to->file('index.html')->openw; |
39
|
|
|
|
|
|
|
print $fh $tpl; |
40
|
2
|
|
|
2
|
|
5
|
close $fh; |
41
|
2
|
100
|
|
|
|
57
|
} |
42
|
1
|
|
|
|
|
173
|
return $self->to->file('index.html'); |
43
|
1
|
|
|
|
|
29
|
} |
44
|
1
|
|
|
|
|
265
|
has 'archive_db' => (is=>'ro',isa=>'Path::Class::File',lazy_build=>1,traits=> ['NoGetopt']); |
45
|
1
|
|
|
|
|
60
|
my $self = shift; |
46
|
|
|
|
|
|
|
return $self->to->file('archive_db'); |
47
|
2
|
|
|
|
|
180
|
} |
48
|
|
|
|
|
|
|
has 'previous_stats' => (is=>'ro',isa=>'ArrayRef',lazy_build=>1,traits=>['NoGetopt']); |
49
|
|
|
|
|
|
|
my $self = shift; |
50
|
|
|
|
|
|
|
if (-e $self->archive_db) { |
51
|
2
|
|
|
2
|
|
5
|
my $dbr = $self->archive_db->openr; |
52
|
2
|
|
|
|
|
49
|
my @data = <$dbr>; # probably better to just get last line... |
53
|
|
|
|
|
|
|
my @prev = split(/;/,$data[-1]); |
54
|
|
|
|
|
|
|
return \@prev; |
55
|
|
|
|
|
|
|
} |
56
|
2
|
|
|
2
|
|
5
|
else { |
57
|
2
|
100
|
|
|
|
72
|
return [undef,0,0,0]; |
58
|
1
|
|
|
|
|
81
|
} |
59
|
1
|
|
|
|
|
167
|
} |
60
|
1
|
|
|
|
|
7
|
has 'diff_html' => (is=>'ro',isa=>'Path::Class::File',lazy_build=>1,traits=> ['NoGetopt']); |
61
|
1
|
|
|
|
|
42
|
my $self = shift; |
62
|
|
|
|
|
|
|
return $self->to->subdir($self->runtime->iso8601)->file('diff.html'); |
63
|
|
|
|
|
|
|
} |
64
|
1
|
|
|
|
|
90
|
|
65
|
|
|
|
|
|
|
my $self = shift; |
66
|
|
|
|
|
|
|
$self->archive; |
67
|
|
|
|
|
|
|
$self->generate_diff; |
68
|
|
|
|
|
|
|
$self->update_index; |
69
|
1
|
|
|
1
|
|
4
|
} |
70
|
1
|
|
|
|
|
46
|
|
71
|
|
|
|
|
|
|
my $self = shift; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my $from = $self->from; |
74
|
4
|
|
|
4
|
0
|
5903
|
my $target = $self->to->subdir($self->runtime->iso8601); |
75
|
4
|
|
|
|
|
14
|
|
76
|
2
|
|
|
|
|
17
|
if (-e $target) { |
77
|
2
|
|
|
|
|
12
|
say "This coverage report has already been archived."; |
78
|
|
|
|
|
|
|
exit; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
4
|
|
|
4
|
0
|
11
|
$target->mkpath; |
82
|
|
|
|
|
|
|
my $target_string = $target->stringify; |
83
|
4
|
|
|
|
|
138
|
|
84
|
4
|
|
|
|
|
96
|
while (my $f = $from->next) { |
85
|
|
|
|
|
|
|
next unless $f=~/\.(html|css)$/; |
86
|
3
|
100
|
|
|
|
214
|
copy($f->stringify,$target_string) || die "Cannot copy $from to $target_string: $!"; |
87
|
1
|
|
|
|
|
58
|
} |
88
|
1
|
|
|
|
|
7
|
|
89
|
|
|
|
|
|
|
say "archived coverage reports at $target_string"; |
90
|
|
|
|
|
|
|
} |
91
|
2
|
|
|
|
|
84
|
|
92
|
2
|
|
|
|
|
470
|
my $self = shift; |
93
|
|
|
|
|
|
|
|
94
|
2
|
|
|
|
|
87
|
my $te = HTML::TableExtract->new( headers => [qw(stm sub total)] ); |
95
|
22
|
100
|
|
|
|
6689
|
$te->parse(scalar $self->coverage_html->slurp); |
96
|
12
|
50
|
|
|
|
337
|
my $rows =$te->rows; |
97
|
|
|
|
|
|
|
my $last_row = $rows->[-1]; |
98
|
|
|
|
|
|
|
|
99
|
2
|
|
|
|
|
927
|
$self->update_archive_html($last_row); |
100
|
|
|
|
|
|
|
$self->update_archive_db($last_row); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
2
|
|
|
2
|
0
|
4
|
my ($self, $last_row) = @_; |
104
|
|
|
|
|
|
|
|
105
|
2
|
|
|
|
|
40
|
my $prev_stats = $self->previous_stats; |
106
|
2
|
|
|
|
|
338
|
my $runtime = $self->runtime; |
107
|
2
|
|
|
|
|
9453
|
my $date = $runtime->ymd('-').' '.$runtime->hms; |
108
|
2
|
|
|
|
|
417
|
my $link = "./".$runtime->iso8601."/coverage.html"; |
109
|
|
|
|
|
|
|
my $diff = "./".$runtime->iso8601."/diff.html"; |
110
|
2
|
|
|
|
|
9
|
|
111
|
2
|
|
|
|
|
926
|
my $new_stat = qq{\n<tr><td><a href="$link">$date</a></td><td><a href="$diff">diff</a></td>}; |
112
|
|
|
|
|
|
|
foreach my $val (@$last_row) { |
113
|
|
|
|
|
|
|
$new_stat.=$self->td_style($val); |
114
|
|
|
|
|
|
|
} |
115
|
2
|
|
|
2
|
0
|
6
|
my $prev_total = $prev_stats->[3]; |
116
|
|
|
|
|
|
|
my $this_total = $last_row->[-1]; |
117
|
2
|
|
|
|
|
69
|
if ($this_total == $prev_total) { |
118
|
2
|
|
|
|
|
50
|
$new_stat.=qq{<td class="c3">=</td>}; |
119
|
2
|
|
|
|
|
12
|
} |
120
|
2
|
|
|
|
|
51
|
elsif ($this_total > $prev_total) { |
121
|
2
|
|
|
|
|
47
|
$new_stat.=qq{<td class="c3">+</td>}; |
122
|
|
|
|
|
|
|
} |
123
|
2
|
|
|
|
|
41
|
else { |
124
|
2
|
|
|
|
|
6
|
$new_stat.=qq{<td class="c0">-</td>}; |
125
|
6
|
|
|
|
|
16
|
} |
126
|
|
|
|
|
|
|
|
127
|
2
|
|
|
|
|
6
|
$new_stat.="</tr>\n"; |
128
|
2
|
|
|
|
|
4
|
|
129
|
2
|
50
|
|
|
|
11
|
my $archive = $self->archive_html->slurp; |
|
|
50
|
|
|
|
|
|
130
|
0
|
|
|
|
|
0
|
$archive =~ s/(<!-- INSERT -->)/$1 . $new_stat/e; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
my $fh = $self->archive_html->openw; |
133
|
2
|
|
|
|
|
14
|
print $fh $archive; |
134
|
|
|
|
|
|
|
close $fh; |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
0
|
unless (-e $self->to->file('cover.css')) { |
137
|
|
|
|
|
|
|
copy($self->from->file('cover.css'),$self->to->file('cover.css')) || warn "Cannot copy cover.css: $!"; |
138
|
|
|
|
|
|
|
} |
139
|
2
|
|
|
|
|
11
|
} |
140
|
|
|
|
|
|
|
|
141
|
2
|
|
|
|
|
65
|
my ($self, $last_row) = @_; |
142
|
2
|
|
|
|
|
393
|
my $dbw = $self->archive_db->open(">>") || warn "Can't write archive.db: $!"; |
|
2
|
|
|
|
|
62
|
|
143
|
|
|
|
|
|
|
say $dbw join(';',$self->runtime->iso8601,@$last_row); |
144
|
2
|
|
|
|
|
65
|
close $dbw; |
145
|
2
|
|
|
|
|
355
|
} |
146
|
2
|
|
|
|
|
212
|
|
147
|
|
|
|
|
|
|
my $self = shift; |
148
|
2
|
100
|
|
|
|
72
|
|
149
|
1
|
50
|
|
|
|
144
|
my $prev = $self->previous_stats; |
150
|
|
|
|
|
|
|
return unless $prev->[0]; |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
my $te_new = HTML::TableExtract->new( headers => [qw(file stm sub total)] ); |
153
|
|
|
|
|
|
|
$te_new->parse(scalar $self->coverage_html->slurp); |
154
|
2
|
|
|
2
|
0
|
7
|
my $new_rows =$te_new->rows; |
155
|
2
|
|
33
|
|
|
65
|
my $te_old = HTML::TableExtract->new( headers => [qw(file stm sub total)] ); |
156
|
2
|
|
|
|
|
378
|
$te_old->parse(scalar $self->to->subdir($prev->[0])->file('coverage.html')->slurp); |
157
|
2
|
|
|
|
|
207
|
my $old_rows =$te_old->rows; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
my %diff; |
160
|
|
|
|
|
|
|
foreach my $row (@$new_rows) { |
161
|
2
|
|
|
2
|
0
|
5
|
my $file =shift(@$row); |
162
|
|
|
|
|
|
|
$diff{$file}=$row; |
163
|
2
|
|
|
|
|
77
|
} |
164
|
2
|
100
|
|
|
|
8
|
|
165
|
|
|
|
|
|
|
foreach my $row (@$old_rows) { |
166
|
1
|
|
|
|
|
14
|
my $file =shift(@$row); |
167
|
1
|
|
|
|
|
198
|
push(@{$diff{$file}},@$row); |
168
|
1
|
|
|
|
|
4987
|
} |
169
|
1
|
|
|
|
|
283
|
|
170
|
1
|
|
|
|
|
160
|
my @output; |
171
|
1
|
|
|
|
|
4809
|
foreach my $file (sort keys %diff) { |
172
|
|
|
|
|
|
|
my $data = $diff{$file}; |
173
|
1
|
|
|
|
|
207
|
|
174
|
1
|
|
|
|
|
4
|
my $line = qq{\n<tr><td>$file</td>}; |
175
|
2
|
|
|
|
|
4
|
foreach my $i (0,1,2) { |
176
|
2
|
|
|
|
|
6
|
my $nv = $data->[$i] || 0; |
177
|
|
|
|
|
|
|
my $ov = $data->[$i+3] || 0; |
178
|
|
|
|
|
|
|
my $display = "$ov -> $nv"; |
179
|
1
|
|
|
|
|
4
|
if ($nv == $ov) { |
180
|
2
|
|
|
|
|
6
|
$line.=qq{<td>$display</td>}; |
181
|
2
|
|
|
|
|
4
|
} |
|
2
|
|
|
|
|
6
|
|
182
|
|
|
|
|
|
|
elsif ($nv > $ov) { |
183
|
|
|
|
|
|
|
$line.=$self->td_style(100,$display); |
184
|
1
|
|
|
|
|
2
|
} |
185
|
1
|
|
|
|
|
5
|
else { |
186
|
2
|
|
|
|
|
12
|
$line.=$self->td_style(0,$display); |
187
|
|
|
|
|
|
|
} |
188
|
2
|
|
|
|
|
10
|
} |
189
|
2
|
|
|
|
|
4
|
$line.="</tr>"; |
190
|
6
|
|
50
|
|
|
16
|
push(@output,$line); |
191
|
6
|
|
50
|
|
|
9
|
} |
192
|
6
|
|
|
|
|
12
|
my $table = join("\n",@output); |
193
|
6
|
50
|
|
|
|
20
|
my $tpl = $self->_diff_template; |
|
|
50
|
|
|
|
|
|
194
|
0
|
|
|
|
|
0
|
$tpl=~s/DATA/$table/; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
my $fh = $self->diff_html->openw; |
197
|
6
|
|
|
|
|
12
|
print $fh $tpl; |
198
|
|
|
|
|
|
|
close $fh; |
199
|
|
|
|
|
|
|
} |
200
|
0
|
|
|
|
|
0
|
|
201
|
|
|
|
|
|
|
my ($self, $val, $display) = @_; |
202
|
|
|
|
|
|
|
$display //=$val; |
203
|
2
|
|
|
|
|
5
|
my $style; |
204
|
2
|
|
|
|
|
5
|
given ($val) { |
205
|
|
|
|
|
|
|
when ($_ < 75) { $style = 'c0' } |
206
|
1
|
|
|
|
|
16
|
when ($_ < 90) { $style = 'c1' } |
207
|
1
|
|
|
|
|
5
|
when ($_ < 100) { $style = 'c2' } |
208
|
1
|
|
|
|
|
15
|
when ($_ >= 100) { $style = 'c3' } |
209
|
|
|
|
|
|
|
} |
210
|
1
|
|
|
|
|
42
|
return qq{<td class="$style">$display</td>}; |
211
|
1
|
|
|
|
|
216
|
} |
212
|
1
|
|
|
|
|
120
|
|
213
|
|
|
|
|
|
|
my $self = shift; |
214
|
|
|
|
|
|
|
my $name = $self->project; |
215
|
|
|
|
|
|
|
$self->_page_template( |
216
|
12
|
|
|
12
|
0
|
20
|
"Test Coverage Archive for $name", |
217
|
12
|
|
66
|
|
|
37
|
q{ |
218
|
12
|
|
|
|
|
13
|
<table> |
219
|
12
|
|
|
|
|
15
|
<tr><th>Coverage Report</th><th>diff</th><th>stmt</th><th>sub</th><th>total</th><th>Trend</th></tr> |
220
|
12
|
|
|
|
|
24
|
<!-- INSERT --> |
|
3
|
|
|
|
|
5
|
|
221
|
9
|
|
|
|
|
33
|
</table> |
|
2
|
|
|
|
|
7
|
|
222
|
7
|
|
|
|
|
24
|
}); |
|
0
|
|
|
|
|
0
|
|
223
|
7
|
|
|
|
|
8
|
} |
|
7
|
|
|
|
|
21
|
|
224
|
|
|
|
|
|
|
|
225
|
12
|
|
|
|
|
47
|
my $self = shift; |
226
|
|
|
|
|
|
|
my $name = $self->project; |
227
|
|
|
|
|
|
|
$self->_page_template( |
228
|
|
|
|
|
|
|
"Test Coverage Diff for $name", |
229
|
1
|
|
|
1
|
|
3
|
q{ |
230
|
1
|
|
|
|
|
42
|
<table> |
231
|
1
|
|
|
|
|
6
|
<tr><th>File</th><th>stmt</th><th>sub</th><th>total</th></tr> |
232
|
|
|
|
|
|
|
DATA |
233
|
|
|
|
|
|
|
</table> |
234
|
|
|
|
|
|
|
}); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
my ($self, $title, $content) = @_; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
my $name = $self->project; |
240
|
|
|
|
|
|
|
my $class = ref($self); |
241
|
|
|
|
|
|
|
my $version = $class->VERSION; |
242
|
1
|
|
|
1
|
|
2
|
return <<"EOTMPL"; |
243
|
1
|
|
|
|
|
37
|
<!DOCTYPE html |
244
|
1
|
|
|
|
|
7
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
245
|
|
|
|
|
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
246
|
|
|
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml"> |
247
|
|
|
|
|
|
|
<!-- This file was generated by $class version $version --> |
248
|
|
|
|
|
|
|
<head> |
249
|
|
|
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta> |
250
|
|
|
|
|
|
|
<meta http-equiv="Content-Language" content="en-us"></meta> |
251
|
|
|
|
|
|
|
<link rel="stylesheet" type="text/css" href="cover.css"></link> |
252
|
|
|
|
|
|
|
<title>Test Coverage Archive for $name</title> |
253
|
|
|
|
|
|
|
</head> |
254
|
|
|
|
|
|
|
<body> |
255
|
2
|
|
|
2
|
|
7
|
|
256
|
|
|
|
|
|
|
<body> |
257
|
2
|
|
|
|
|
57
|
<h1>$title</h1> |
258
|
2
|
|
|
|
|
5
|
|
259
|
2
|
|
|
|
|
43
|
$content |
260
|
2
|
|
|
|
|
27
|
|
261
|
|
|
|
|
|
|
<p>Generated by <a href="http://metacpan.org/module/$class">$class</a> version $version.</p> |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
</body> |
264
|
|
|
|
|
|
|
</html> |
265
|
|
|
|
|
|
|
EOTMPL |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
270
|
|
|
|
|
|
|
1; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=pod |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=encoding UTF-8 |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head1 NAME |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
App::ArchiveDevelCover - Archive Devel::Cover reports |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=head1 VERSION |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
version 1.004 |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=head1 SYNOPSIS |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Backend for the C<archive_devel_cover.pl> command. See L<archive_devel_cover.pl> and/or C<perldoc archive_devel_cover.pl> for details. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=head1 AUTHOR |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Thomas Klausner <domm@plix.at> |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
This software is copyright (c) 2012 - 2022 by Thomas Klausner. |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
298
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=cut |