line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CPAN::Testers::WWW::Statistics::Pages; |
2
|
|
|
|
|
|
|
|
3
|
15
|
|
|
15
|
|
53195
|
use warnings; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
432
|
|
4
|
15
|
|
|
15
|
|
71
|
use strict; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
281
|
|
5
|
15
|
|
|
15
|
|
64
|
use vars qw($VERSION); |
|
15
|
|
|
|
|
35
|
|
|
15
|
|
|
|
|
706
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
$VERSION = '1.23'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#---------------------------------------------------------------------------- |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
CPAN::Testers::WWW::Statistics::Pages - CPAN Testers Statistics pages. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my %hash = { config => 'options' }; |
18
|
|
|
|
|
|
|
my $obj = CPAN::Testers::WWW::Statistics->new(%hash); |
19
|
|
|
|
|
|
|
my $ct = CPAN::Testers::WWW::Statistics::Pages->new(parent => $obj); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
$ct->update_full(); # updates statistics data and web pages |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# alternatively called individual processes |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
$ct->update_data(); # updates statistics data |
26
|
|
|
|
|
|
|
$ct->build_basics(); # updates basic web pages |
27
|
|
|
|
|
|
|
$ct->build_matrices(); # updates matrix style web pages |
28
|
|
|
|
|
|
|
$ct->build_stats(); # updates stats style web pages |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 DESCRIPTION |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
Using the cpanstats database, this module extracts all the data and generates |
33
|
|
|
|
|
|
|
all the HTML pages needed for the CPAN Testers Statistics website. In addition, |
34
|
|
|
|
|
|
|
also generates the data files in order generate the graphs that appear on the |
35
|
|
|
|
|
|
|
site. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Note that this package should not be called directly, but via its parent as: |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my %hash = { config => 'options' }; |
40
|
|
|
|
|
|
|
my $obj = CPAN::Testers::WWW::Statistics->new(%hash); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
$obj->make_pages(); # updates statistics data and web pages |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# alternatively called individual processes |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
$obj->update(); # updates statistics data |
47
|
|
|
|
|
|
|
$obj->make_basics(); # updates basic web pages |
48
|
|
|
|
|
|
|
$obj->make_matrix(); # updates matrix style web pages |
49
|
|
|
|
|
|
|
$obj->make_stats(); # updates stats style web pages |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=cut |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# ------------------------------------- |
54
|
|
|
|
|
|
|
# Library Modules |
55
|
|
|
|
|
|
|
|
56
|
15
|
|
|
15
|
|
6966
|
use Data::Dumper; |
|
15
|
|
|
|
|
75383
|
|
|
15
|
|
|
|
|
943
|
|
57
|
15
|
|
|
15
|
|
10105
|
use DateTime; |
|
15
|
|
|
|
|
6628194
|
|
|
15
|
|
|
|
|
712
|
|
58
|
15
|
|
|
15
|
|
137
|
use File::Basename; |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
1295
|
|
59
|
15
|
|
|
15
|
|
7998
|
use File::Copy; |
|
15
|
|
|
|
|
24902
|
|
|
15
|
|
|
|
|
802
|
|
60
|
15
|
|
|
15
|
|
104
|
use File::Path; |
|
15
|
|
|
|
|
43
|
|
|
15
|
|
|
|
|
659
|
|
61
|
15
|
|
|
15
|
|
5931
|
use File::Slurp; |
|
15
|
|
|
|
|
44931
|
|
|
15
|
|
|
|
|
1022
|
|
62
|
15
|
|
|
15
|
|
744
|
use HTML::Entities; |
|
15
|
|
|
|
|
5100
|
|
|
15
|
|
|
|
|
753
|
|
63
|
15
|
|
|
15
|
|
590
|
use IO::File; |
|
15
|
|
|
|
|
6752
|
|
|
15
|
|
|
|
|
1887
|
|
64
|
15
|
|
|
15
|
|
8189
|
use JSON; |
|
15
|
|
|
|
|
114932
|
|
|
15
|
|
|
|
|
113
|
|
65
|
15
|
|
|
15
|
|
8151
|
use Sort::Versions; |
|
15
|
|
|
|
|
7529
|
|
|
15
|
|
|
|
|
1603
|
|
66
|
15
|
|
|
15
|
|
6252
|
use Template; |
|
15
|
|
|
|
|
225645
|
|
|
15
|
|
|
|
|
478
|
|
67
|
|
|
|
|
|
|
#use Time::HiRes qw ( time ); |
68
|
15
|
|
|
15
|
|
7177
|
use Time::Piece; |
|
15
|
|
|
|
|
100644
|
|
|
15
|
|
|
|
|
95
|
|
69
|
15
|
|
|
15
|
|
1276
|
use Try::Tiny; |
|
15
|
|
|
|
|
45
|
|
|
15
|
|
|
|
|
174633
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# ------------------------------------- |
72
|
|
|
|
|
|
|
# Variables |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
my %month = ( |
75
|
|
|
|
|
|
|
0 => 'January', 1 => 'February', 2 => 'March', 3 => 'April', |
76
|
|
|
|
|
|
|
4 => 'May', 5 => 'June', 6 => 'July', 7 => 'August', |
77
|
|
|
|
|
|
|
8 => 'September', 9 => 'October', 10 => 'November', 11 => 'December' |
78
|
|
|
|
|
|
|
); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
my @months = map { $month{$_} } keys %month; |
81
|
|
|
|
|
|
|
my @days = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday); |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
my $ADAY = 86400; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
my %matrix_limits = ( |
86
|
|
|
|
|
|
|
all => [ 1000, 5000 ], |
87
|
|
|
|
|
|
|
month => [ 100, 500 ] |
88
|
|
|
|
|
|
|
); |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# ------------------------------------- |
91
|
|
|
|
|
|
|
# Subroutines |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 INTERFACE |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head2 The Constructor |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=over 4 |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item * new |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Page creation object. Allows the user to turn or off the progress tracking. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
new() takes an option hash as an argument, which may contain 'progress => 1' |
104
|
|
|
|
|
|
|
to turn on the progress tracker. |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=back |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=cut |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub new { |
111
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
112
|
0
|
|
|
|
|
|
my %hash = @_; |
113
|
|
|
|
|
|
|
|
114
|
0
|
0
|
|
|
|
|
die "Must specify the parent statistics object\n" unless(defined $hash{parent}); |
115
|
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
my $self = {parent => $hash{parent}}; |
117
|
0
|
|
|
|
|
|
bless $self, $class; |
118
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
|
$self->setdates(); |
120
|
0
|
|
|
|
|
|
return $self; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=head2 Public Methods |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=over 4 |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item * setdates |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Prime all key date variable. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item * update_full |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Full update of data and pages. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item * update_data |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
Update data and store in JSON format. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=item * build_basics |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
Create the basic set of pages,those require no statistical calculation. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=item * build_matrices |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Create the matrices pages and distribution list pages. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item * build_stats |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Create all other statistical pages; monthly tables, interesting stats, etc. |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=item * build_leaders |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Create all OS Leaderboards. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=item * build_cpan |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Create/update the CPAN specific statistics data files and pages. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item * build_performance |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Create/update the builder performance data file. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item * build_noreports |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Create all OS no report pages. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=back |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=cut |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub setdates { |
172
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
173
|
0
|
|
0
|
|
|
|
my $time = shift || time; |
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
$self->{parent}->_log("init"); |
176
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
|
Time::Piece::day_list(@days); |
178
|
0
|
|
|
|
|
|
Time::Piece::mon_list(@months); |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# timestamp for now |
181
|
0
|
|
|
|
|
|
my $t = localtime($time); |
182
|
0
|
|
|
|
|
|
$self->{dates}{RUNTIME} = $t->strftime("%a, %e %b %Y %T %Z"); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# todays date |
185
|
0
|
|
|
|
|
|
my @datetime = localtime($time); |
186
|
0
|
|
|
|
|
|
my $THISYEAR = ($datetime[5] + 1900); |
187
|
0
|
|
|
|
|
|
my $THISMONTH = ($datetime[4]); |
188
|
0
|
|
|
|
|
|
$self->{dates}{RUNDATE} = sprintf "%d%s %s %d", $datetime[3], _ext($datetime[3]), $month{$THISMONTH}, $THISYEAR; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# THISMONTH is the last date for all data |
191
|
0
|
|
|
|
|
|
$self->{dates}{THISMONTH} = ($THISYEAR) * 100 + $THISMONTH + 1; |
192
|
0
|
|
|
|
|
|
$self->{dates}{THISDATE} = sprintf "%s %d", $month{int($THISMONTH)}, $THISYEAR; |
193
|
|
|
|
|
|
|
|
194
|
0
|
|
|
|
|
|
my $THATMONTH = $THISMONTH - 1; |
195
|
0
|
|
|
|
|
|
my $THATYEAR = $THISYEAR; |
196
|
0
|
0
|
|
|
|
|
if($THATMONTH < 0) { |
197
|
0
|
|
|
|
|
|
$THATMONTH = 11; |
198
|
0
|
|
|
|
|
|
$THATYEAR--; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# LASTMONTH is the Month/Year stats are run for |
202
|
0
|
|
|
|
|
|
$self->{dates}{LASTMONTH} = sprintf "%04d%02d", $THATYEAR, int($THATMONTH+1); |
203
|
0
|
|
|
|
|
|
$self->{dates}{LASTDATE} = sprintf "%s %d", $month{int($THATMONTH)}, $THATYEAR; |
204
|
0
|
|
|
|
|
|
$self->{dates}{PREVMONTH} = sprintf "%02d/%02d", int($THATMONTH+1), $THATYEAR - 2000; |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
$THATMONTH--; |
207
|
0
|
0
|
|
|
|
|
if($THATMONTH < 0) { |
208
|
0
|
|
|
|
|
|
$THATMONTH = 11; |
209
|
0
|
|
|
|
|
|
$THATYEAR--; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# THATMONTH is the previous Month/Year for a full matrix |
213
|
0
|
|
|
|
|
|
$self->{dates}{THATMONTH} = sprintf "%04d%02d", $THATYEAR, int($THATMONTH+1); |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
|
$self->{parent}->_log( "THISYEAR=[$THISYEAR]" ); |
216
|
0
|
|
|
|
|
|
$self->{parent}->_log( "THATYEAR=[$THATYEAR]" ); |
217
|
0
|
|
|
|
|
|
$self->{parent}->_log( "DATES=" . Dumper( $self->{dates} ) ); |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# calculate database metrics |
220
|
0
|
|
|
|
|
|
my @rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT fulldate FROM cpanstats ORDER BY id DESC LIMIT 1"); |
221
|
0
|
|
|
|
|
|
my @time = $rows[0]->[0] =~ /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/; |
222
|
0
|
|
|
|
|
|
$self->{dates}{RUNDATE2} = sprintf "%d%s %s %d", $time[2],_ext($time[2]),$month{$time[1]-1},$time[0]; |
223
|
0
|
|
|
|
|
|
$self->{dates}{RUNDATE3} = sprintf "%d%s %s %d, %02d:%02d", $time[2],_ext($time[2]),$month{$time[1]-1},$time[0],$time[3],$time[4]; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub update_full { |
227
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
$self->{parent}->_log("start update_full"); |
230
|
0
|
|
|
|
|
|
$self->build_basics(); |
231
|
0
|
|
|
|
|
|
$self->build_data(); |
232
|
0
|
|
|
|
|
|
$self->build_matrices(); |
233
|
0
|
|
|
|
|
|
$self->build_stats(); |
234
|
0
|
|
|
|
|
|
$self->build_leaders(); |
235
|
0
|
|
|
|
|
|
$self->{parent}->_log("finish update_full"); |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
sub update_data { |
239
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
240
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
$self->{parent}->_log("start update_data"); |
242
|
0
|
|
|
|
|
|
$self->build_data(); |
243
|
0
|
|
|
|
|
|
$self->{parent}->_log("finish update_data"); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub build_basics { |
247
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
$self->{parent}->_log("start build_basics"); |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
## BUILD INFREQUENT PAGES |
252
|
0
|
|
|
|
|
|
$self->_write_basics(); |
253
|
0
|
|
|
|
|
|
$self->_missing_in_action(); |
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
$self->{parent}->_log("finish build_basics"); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub build_matrices { |
259
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
$self->{parent}->_log("start build_matrices"); |
262
|
0
|
|
|
|
|
|
$self->storage_read(); |
263
|
0
|
0
|
|
|
|
|
if($self->{perls}) { |
264
|
0
|
|
|
|
|
|
$self->{parent}->_log("building dist hash from storage"); |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
my @versions = sort {versioncmp($b,$a)} keys %{$self->{perls}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
$self->{versions} = \@versions; |
268
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
|
$self->_build_osname_matrix(); |
270
|
0
|
|
|
|
|
|
$self->_build_platform_matrix(); |
271
|
|
|
|
|
|
|
} |
272
|
0
|
|
|
|
|
|
$self->{parent}->_log("finish build_matrices"); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub build_stats { |
276
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
277
|
|
|
|
|
|
|
|
278
|
0
|
|
|
|
|
|
$self->{parent}->_log("stats start"); |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
|
$self->{parent}->_log("building dist hash from storage"); |
281
|
0
|
|
|
|
|
|
$self->storage_read(); |
282
|
0
|
|
|
|
|
|
my $testers = $self->storage_read('testers'); |
283
|
0
|
|
|
|
|
|
$self->{parent}->_log("dist hash from storage built"); |
284
|
|
|
|
|
|
|
|
285
|
0
|
0
|
|
|
|
|
if($testers) { |
286
|
0
|
|
|
|
|
|
for my $tester (keys %$testers) { |
287
|
0
|
|
|
|
|
|
$self->{counts}{$testers->{$tester}{first}}{first}++; |
288
|
0
|
|
|
|
|
|
$self->{counts}{$testers->{$tester}{last}}{last}++; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
0
|
|
|
|
|
|
$testers = {}; # save memory |
292
|
0
|
|
|
|
|
|
$self->{parent}->_log("tester counts built"); |
293
|
|
|
|
|
|
|
|
294
|
0
|
|
|
|
|
|
my @versions = sort {versioncmp($b,$a)} keys %{$self->{perls}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
295
|
0
|
|
|
|
|
|
$self->{versions} = \@versions; |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
## BUILD INDEPENDENT STATS |
298
|
0
|
|
|
|
|
|
$self->_build_sizes(); |
299
|
0
|
|
|
|
|
|
$self->_report_cpan(); |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
## BUILD MONTHLY STATS |
302
|
0
|
|
|
|
|
|
$self->_build_monthly_stats(); |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
## BUILD STATS PAGES |
305
|
0
|
|
|
|
|
|
$self->_report_interesting(); |
306
|
0
|
|
|
|
|
|
$self->_build_monthly_stats_files(); |
307
|
0
|
|
|
|
|
|
$self->_build_failure_rates(); |
308
|
0
|
|
|
|
|
|
$self->_build_performance_stats(); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
## BUILD INDEX PAGE |
311
|
0
|
|
|
|
|
|
$self->_write_index(); |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
0
|
|
|
|
|
|
$self->{parent}->_log("stats finish"); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub build_cpan { |
318
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
319
|
|
|
|
|
|
|
|
320
|
0
|
|
|
|
|
|
$self->{parent}->_log("cpan stats start"); |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
## BUILD INDEPENDENT STATS |
323
|
0
|
|
|
|
|
|
$self->_build_sizes(); |
324
|
0
|
|
|
|
|
|
$self->_report_cpan(); |
325
|
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
$self->{parent}->_log("cpan stats finish"); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub build_performance { |
330
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
331
|
|
|
|
|
|
|
|
332
|
0
|
|
|
|
|
|
$self->{parent}->_log("performance start"); |
333
|
0
|
|
|
|
|
|
$self->{build} = $self->storage_read('build'); |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
## BUILD PERFORMANCE FILES |
336
|
0
|
|
|
|
|
|
$self->_build_performance_stats(); |
337
|
|
|
|
|
|
|
|
338
|
0
|
|
|
|
|
|
$self->{parent}->_log("performance finish"); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub build_leaders { |
342
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
343
|
|
|
|
|
|
|
|
344
|
0
|
|
|
|
|
|
$self->{parent}->_log("leaders start"); |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
## BUILD OS LEADERBOARDS |
347
|
0
|
|
|
|
|
|
$self->_build_osname_leaderboards(); |
348
|
|
|
|
|
|
|
|
349
|
0
|
|
|
|
|
|
$self->{parent}->_log("leaders finish"); |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
sub build_noreports { |
353
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
354
|
|
|
|
|
|
|
|
355
|
0
|
|
|
|
|
|
$self->{parent}->_log("noreports start"); |
356
|
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
|
$self->_build_noreports(); |
358
|
|
|
|
|
|
|
|
359
|
0
|
|
|
|
|
|
$self->{parent}->_log("noreports finish"); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
=head2 Private Methods |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=head3 Data Methods |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=over 4 |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=item * build_data |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=item * storage_read |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=item * storage_write |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=back |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=cut |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub build_data { |
379
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
380
|
|
|
|
|
|
|
|
381
|
0
|
|
|
|
|
|
$self->{parent}->_log("building rate hash"); |
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
|
my ($d1,$d2) = (time(), time() - $ADAY); |
384
|
0
|
|
|
|
|
|
my @date = localtime($d2); |
385
|
0
|
|
|
|
|
|
my $date = sprintf "%04d%02d%02d", $date[5]+1900, $date[4]+1, $date[3]; |
386
|
0
|
|
|
|
|
|
my @tday = localtime($d1); |
387
|
0
|
|
|
|
|
|
my $tday = sprintf "%04d%02d%02d", $tday[5]+1900, $tday[4]+1, $tday[3]; |
388
|
|
|
|
|
|
|
|
389
|
0
|
|
0
|
|
|
|
my $lastid = $self->storage_read('lastid') || 0; |
390
|
0
|
|
|
|
|
|
my $testers = {}; |
391
|
|
|
|
|
|
|
|
392
|
0
|
0
|
|
|
|
|
if($lastid) { |
393
|
0
|
|
|
|
|
|
$self->{parent}->_log("building dist hash from storage"); |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
|
$self->storage_read(); |
396
|
0
|
|
|
|
|
|
$testers = $self->storage_read('testers'); |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
# only remember the latest release for 'dists' hash |
399
|
0
|
|
|
|
|
|
my $iterator = $self->{parent}->{CPANSTATS}->iterator('hash',"SELECT dist,version FROM ixlatest"); |
400
|
0
|
|
|
|
|
|
while(my $row = $iterator->()) { |
401
|
0
|
0
|
0
|
|
|
|
next if($self->{dists}{$row->{dist}} && $self->{dists}{$row->{dist}}->{VER} eq $row->{version}); |
402
|
0
|
|
|
|
|
|
$self->{dists}{$row->{dist}} = { ALL => 0, IXL => 0, VER => $row->{version}}; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
} else { |
406
|
0
|
|
|
|
|
|
$self->{parent}->_log("building dist hash from scratch"); |
407
|
|
|
|
|
|
|
|
408
|
0
|
|
|
|
|
|
my $iterator = $self->{parent}->{CPANSTATS}->iterator('hash',"SELECT dist,version FROM ixlatest"); |
409
|
0
|
|
|
|
|
|
while(my $row = $iterator->()) { |
410
|
0
|
|
|
|
|
|
$self->{dists}{$row->{dist}}->{ALL} = 0; |
411
|
0
|
|
|
|
|
|
$self->{dists}{$row->{dist}}->{IXL} = 0; |
412
|
0
|
|
|
|
|
|
$self->{dists}{$row->{dist}}->{VER} = $row->{version}; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
0
|
|
|
|
|
|
$self->{parent}->_log("building stats hash"); |
416
|
|
|
|
|
|
|
|
417
|
0
|
|
0
|
|
|
|
$self->{count}{$_} ||= 0 for(qw(posters entries reports distros)); |
418
|
|
|
|
|
|
|
$self->{xrefs} = { posters => {}, entries => {}, reports => {} }, |
419
|
0
|
|
|
|
|
|
$self->{xlast} = { posters => [], entries => [], reports => [] }, |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
# clear old month entries |
423
|
0
|
|
|
|
|
|
for my $key (qw(platform osys osname)) { |
424
|
0
|
|
|
|
|
|
for my $name (keys %{$self->{$key}}) { |
|
0
|
|
|
|
|
|
|
425
|
0
|
|
|
|
|
|
for my $perl (keys %{$self->{$key}{$name}}) { |
|
0
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
for my $month (keys %{$self->{$key}{$name}{$perl}{month}}) { |
|
0
|
|
|
|
|
|
|
427
|
0
|
0
|
0
|
|
|
|
next if($month =~ /^\d+$/ && $month > $self->{dates}{THATMONTH}); |
428
|
0
|
|
|
|
|
|
delete $self->{$key}{$name}{$perl}{month}{$month}; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
#$self->{parent}->_log("build:1.".Dumper($self->{build})); |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
# reports builder performance stats |
437
|
0
|
|
|
|
|
|
for my $d (keys %{$self->{build}}) { |
|
0
|
|
|
|
|
|
|
438
|
0
|
|
|
|
|
|
$self->{build}{$d}->{old} = 0; |
439
|
|
|
|
|
|
|
} |
440
|
0
|
|
|
|
|
|
my $file = $self->{parent}->builder(); |
441
|
0
|
0
|
0
|
|
|
|
if($file && -f $file) { |
442
|
0
|
0
|
|
|
|
|
if(my $fh = IO::File->new($file,'r')) { |
443
|
0
|
|
|
|
|
|
while(<$fh>) { |
444
|
0
|
|
|
|
|
|
my ($d,$r,$p) = /(\d+),(\d+),(\d+)/; |
445
|
0
|
0
|
|
|
|
|
next unless($d); |
446
|
0
|
|
|
|
|
|
$self->{build}{$d}->{webtotal} = $r; |
447
|
0
|
|
|
|
|
|
$self->{build}{$d}->{webunique} = $p; |
448
|
0
|
|
|
|
|
|
$self->{build}{$d}->{old} = 1; |
449
|
|
|
|
|
|
|
} |
450
|
0
|
|
|
|
|
|
$fh->close; |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
} |
453
|
0
|
|
|
|
|
|
$self->{build}{$date}->{old} = 1; # keep the tally for yesterday |
454
|
0
|
|
|
|
|
|
$self->{build}{$tday}->{old} = 2; # keep the tally for today, but don't use |
455
|
0
|
|
|
|
|
|
for my $d (keys %{$self->{build}}) { |
|
0
|
|
|
|
|
|
|
456
|
0
|
0
|
|
|
|
|
delete $self->{build}{$d} unless($self->{build}{$d}->{old}); |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
#$self->{parent}->_log("build:2.".Dumper($self->{build})); |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# load pass matrices, for all or just the last full month |
462
|
0
|
|
|
|
|
|
$self->{parent}->_log("building pass reports matrices from database"); |
463
|
0
|
|
|
|
|
|
my $count = 0; |
464
|
0
|
|
|
|
|
|
my $iterator = $self->{parent}->{CPANSTATS}->iterator('hash','SELECT * FROM passreports'); |
465
|
0
|
|
|
|
|
|
while(my $row = $iterator->()) { |
466
|
0
|
|
|
|
|
|
$self->{pass}{$row->{platform}}{$row->{perl}}{all}{$row->{dist}} = 1; |
467
|
0
|
0
|
|
|
|
|
next if($row->{postdate} <= $self->{dates}{THATMONTH}); |
468
|
0
|
|
|
|
|
|
$self->{pass}{$row->{platform}}{$row->{perl}}{month}{$row->{postdate}}{$row->{dist}} = 1; |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
# 0, 1, 2, 3, 4, 5 6, 7, 8, 9, 10 11 12 |
473
|
|
|
|
|
|
|
# id, guid, state, postdate, tester, dist, version, platform, perl, osname, osvers, fulldate, type |
474
|
|
|
|
|
|
|
|
475
|
0
|
|
|
|
|
|
$self->{parent}->_log("building dist hash from $lastid"); |
476
|
0
|
|
|
|
|
|
$iterator = $self->{parent}->{CPANSTATS}->iterator('hash',"SELECT * FROM cpanstats WHERE type = 2 AND id > $lastid ORDER BY id LIMIT 1000000"); |
477
|
0
|
|
|
|
|
|
while(my $row = $iterator->()) { |
478
|
0
|
|
|
|
|
|
$row->{perl} =~ s/\s.*//; # only need to know the main release |
479
|
0
|
|
|
|
|
|
$lastid = $row->{id}; |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
{ |
482
|
0
|
|
|
|
|
|
my $osname = $self->{parent}->osname($row->{osname}); |
|
0
|
|
|
|
|
|
|
483
|
0
|
|
|
|
|
|
my ($name) = $self->{parent}->tester($row->{tester}); |
484
|
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
|
$self->{stats}{$row->{postdate}}{reports}++; |
486
|
0
|
|
|
|
|
|
$self->{stats}{$row->{postdate}}{state }{$row->{state}}++; |
487
|
|
|
|
|
|
|
#$self->{stats}{$row->{postdate}}{dist }{$row->{dist}}++; |
488
|
|
|
|
|
|
|
#$self->{stats}{$row->{postdate}}{version }{$row->{version}}++; |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# check distribution tallies |
491
|
0
|
0
|
|
|
|
|
if(defined $self->{dists}{$row->{dist}}) { |
492
|
0
|
|
|
|
|
|
$self->{dists}{$row->{dist}}{ALL}++; |
493
|
|
|
|
|
|
|
|
494
|
0
|
0
|
|
|
|
|
if($self->{dists}{$row->{dist}}->{VER} eq $row->{version}) { |
495
|
0
|
|
|
|
|
|
$self->{dists}{$row->{dist}}{IXL}++; |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# check failure rates |
498
|
0
|
0
|
|
|
|
|
$self->{fails}{$row->{dist}}{$row->{version}}{fail}++ if($row->{state} eq 'fail'); |
499
|
0
|
0
|
|
|
|
|
$self->{fails}{$row->{dist}}{$row->{version}}{pass}++ if($row->{state} eq 'pass'); |
500
|
0
|
|
|
|
|
|
$self->{fails}{$row->{dist}}{$row->{version}}{total}++; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
# build matrix stats |
505
|
0
|
|
|
|
|
|
my $perl = $row->{perl}; |
506
|
0
|
|
|
|
|
|
$perl =~ s/\s.*//; # only need to know the main release |
507
|
0
|
|
|
|
|
|
$self->{perls}{$perl} = 1; |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# $self->{pass} {$row->{platform}}{$perl}{all}{$row->{dist}} = 1; |
510
|
0
|
|
|
|
|
|
$self->{platform}{$row->{platform}}{$perl}{all}++; |
511
|
0
|
|
|
|
|
|
$self->{osys} {$osname} {$perl}{all}{$row->{dist}} = 1; |
512
|
0
|
|
|
|
|
|
$self->{osname} {$osname} {$perl}{all}++; |
513
|
|
|
|
|
|
|
|
514
|
0
|
0
|
|
|
|
|
if($row->{postdate} > $self->{dates}{THATMONTH}) { |
515
|
|
|
|
|
|
|
# $self->{pass} {$row->{platform}}{$perl}{month}{$row->{postdate}}{$row->{dist}} = 1; |
516
|
0
|
|
|
|
|
|
$self->{platform}{$row->{platform}}{$perl}{month}{$row->{postdate}}++; |
517
|
0
|
|
|
|
|
|
$self->{osys} {$osname} {$perl}{month}{$row->{postdate}}{$row->{dist}} = 1; |
518
|
0
|
|
|
|
|
|
$self->{osname} {$osname} {$perl}{month}{$row->{postdate}}++; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
# record tester activity |
522
|
0
|
|
0
|
|
|
|
$testers->{$name}{first} ||= $row->{postdate}; |
523
|
0
|
|
|
|
|
|
$testers->{$name}{last} = $row->{postdate}; |
524
|
0
|
|
|
|
|
|
$self->{counts}{$row->{postdate}}{testers}{$name} = 1; |
525
|
|
|
|
|
|
|
|
526
|
0
|
|
|
|
|
|
my $day = substr($row->{fulldate},0,8); |
527
|
0
|
0
|
|
|
|
|
$self->{build}{$day}{reports}++ if(defined $self->{build}{$day}); |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
|
530
|
0
|
|
|
|
|
|
my @row = (0, map {$row->{$_}} qw(id guid state postdate tester dist version platform perl osname osvers fulldate type)); |
|
0
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
|
532
|
0
|
|
|
|
|
|
$self->{count}{posters} = $row[1]; |
533
|
0
|
|
|
|
|
|
$self->{count}{entries}++; |
534
|
0
|
|
|
|
|
|
$self->{count}{reports}++; |
535
|
|
|
|
|
|
|
|
536
|
0
|
|
|
|
|
|
my $type = 'reports'; |
537
|
0
|
0
|
|
|
|
|
$self->{parent}->_log("checkpoint: count=$self->{count}{$type}, lastid=$lastid") if($self->{count}{$type} % 10000 == 0); |
538
|
|
|
|
|
|
|
|
539
|
0
|
0
|
|
|
|
|
if($self->{count}->{$type} % 100000 == 0) { |
540
|
|
|
|
|
|
|
# due to the large data structures used, long runs (eg starting from |
541
|
|
|
|
|
|
|
# scratch) should save the current state periodically. |
542
|
0
|
|
|
|
|
|
$self->storage_write(); |
543
|
0
|
|
|
|
|
|
$self->storage_write('testers',$testers); |
544
|
0
|
|
|
|
|
|
$self->storage_write('lastid',$lastid); |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
0
|
0
|
0
|
|
|
|
if($self->{count}{$type} == 1 || ($self->{count}->{$type} % 500000) == 0) { |
548
|
0
|
|
|
|
|
|
$self->{xrefs}{$type}->{$self->{count}->{$type}} = \@row; |
549
|
|
|
|
|
|
|
} else { |
550
|
0
|
|
|
|
|
|
$self->{xlast}{$type} = \@row; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
#$self->{parent}->_log("build:3.".Dumper($self->{build})); |
554
|
|
|
|
|
|
|
#$self->{parent}->_log("build:4.".Dumper($testers)); |
555
|
|
|
|
|
|
|
|
556
|
0
|
|
|
|
|
|
$self->storage_write(); |
557
|
0
|
|
|
|
|
|
$self->storage_write('testers',$testers); |
558
|
0
|
|
|
|
|
|
$self->storage_write('lastid',$lastid); |
559
|
|
|
|
|
|
|
|
560
|
0
|
|
|
|
|
|
for my $tester (keys %$testers) { |
561
|
0
|
|
|
|
|
|
$self->{counts}{$testers->{$tester}{first}}{first}++; |
562
|
0
|
|
|
|
|
|
$self->{counts}{$testers->{$tester}{last}}{last}++; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
#$self->{parent}->_log("build:5.".Dumper($self->{counts})); |
565
|
|
|
|
|
|
|
|
566
|
0
|
|
|
|
|
|
my @versions = sort {versioncmp($b,$a)} keys %{$self->{perls}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
567
|
0
|
|
|
|
|
|
$self->{versions} = \@versions; |
568
|
|
|
|
|
|
|
|
569
|
0
|
|
|
|
|
|
$self->{parent}->_log("stats hash built"); |
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
sub storage_read { |
573
|
0
|
|
|
0
|
1
|
|
my ($self,$type) = @_; |
574
|
|
|
|
|
|
|
|
575
|
0
|
0
|
|
|
|
|
if($type) { |
576
|
0
|
|
|
|
|
|
my $storage = sprintf $self->{parent}->mainstore(), $type; |
577
|
0
|
0
|
|
|
|
|
return unless(-f $storage); |
578
|
0
|
|
|
|
|
|
my $data = read_file($storage); |
579
|
0
|
|
|
|
|
|
my $store = decode_json($data); |
580
|
0
|
|
|
|
|
|
return $store->{$type}; |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
# for $type (qw(stats dists fails perls pass platform osys osname build counts count xrefs xlast)) { |
584
|
0
|
|
|
|
|
|
for $type (qw(stats dists fails perls platform osys osname build counts count xrefs xlast)) { |
585
|
0
|
|
|
|
|
|
$self->{parent}->_log("storage_read:1.type=$type"); |
586
|
0
|
|
|
|
|
|
my $storage = sprintf $self->{parent}->mainstore(), $type; |
587
|
0
|
0
|
|
|
|
|
next unless(-f $storage); |
588
|
0
|
|
|
|
|
|
$self->{parent}->_log("storage_read:2.storage=$storage"); |
589
|
|
|
|
|
|
|
try { |
590
|
0
|
|
|
0
|
|
|
my $data = read_file($storage); |
591
|
0
|
|
|
|
|
|
my $store = decode_json($data); |
592
|
0
|
|
|
|
|
|
$self->{$type} = $store->{$type}; |
593
|
|
|
|
|
|
|
} catch { |
594
|
0
|
|
|
0
|
|
|
$self->{parent}->_log("storage_read:3.failed to read data storage=$storage"); |
595
|
0
|
|
|
|
|
|
}; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub storage_write { |
600
|
0
|
|
|
0
|
1
|
|
my ($self,$type,$store) = @_; |
601
|
|
|
|
|
|
|
|
602
|
0
|
0
|
|
|
|
|
if($type) { |
603
|
0
|
0
|
|
|
|
|
return unless($store); |
604
|
0
|
|
|
|
|
|
my $data = encode_json({$type => $store}); |
605
|
|
|
|
|
|
|
|
606
|
0
|
|
|
|
|
|
my $storage = sprintf $self->{parent}->mainstore(), $type; |
607
|
0
|
|
|
|
|
|
my $dir = dirname($storage); |
608
|
0
|
0
|
0
|
|
|
|
mkpath($dir) if($dir && !-e $dir); |
609
|
0
|
|
|
|
|
|
overwrite_file($storage,$data); |
610
|
0
|
|
|
|
|
|
return; |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# for $type (qw(stats dists fails perls pass platform osys osname build counts count xrefs xlast)) { |
614
|
0
|
|
|
|
|
|
for $type (qw(stats dists fails perls platform osys osname build counts count xrefs xlast)) { |
615
|
0
|
0
|
|
|
|
|
next unless($self->{$type}); |
616
|
0
|
|
|
|
|
|
my $data = encode_json({$type => $self->{$type}}); |
617
|
|
|
|
|
|
|
|
618
|
0
|
|
|
|
|
|
my $storage = sprintf $self->{parent}->mainstore(), $type; |
619
|
0
|
|
|
|
|
|
my $dir = dirname($storage); |
620
|
0
|
0
|
0
|
|
|
|
mkpath($dir) if($dir && !-e $dir); |
621
|
0
|
|
|
|
|
|
overwrite_file($storage,$data); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
=head3 Page Creation Methods |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
=over 4 |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
=item * _write_basics |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
Write out basic pages, all of which are simply built from the templates, |
632
|
|
|
|
|
|
|
without any data processing required. |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
=cut |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
sub _write_basics { |
637
|
0
|
|
|
0
|
|
|
my $self = shift; |
638
|
0
|
|
|
|
|
|
my $directory = $self->{parent}->directory; |
639
|
0
|
|
|
|
|
|
my $templates = $self->{parent}->templates; |
640
|
0
|
|
|
|
|
|
my $results = "$directory/stats"; |
641
|
0
|
|
|
|
|
|
mkpath($results); |
642
|
|
|
|
|
|
|
|
643
|
0
|
|
|
|
|
|
$self->{parent}->_log("writing basic files"); |
644
|
|
|
|
|
|
|
|
645
|
0
|
|
|
|
|
|
my $ranges1 = $self->{parent}->ranges('TEST_RANGES'); |
646
|
0
|
|
|
|
|
|
my $ranges2 = $self->{parent}->ranges('CPAN_RANGES'); |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
# additional pages not requiring metrics |
649
|
0
|
|
|
|
|
|
my %pages = ( |
650
|
|
|
|
|
|
|
cpanmail => {}, |
651
|
|
|
|
|
|
|
response => {}, |
652
|
|
|
|
|
|
|
perform => {}, |
653
|
|
|
|
|
|
|
terms => {}, |
654
|
|
|
|
|
|
|
graphs => {}, |
655
|
|
|
|
|
|
|
graphs1 => {RANGES => $ranges1, template=>'archive', PREFIX=>'stats1' ,TITLE=>'Monthly Report Counts'}, |
656
|
|
|
|
|
|
|
graphs2 => {RANGES => $ranges1, template=>'archive', PREFIX=>'stats2' ,TITLE=>'Testers, Platforms and Perls'}, |
657
|
|
|
|
|
|
|
graphs3 => {RANGES => $ranges1, template=>'archive', PREFIX=>'stats3' ,TITLE=>'Monthly Non-Passing Reports Counts'}, |
658
|
|
|
|
|
|
|
graphs4 => {RANGES => $ranges1, template=>'archive', PREFIX=>'stats4' ,TITLE=>'Monthly Tester Fluctuations'}, |
659
|
|
|
|
|
|
|
graphs5 => {RANGES => $ranges1, template=>'archive', PREFIX=>'pcent1' ,TITLE=>'Monthly Report Percentages'}, |
660
|
|
|
|
|
|
|
graphs6 => {RANGES => $ranges2, template=>'archive', PREFIX=>'stats6' ,TITLE=>'All Distribution Uploads per Month'}, |
661
|
|
|
|
|
|
|
graphs12 => {RANGES => $ranges2, template=>'archive', PREFIX=>'stats12',TITLE=>'New Distribution Uploads per Month'} |
662
|
|
|
|
|
|
|
); |
663
|
|
|
|
|
|
|
|
664
|
0
|
|
|
|
|
|
$self->{parent}->_log("building support pages"); |
665
|
0
|
|
|
|
|
|
$self->_writepage($_,$pages{$_}) for(keys %pages); |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
# copy files |
668
|
0
|
|
|
|
|
|
$self->{parent}->_log("copying static files"); |
669
|
0
|
|
|
|
|
|
my $tocopy = $self->{parent}->tocopy; |
670
|
0
|
|
|
|
|
|
$self->{parent}->_log("files to copy = " . scalar(@$tocopy)); |
671
|
0
|
|
|
|
|
|
for my $filename (@$tocopy) { |
672
|
0
|
|
|
|
|
|
my $source = $templates . "/$filename"; |
673
|
0
|
0
|
|
|
|
|
if(-f $source) { |
674
|
0
|
|
|
|
|
|
my $target = $directory . "/$filename"; |
675
|
0
|
0
|
|
|
|
|
next if(-f $target); |
676
|
|
|
|
|
|
|
|
677
|
0
|
|
|
|
|
|
mkpath( dirname($target) ); |
678
|
0
|
0
|
|
|
|
|
if(-d dirname($target)) { |
679
|
0
|
|
|
|
|
|
$self->{parent}->_log("copying '$source' to '$target'"); |
680
|
0
|
|
|
|
|
|
copy( $source, $target ); |
681
|
|
|
|
|
|
|
} else { |
682
|
0
|
|
|
|
|
|
$self->{parent}->_log("copy error: Missing directory: $target"); |
683
|
0
|
|
|
|
|
|
warn "Missing directory: $target\n"; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
} else { |
686
|
0
|
|
|
|
|
|
$self->{parent}->_log("copy error: Missing file: $source"); |
687
|
0
|
|
|
|
|
|
warn "Missing file: $source\n"; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
} |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
#link files |
692
|
0
|
|
|
|
|
|
$self->{parent}->_log("linking static files"); |
693
|
0
|
|
|
|
|
|
my $tolink = $self->{parent}->tolink; |
694
|
0
|
|
|
|
|
|
for my $filename (keys %$tolink) { |
695
|
0
|
|
|
|
|
|
my $source = $directory . "/$filename"; |
696
|
0
|
|
|
|
|
|
my $target = $directory . '/'.$tolink->{$filename}; |
697
|
|
|
|
|
|
|
|
698
|
0
|
0
|
|
|
|
|
next if(-f $target); |
699
|
0
|
0
|
|
|
|
|
if(-f $source) { |
700
|
0
|
|
|
|
|
|
link($target,$source); |
701
|
|
|
|
|
|
|
} else { |
702
|
0
|
|
|
|
|
|
warn "Missing file: $source\n"; |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
# wget |
707
|
0
|
|
|
|
|
|
my $cmd = sprintf "wget -O %s/sponsors.json http://iheart.cpantesters.org/home/sponsors?images=1 2>/dev/null", $directory; |
708
|
0
|
|
|
|
|
|
$self->{parent}->_log("sponsors: '$cmd'"); |
709
|
0
|
|
|
|
|
|
system($cmd); |
710
|
|
|
|
|
|
|
} |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=item * _write_index |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
Writes out the main index page, after all stats have been calculated. |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=cut |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
sub _write_index { |
719
|
0
|
|
|
0
|
|
|
my $self = shift; |
720
|
0
|
|
|
|
|
|
my $directory = $self->{parent}->directory; |
721
|
0
|
|
|
|
|
|
my $templates = $self->{parent}->templates; |
722
|
|
|
|
|
|
|
|
723
|
0
|
|
|
|
|
|
$self->{parent}->_log("writing index file"); |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
# calculate growth rates |
726
|
0
|
|
|
|
|
|
my ($d1,$d2) = (time(), time() - $ADAY); |
727
|
0
|
|
|
|
|
|
my @date = localtime($d2); |
728
|
0
|
|
|
|
|
|
my $date = sprintf "%04d%02d%02d", $date[5]+1900, $date[4]+1, $date[3]; |
729
|
|
|
|
|
|
|
|
730
|
0
|
|
|
|
|
|
my @rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT COUNT(*) FROM cpanstats WHERE type = 2 AND fulldate like '$date%'"); |
731
|
0
|
0
|
|
|
|
|
$self->{rates}{report} = $rows[0]->[0] ? $ADAY / $rows[0]->[0] * 1000 : $ADAY / 10000 * 1000; |
732
|
0
|
|
|
|
|
|
@rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT COUNT(*) FROM uploads WHERE released > $d2 and released < $d1"); |
733
|
0
|
0
|
|
|
|
|
$self->{rates}{distro} = $rows[0]->[0] ? $ADAY / $rows[0]->[0] * 1000 : $ADAY / 60 * 1000; |
734
|
|
|
|
|
|
|
|
735
|
0
|
0
|
|
|
|
|
$self->{rates}{report} = 1000 if($self->{rates}{report} < 1000); |
736
|
0
|
0
|
|
|
|
|
$self->{rates}{distro} = 1000 if($self->{rates}{distro} < 1000); |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# index page |
739
|
|
|
|
|
|
|
my %pages = ( |
740
|
|
|
|
|
|
|
index => { |
741
|
|
|
|
|
|
|
LASTMONTH => $self->{dates}{LASTMONTH}, |
742
|
|
|
|
|
|
|
report_count => $self->{count}{reports}, |
743
|
|
|
|
|
|
|
distro_count => $self->{count}{distros}, |
744
|
|
|
|
|
|
|
report_rate => $self->{rates}{report}, |
745
|
|
|
|
|
|
|
distro_rate => $self->{rates}{distro} |
746
|
|
|
|
|
|
|
}, |
747
|
0
|
|
|
|
|
|
); |
748
|
|
|
|
|
|
|
|
749
|
0
|
|
|
|
|
|
$self->_writepage($_,$pages{$_}) for(keys %pages); |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=item * _report_interesting |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
Generates the interesting stats page |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=cut |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
sub _report_interesting { |
759
|
0
|
|
|
0
|
|
|
my $self = shift; |
760
|
0
|
|
|
|
|
|
my %tvars; |
761
|
|
|
|
|
|
|
|
762
|
0
|
|
|
|
|
|
$self->{parent}->_log("building interesting page"); |
763
|
|
|
|
|
|
|
|
764
|
0
|
|
|
|
|
|
$tvars{sizes}{reports} = $self->{sizes}{dir_reports}; |
765
|
|
|
|
|
|
|
|
766
|
0
|
|
|
|
|
|
my (@bydist,@byvers); |
767
|
0
|
|
|
|
|
|
my $inx = 20; |
768
|
0
|
0
|
|
|
|
|
for my $dist (sort {$self->{dists}{$b}{ALL} <=> $self->{dists}{$a}{ALL} || $a cmp $b} keys %{$self->{dists}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
769
|
0
|
|
|
|
|
|
push @bydist, [$self->{dists}{$dist}{ALL},$dist]; |
770
|
0
|
0
|
|
|
|
|
last if(--$inx <= 0); |
771
|
|
|
|
|
|
|
} |
772
|
0
|
|
|
|
|
|
$inx = 20; |
773
|
0
|
0
|
|
|
|
|
for my $dist (sort {$self->{dists}{$b}{IXL} <=> $self->{dists}{$a}{IXL} || $a cmp $b} keys %{$self->{dists}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
774
|
0
|
|
|
|
|
|
push @byvers, [$self->{dists}{$dist}{IXL},$dist,$self->{dists}{$dist}{VER}]; |
775
|
0
|
0
|
|
|
|
|
last if(--$inx <= 0); |
776
|
|
|
|
|
|
|
} |
777
|
|
|
|
|
|
|
|
778
|
0
|
|
|
|
|
|
$tvars{BYDIST} = \@bydist; |
779
|
0
|
|
|
|
|
|
$tvars{BYVERS} = \@byvers; |
780
|
|
|
|
|
|
|
|
781
|
0
|
|
|
|
|
|
my $type = 'reports'; |
782
|
0
|
|
0
|
|
|
|
$self->{count}{$type} ||= 0; |
783
|
0
|
0
|
|
|
|
|
$self->{xrefs}{$type}{$self->{count}{$type}} = $self->{xlast} ? $self->{xlast}{$type} : []; |
784
|
|
|
|
|
|
|
|
785
|
0
|
|
|
|
|
|
for my $key (sort {$b <=> $a} keys %{ $self->{xrefs}{$type} }) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
786
|
0
|
|
|
|
|
|
my @row = @{ $self->{xrefs}{$type}{$key} }; |
|
0
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
|
788
|
0
|
|
|
|
|
|
$row[0] = $key; |
789
|
0
|
0
|
|
|
|
|
$row[3] = uc $row[3] if($row[3]); |
790
|
0
|
0
|
0
|
|
|
|
($row[5]) = $self->{parent}->tester($row[5]) if($row[5] && $row[5] =~ /\@/); |
791
|
0
|
|
|
|
|
|
push @{ $tvars{ uc($type) } }, \@row; |
|
0
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
} |
793
|
|
|
|
|
|
|
|
794
|
0
|
|
|
|
|
|
my @headings = qw( count grade postdate tester dist version platform perl osname osvers fulldate ); |
795
|
0
|
|
|
|
|
|
$tvars{HEADINGS} = \@headings; |
796
|
0
|
|
|
|
|
|
$self->_writepage('interest',\%tvars); |
797
|
|
|
|
|
|
|
} |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
=item * _report_cpan |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
Generates the statistic pages that relate specifically to CPAN. |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=cut |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
sub _report_cpan { |
806
|
0
|
|
|
0
|
|
|
my $self = shift; |
807
|
0
|
|
|
|
|
|
my (%authors,%distros,%tvars); |
808
|
|
|
|
|
|
|
|
809
|
0
|
|
|
|
|
|
$self->{parent}->_log("building cpan trends page"); |
810
|
|
|
|
|
|
|
|
811
|
0
|
|
|
|
|
|
my $directory = $self->{parent}->directory; |
812
|
0
|
|
|
|
|
|
my $results = "$directory/stats"; |
813
|
0
|
|
|
|
|
|
mkpath($results); |
814
|
|
|
|
|
|
|
|
815
|
0
|
|
|
|
|
|
my $next = $self->{parent}->{CPANSTATS}->iterator('hash',"SELECT * FROM uploads ORDER BY released"); |
816
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
817
|
0
|
0
|
|
|
|
|
next if($row->{dist} eq 'perl'); |
818
|
|
|
|
|
|
|
|
819
|
0
|
|
|
|
|
|
my $date = _parsedate($row->{released}); |
820
|
0
|
|
|
|
|
|
$authors{$row->{author}}{count}++; |
821
|
0
|
|
|
|
|
|
$distros{$row->{dist}}{count}++; |
822
|
0
|
|
|
|
|
|
$authors{$row->{author}}{dist}{$row->{dist}}++; |
823
|
0
|
0
|
|
|
|
|
$authors{$row->{author}}{dists}++ if($authors{$row->{author}}{dist}{$row->{dist}} == 1); |
824
|
|
|
|
|
|
|
|
825
|
0
|
|
|
|
|
|
$self->{counts}{$date}{authors}{$row->{author}}++; |
826
|
0
|
|
|
|
|
|
$self->{counts}{$date}{distros}{$row->{dist}}++; |
827
|
|
|
|
|
|
|
|
828
|
0
|
0
|
|
|
|
|
$self->{counts}{$date}{newauthors}++ if($authors{$row->{author}}{count} == 1); |
829
|
0
|
0
|
|
|
|
|
$self->{counts}{$date}{newdistros}++ if($distros{$row->{dist}}{count} == 1); |
830
|
|
|
|
|
|
|
|
831
|
0
|
|
|
|
|
|
$self->{pause}{$date}++; |
832
|
|
|
|
|
|
|
} |
833
|
|
|
|
|
|
|
|
834
|
0
|
0
|
|
|
|
|
my $stat6 = IO::File->new("$results/stats6.txt",'w+') or die "Cannot write to file [$results/stats6.txt]: $!\n"; |
835
|
0
|
|
|
|
|
|
print $stat6 "#DATE,AUTHORS,DISTROS\n"; |
836
|
0
|
0
|
|
|
|
|
my $stat12 = IO::File->new("$results/stats12.txt",'w+') or die "Cannot write to file [$results/stats12.txt]: $!\n"; |
837
|
0
|
|
|
|
|
|
print $stat12 "#DATE,AUTHORS,DISTROS\n"; |
838
|
|
|
|
|
|
|
|
839
|
0
|
|
|
|
|
|
for my $date (sort keys %{ $self->{counts} }) { |
|
0
|
|
|
|
|
|
|
840
|
0
|
|
|
|
|
|
my $authors = scalar(keys %{ $self->{counts}{$date}{authors} }); |
|
0
|
|
|
|
|
|
|
841
|
0
|
|
|
|
|
|
my $distros = scalar(keys %{ $self->{counts}{$date}{distros} }); |
|
0
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
|
843
|
0
|
|
0
|
|
|
|
$self->{counts}{$date}{newauthors} ||= 0; |
844
|
0
|
|
0
|
|
|
|
$self->{counts}{$date}{newdistros} ||= 0; |
845
|
|
|
|
|
|
|
|
846
|
0
|
|
|
|
|
|
print $stat6 "$date,$authors,$distros\n"; |
847
|
0
|
|
|
|
|
|
print $stat12 "$date,$self->{counts}{$date}{newauthors},$self->{counts}{$date}{newdistros}\n"; |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
# print $stat6 "$date,$authors\n"; |
850
|
|
|
|
|
|
|
# print $stat7 "$date,$distros\n"; |
851
|
|
|
|
|
|
|
# print $stat12 "$date,$self->{counts}{$date}{newauthors}\n"; |
852
|
|
|
|
|
|
|
# print $stat13 "$date,$self->{counts}{$date}{newdistros}\n"; |
853
|
|
|
|
|
|
|
} |
854
|
|
|
|
|
|
|
|
855
|
0
|
|
|
|
|
|
$stat6->close; |
856
|
|
|
|
|
|
|
# $stat7->close; |
857
|
0
|
|
|
|
|
|
$stat12->close; |
858
|
|
|
|
|
|
|
# $stat13->close; |
859
|
|
|
|
|
|
|
|
860
|
0
|
|
|
|
|
|
$tvars{maxyear} = DateTime->now->year; |
861
|
0
|
|
|
|
|
|
$self->_writepage('trends',\%tvars); |
862
|
|
|
|
|
|
|
|
863
|
0
|
|
|
|
|
|
$self->_report_new_distros(); |
864
|
0
|
|
|
|
|
|
$self->_report_submissions(); |
865
|
|
|
|
|
|
|
|
866
|
0
|
|
|
|
|
|
$self->{parent}->_log("building cpan leader page"); |
867
|
|
|
|
|
|
|
|
868
|
0
|
|
|
|
|
|
my $query = 'SELECT x.author,COUNT(x.dist) AS count FROM ixlatest AS x '. |
869
|
|
|
|
|
|
|
'INNER JOIN uploads AS u ON u.dist=x.dist AND u.version=x.version '. |
870
|
|
|
|
|
|
|
"WHERE u.type != 'backpan' GROUP BY x.author"; |
871
|
0
|
|
|
|
|
|
my @latest = $self->{parent}->{CPANSTATS}->get_query('hash',$query); |
872
|
0
|
|
|
|
|
|
my (@allcurrent,@alluploads,@allrelease,@alldistros); |
873
|
0
|
|
|
|
|
|
my $inx = 1; |
874
|
0
|
|
|
|
|
|
for my $latest (sort {$b->{count} <=> $a->{count}} @latest) { |
|
0
|
|
|
|
|
|
|
875
|
0
|
|
|
|
|
|
push @allcurrent, {inx => $inx++, count => $latest->{count}, name => $latest->{author}}; |
876
|
0
|
0
|
|
|
|
|
last if($inx > 20); |
877
|
|
|
|
|
|
|
} |
878
|
|
|
|
|
|
|
|
879
|
0
|
|
|
|
|
|
$inx = 1; |
880
|
0
|
0
|
|
|
|
|
for my $author (sort {$authors{$b}{dists} <=> $authors{$a}{dists} || $a cmp $b} keys %authors) { |
|
0
|
|
|
|
|
|
|
881
|
0
|
|
|
|
|
|
push @alluploads, {inx => $inx++, count => $authors{$author}{dists}, name => $author}; |
882
|
0
|
0
|
|
|
|
|
last if($inx > 20); |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
|
885
|
0
|
|
|
|
|
|
$inx = 1; |
886
|
0
|
0
|
|
|
|
|
for my $author (sort {$authors{$b}{count} <=> $authors{$a}{count} || $a cmp $b} keys %authors) { |
|
0
|
|
|
|
|
|
|
887
|
0
|
|
|
|
|
|
push @allrelease, {inx => $inx++, count => $authors{$author}{count}, name => $author}; |
888
|
0
|
0
|
|
|
|
|
last if($inx > 20); |
889
|
|
|
|
|
|
|
} |
890
|
|
|
|
|
|
|
|
891
|
0
|
|
|
|
|
|
$inx = 1; |
892
|
0
|
0
|
|
|
|
|
for my $distro (sort {$distros{$b}{count} <=> $distros{$a}{count} || $a cmp $b} keys %distros) { |
|
0
|
|
|
|
|
|
|
893
|
0
|
|
|
|
|
|
push @alldistros, {inx => $inx++, count => $distros{$distro}{count}, name => $distro}; |
894
|
0
|
0
|
|
|
|
|
last if($inx > 20); |
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
|
897
|
0
|
|
|
|
|
|
$tvars{allcurrent} = \@allcurrent; |
898
|
0
|
|
|
|
|
|
$tvars{alluploads} = \@alluploads; |
899
|
0
|
|
|
|
|
|
$tvars{allrelease} = \@allrelease; |
900
|
0
|
|
|
|
|
|
$tvars{alldistros} = \@alldistros; |
901
|
|
|
|
|
|
|
|
902
|
0
|
|
|
|
|
|
$self->_writepage('leadercpan',\%tvars); |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
|
905
|
0
|
|
|
|
|
|
$self->{parent}->_log("building cpan interesting stats page (part 1)"); |
906
|
|
|
|
|
|
|
|
907
|
0
|
|
|
|
|
|
$tvars{sizes}{cpan} = $self->{sizes}{dir_cpan}; |
908
|
0
|
|
|
|
|
|
$tvars{sizes}{backpan} = $self->{sizes}{dir_backpan}; |
909
|
|
|
|
|
|
|
|
910
|
0
|
|
|
|
|
|
$tvars{authors}{total} = $self->_count_mailrc(); |
911
|
0
|
|
|
|
|
|
my @rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT COUNT(distinct author) FROM uploads"); |
912
|
0
|
|
|
|
|
|
$tvars{authors}{active} = $rows[0]->[0]; |
913
|
0
|
|
|
|
|
|
$tvars{authors}{inactive} = $tvars{authors}{total} - $rows[0]->[0]; |
914
|
|
|
|
|
|
|
|
915
|
0
|
|
|
|
|
|
@rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT COUNT(distinct dist) FROM uploads WHERE type != 'backpan'"); |
916
|
0
|
|
|
|
|
|
$tvars{distros}{uploaded1} = $rows[0]->[0]; |
917
|
0
|
|
|
|
|
|
$self->{count}{distros} = $rows[0]->[0]; |
918
|
0
|
|
|
|
|
|
@rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT COUNT(distinct dist) FROM uploads"); |
919
|
0
|
|
|
|
|
|
$tvars{distros}{uploaded2} = $rows[0]->[0]; |
920
|
0
|
|
|
|
|
|
$tvars{distros}{uploaded3} = $tvars{distros}{uploaded2} - $tvars{distros}{uploaded1}; |
921
|
|
|
|
|
|
|
|
922
|
0
|
|
|
|
|
|
@rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT COUNT(*) FROM uploads WHERE type != 'backpan'"); |
923
|
0
|
|
|
|
|
|
$tvars{distros}{uploaded4} = $rows[0]->[0]; |
924
|
0
|
|
|
|
|
|
@rows = $self->{parent}->{CPANSTATS}->get_query('array',"SELECT COUNT(*) FROM uploads"); |
925
|
0
|
|
|
|
|
|
$tvars{distros}{uploaded5} = $rows[0]->[0]; |
926
|
0
|
|
|
|
|
|
$tvars{distros}{uploaded6} = $tvars{distros}{uploaded5} - $tvars{distros}{uploaded4}; |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
|
929
|
0
|
|
|
|
|
|
$self->{parent}->_log("building cpan interesting stats page (part 2)"); |
930
|
|
|
|
|
|
|
|
931
|
0
|
|
|
|
|
|
my (%stats,%dists,%pause,%last); |
932
|
0
|
|
|
|
|
|
$next = $self->{parent}->{CPANSTATS}->iterator('hash','SELECT * FROM uploads ORDER BY released'); |
933
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
934
|
0
|
|
|
|
|
|
$stats{vcounter}++; |
935
|
0
|
0
|
|
|
|
|
if($stats{vcounter} % 10000 == 0) { |
936
|
0
|
|
|
|
|
|
$stats{'uploads'}{$stats{vcounter}}{dist} = $row->{dist}; |
937
|
0
|
|
|
|
|
|
$stats{'uploads'}{$stats{vcounter}}{vers} = $row->{version}; |
938
|
0
|
|
|
|
|
|
$stats{'uploads'}{$stats{vcounter}}{date} = $row->{released}; |
939
|
0
|
|
|
|
|
|
$stats{'uploads'}{$stats{vcounter}}{name} = $row->{author}; |
940
|
|
|
|
|
|
|
} |
941
|
|
|
|
|
|
|
|
942
|
0
|
|
|
|
|
|
$last{'uploads'}{counter} = $stats{vcounter}; |
943
|
0
|
|
|
|
|
|
$last{'uploads'}{dist} = $row->{dist}; |
944
|
0
|
|
|
|
|
|
$last{'uploads'}{vers} = $row->{version}; |
945
|
0
|
|
|
|
|
|
$last{'uploads'}{date} = $row->{released}; |
946
|
0
|
|
|
|
|
|
$last{'uploads'}{name} = $row->{author}; |
947
|
|
|
|
|
|
|
|
948
|
0
|
0
|
|
|
|
|
unless($pause{$row->{author}}) { |
949
|
0
|
|
|
|
|
|
$pause{$row->{author}} = 1; |
950
|
0
|
|
|
|
|
|
$stats{pcounter}++; |
951
|
0
|
0
|
|
|
|
|
if($stats{pcounter} % 1000 == 0) { |
952
|
0
|
|
|
|
|
|
$stats{'uploaders'}{$stats{pcounter}}{dist} = $row->{dist}; |
953
|
0
|
|
|
|
|
|
$stats{'uploaders'}{$stats{pcounter}}{vers} = $row->{version}; |
954
|
0
|
|
|
|
|
|
$stats{'uploaders'}{$stats{pcounter}}{date} = $row->{released}; |
955
|
0
|
|
|
|
|
|
$stats{'uploaders'}{$stats{pcounter}}{name} = $row->{author}; |
956
|
|
|
|
|
|
|
} |
957
|
|
|
|
|
|
|
|
958
|
0
|
|
|
|
|
|
$last{'uploaders'}{counter} = $stats{pcounter}; |
959
|
0
|
|
|
|
|
|
$last{'uploaders'}{dist} = $row->{dist}; |
960
|
0
|
|
|
|
|
|
$last{'uploaders'}{vers} = $row->{version}; |
961
|
0
|
|
|
|
|
|
$last{'uploaders'}{date} = $row->{released}; |
962
|
0
|
|
|
|
|
|
$last{'uploaders'}{name} = $row->{author}; |
963
|
|
|
|
|
|
|
} |
964
|
|
|
|
|
|
|
|
965
|
0
|
0
|
|
|
|
|
next if($dists{$row->{dist}}); |
966
|
|
|
|
|
|
|
|
967
|
0
|
|
|
|
|
|
$dists{$row->{dist}} = 1; |
968
|
0
|
|
|
|
|
|
$stats{dcounter}++; |
969
|
0
|
0
|
|
|
|
|
if($stats{dcounter} % 5000 == 0) { |
970
|
0
|
|
|
|
|
|
$stats{'distributions'}{$stats{dcounter}}{dist} = $row->{dist}; |
971
|
0
|
|
|
|
|
|
$stats{'distributions'}{$stats{dcounter}}{vers} = $row->{version}; |
972
|
0
|
|
|
|
|
|
$stats{'distributions'}{$stats{dcounter}}{date} = $row->{released}; |
973
|
0
|
|
|
|
|
|
$stats{'distributions'}{$stats{dcounter}}{name} = $row->{author}; |
974
|
|
|
|
|
|
|
} |
975
|
|
|
|
|
|
|
|
976
|
0
|
|
|
|
|
|
$last{'distributions'}{counter} = $stats{dcounter}; |
977
|
0
|
|
|
|
|
|
$last{'distributions'}{dist} = $row->{dist}; |
978
|
0
|
|
|
|
|
|
$last{'distributions'}{vers} = $row->{version}; |
979
|
0
|
|
|
|
|
|
$last{'distributions'}{date} = $row->{released}; |
980
|
0
|
|
|
|
|
|
$last{'distributions'}{name} = $row->{author}; |
981
|
|
|
|
|
|
|
} |
982
|
|
|
|
|
|
|
|
983
|
0
|
|
|
|
|
|
for my $type (qw(distributions uploads uploaders)) { |
984
|
0
|
|
|
|
|
|
my @list; |
985
|
0
|
|
|
|
|
|
$stats{$type}{$last{$type}{counter}} = $last{$type}; |
986
|
0
|
|
|
|
|
|
for my $count (sort {$a <=> $b} keys %{$stats{$type}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
987
|
0
|
|
|
|
|
|
my @date = localtime($stats{$type}{$count}{date}); |
988
|
0
|
|
|
|
|
|
my $date = sprintf "%04d-%02d-%02d %02d:%02d:%02d", $date[5]+1900, $date[4]+1, $date[3], $date[2], $date[1], $date[0] ; |
989
|
0
|
|
|
|
|
|
$stats{$type}{$count}{counter} = $count; |
990
|
0
|
|
|
|
|
|
$stats{$type}{$count}{date} = $date; |
991
|
0
|
|
|
|
|
|
push @list, $stats{$type}{$count}; |
992
|
|
|
|
|
|
|
} |
993
|
0
|
0
|
|
|
|
|
$tvars{$type} = \@list if(@list); |
994
|
|
|
|
|
|
|
} |
995
|
|
|
|
|
|
|
|
996
|
0
|
|
|
|
|
|
$self->_writepage('statscpan',\%tvars); |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
|
999
|
0
|
|
|
|
|
|
$self->{parent}->_log("building cpan/backpan 100s"); |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
# calculate CPAN 100 data |
1002
|
0
|
|
|
|
|
|
$self->_count_mailrc(); |
1003
|
0
|
|
|
|
|
|
@rows = $self->{parent}->{CPANSTATS}->get_query('hash',"SELECT t.author,t.count FROM (SELECT author,count(distinct dist) AS count FROM uploads WHERE type!='backpan' GROUP BY author ORDER BY count DESC LIMIT 100) AS t WHERE t.count >= 100"); |
1004
|
0
|
|
|
|
|
|
my $fh = IO::File->new(">$results/cpan100.csv"); |
1005
|
0
|
|
|
|
|
|
printf $fh "# DATE: %s\n", DateTime->now->datetime; |
1006
|
0
|
|
|
|
|
|
print $fh "#Pause,Count,Name\n"; |
1007
|
0
|
|
|
|
|
|
for my $row (@rows) { |
1008
|
0
|
|
0
|
|
|
|
printf $fh "%s,%d,%s\n", $row->{author}, $row->{count}, $self->{alias}{$row->{author}}||'???'; |
1009
|
|
|
|
|
|
|
} |
1010
|
0
|
|
|
|
|
|
$fh->close; |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
# calculate BACKCPAN 100 data |
1013
|
0
|
|
|
|
|
|
@rows = $self->{parent}->{CPANSTATS}->get_query('hash',"SELECT t.author,t.count FROM (SELECT author,count(distinct dist) AS count FROM uploads GROUP BY author ORDER BY count DESC LIMIT 100) AS t WHERE t.count >= 100"); |
1014
|
0
|
|
|
|
|
|
$fh = IO::File->new(">$results/backpan100.csv"); |
1015
|
0
|
|
|
|
|
|
printf $fh "# DATE: %s\n", DateTime->now->datetime; |
1016
|
0
|
|
|
|
|
|
print $fh "#Pause,Count,Name\n"; |
1017
|
0
|
|
|
|
|
|
for my $row (@rows) { |
1018
|
0
|
|
0
|
|
|
|
printf $fh "%s,%d,%s\n", $row->{author}, $row->{count}, $self->{alias}{$row->{author}}||'???'; |
1019
|
|
|
|
|
|
|
} |
1020
|
0
|
|
|
|
|
|
$fh->close; |
1021
|
|
|
|
|
|
|
} |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
sub _report_new_distros { |
1024
|
0
|
|
|
0
|
|
|
my $self = shift; |
1025
|
|
|
|
|
|
|
|
1026
|
0
|
|
|
|
|
|
$self->{parent}->_log("building new distro pages"); |
1027
|
|
|
|
|
|
|
|
1028
|
0
|
|
|
|
|
|
my (%seen,%allversions,%newversions); |
1029
|
0
|
|
|
|
|
|
my $start_year = 1995; |
1030
|
0
|
|
|
|
|
|
my $start_month = 8; |
1031
|
0
|
|
|
|
|
|
my $this_year = DateTime->now->year; |
1032
|
0
|
|
|
|
|
|
my $sql = 'select author,dist,version,from_unixtime(released) as reldate from uploads where released >= ? AND released < ? order by released'; |
1033
|
|
|
|
|
|
|
|
1034
|
0
|
|
|
|
|
|
for my $year (1995 .. $this_year) { |
1035
|
0
|
|
|
|
|
|
my $tvars = { template => 'newdistros', year => $year }; |
1036
|
|
|
|
|
|
|
|
1037
|
0
|
|
|
|
|
|
for my $month (1 .. 12) { |
1038
|
0
|
0
|
0
|
|
|
|
next if($year == $start_year && $month < $start_month); |
1039
|
|
|
|
|
|
|
|
1040
|
0
|
|
|
|
|
|
my $thismon = DateTime->new( year => $year, month => $month, day => 1, hour => 0, minute => 0, second => 0); |
1041
|
0
|
|
|
|
|
|
my $nextmon = DateTime->new( year => $thismon->clone->add( months => 1 )->year, month => $thismon->clone->add( months => 1 )->month, day => 1, hour => 0, minute => 0, second => 0); |
1042
|
|
|
|
|
|
|
|
1043
|
0
|
0
|
|
|
|
|
last if($thismon > DateTime->now); |
1044
|
|
|
|
|
|
|
|
1045
|
0
|
|
|
|
|
|
$tvars->{newdistros}{$month}{month} = $thismon->month_name; |
1046
|
0
|
|
|
|
|
|
$tvars->{newdistros}{$month}{counter} = 0; |
1047
|
|
|
|
|
|
|
|
1048
|
0
|
|
|
|
|
|
my @rows = $self->{parent}->{CPANSTATS}->get_query('hash',$sql,$thismon->epoch(),$nextmon->epoch()); |
1049
|
0
|
|
|
|
|
|
for my $row (@rows) { |
1050
|
0
|
|
|
|
|
|
$allversions{$row->{version}}++; |
1051
|
|
|
|
|
|
|
|
1052
|
0
|
0
|
|
|
|
|
next if($seen{$row->{dist}}); |
1053
|
|
|
|
|
|
|
|
1054
|
0
|
|
|
|
|
|
$seen{$row->{dist}} = 1; |
1055
|
0
|
|
|
|
|
|
push @{$tvars->{newdistros}{$month}{dists}}, |
1056
|
|
|
|
|
|
|
{ |
1057
|
|
|
|
|
|
|
author => $row->{author}, |
1058
|
|
|
|
|
|
|
dist => $row->{dist}, |
1059
|
|
|
|
|
|
|
version => $row->{version}, |
1060
|
|
|
|
|
|
|
reldate => $row->{reldate} |
1061
|
0
|
|
|
|
|
|
}; |
1062
|
|
|
|
|
|
|
|
1063
|
0
|
|
|
|
|
|
$tvars->{newdistros}{$month}{counter}++; |
1064
|
0
|
|
|
|
|
|
$newversions{$row->{version}}++; |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
} |
1067
|
|
|
|
|
|
|
|
1068
|
0
|
|
|
|
|
|
$self->_writepage("newdistros/$year",$tvars); |
1069
|
|
|
|
|
|
|
} |
1070
|
|
|
|
|
|
|
|
1071
|
0
|
|
|
|
|
|
$self->{parent}->_log("building new distro versions page"); |
1072
|
|
|
|
|
|
|
|
1073
|
0
|
|
|
|
|
|
my (@allversions,@newversions); |
1074
|
0
|
0
|
|
|
|
|
for my $v (sort {$allversions{$b} <=> $allversions{$a} || $a cmp $b} keys %allversions) { |
|
0
|
|
|
|
|
|
|
1075
|
0
|
|
|
|
|
|
push @allversions, { version => $v, count => $allversions{$v} }; |
1076
|
|
|
|
|
|
|
} |
1077
|
0
|
|
|
|
|
|
my $tvars = { template => 'versions', type => 'All', versions => \@allversions }; |
1078
|
0
|
|
|
|
|
|
$self->_writepage("newdistros/allversions",$tvars); |
1079
|
|
|
|
|
|
|
|
1080
|
0
|
0
|
|
|
|
|
for my $v (sort {$newversions{$b} <=> $newversions{$a} || $a cmp $b} keys %newversions) { |
|
0
|
|
|
|
|
|
|
1081
|
0
|
|
|
|
|
|
push @newversions, { version => $v, count => $newversions{$v} }; |
1082
|
|
|
|
|
|
|
} |
1083
|
0
|
|
|
|
|
|
$tvars = { template => 'versions', type => 'New', versions => \@newversions }; |
1084
|
0
|
|
|
|
|
|
$self->_writepage("newdistros/newversions",$tvars); |
1085
|
|
|
|
|
|
|
} |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
sub _report_submissions { |
1088
|
0
|
|
|
0
|
|
|
my $self = shift; |
1089
|
|
|
|
|
|
|
|
1090
|
0
|
|
|
|
|
|
$self->{parent}->_log("building submission data files"); |
1091
|
|
|
|
|
|
|
|
1092
|
0
|
|
|
|
|
|
my $sql = 'select from_unixtime(released) as reldate from uploads'; |
1093
|
|
|
|
|
|
|
|
1094
|
0
|
|
|
|
|
|
my $now = DateTime->now; |
1095
|
0
|
|
|
|
|
|
my (%hours,%days,%months,%dotw,%tvars); |
1096
|
|
|
|
|
|
|
|
1097
|
0
|
|
|
|
|
|
my $next = $self->{parent}->{CPANSTATS}->iterator('hash',$sql); |
1098
|
0
|
|
|
|
|
|
while( my $row = $next->() ) { |
1099
|
0
|
0
|
0
|
|
|
|
next unless($row->{reldate} && $row->{reldate} =~ /^(\d+)\-(\d+)\-(\d+).(\d+):(\d+):(\d+)/); |
1100
|
0
|
|
|
|
|
|
my ($year,$month,$day,$hour,$minute,$second) = ($1,$2,$3,$4,$5,$6); |
1101
|
|
|
|
|
|
|
|
1102
|
0
|
|
|
|
|
|
my $date = DateTime->new( year => $year, month => $month, day => $day, hour => $hour, minute => $minute, second => $second ); |
1103
|
0
|
|
|
|
|
|
my $dotw = $date->day_of_week; |
1104
|
|
|
|
|
|
|
|
1105
|
0
|
|
|
|
|
|
$months{that}{$month}++; |
1106
|
0
|
|
|
|
|
|
$dotw{that}{$dotw}++; |
1107
|
0
|
|
|
|
|
|
$days{that}{$day}++; |
1108
|
0
|
|
|
|
|
|
$hours{that}{$hour}++; |
1109
|
|
|
|
|
|
|
|
1110
|
0
|
0
|
|
|
|
|
if($year != $now->year) { |
|
|
0
|
|
|
|
|
|
1111
|
0
|
|
|
|
|
|
$months{this}{$month}++; |
1112
|
0
|
|
|
|
|
|
$dotw{this}{$dotw}++; |
1113
|
|
|
|
|
|
|
} elsif($date->week_number != $now->week_number) { |
1114
|
0
|
|
|
|
|
|
$dotw{this}{$dotw}++; |
1115
|
|
|
|
|
|
|
} |
1116
|
|
|
|
|
|
|
|
1117
|
0
|
0
|
0
|
|
|
|
if(( $year != $now->year) || |
|
|
|
0
|
|
|
|
|
1118
|
|
|
|
|
|
|
( $year == $now->year && $month != $now->month) ) { |
1119
|
0
|
|
|
|
|
|
$days{this}{$day}++; |
1120
|
|
|
|
|
|
|
} |
1121
|
|
|
|
|
|
|
|
1122
|
0
|
0
|
0
|
|
|
|
if(( $year != $now->year) || |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1123
|
|
|
|
|
|
|
( $year == $now->year && $month != $now->month) || |
1124
|
|
|
|
|
|
|
( $year == $now->year && $month == $now->month && $day != $now->day) ) { |
1125
|
0
|
|
|
|
|
|
$hours{this}{$hour}++; |
1126
|
|
|
|
|
|
|
} |
1127
|
|
|
|
|
|
|
} |
1128
|
|
|
|
|
|
|
|
1129
|
0
|
|
|
|
|
|
my $directory = $self->{parent}->directory; |
1130
|
0
|
|
|
|
|
|
my $results = "$directory/rates"; |
1131
|
0
|
|
|
|
|
|
mkpath($results); |
1132
|
|
|
|
|
|
|
|
1133
|
0
|
|
|
|
|
|
$self->{parent}->_log("writing $results/submit1.txt"); |
1134
|
0
|
|
|
|
|
|
my $fh = IO::File->new(">$results/submit1.txt"); |
1135
|
0
|
|
|
|
|
|
print $fh "#INDEX,EXCLUSIVE,INCLUSIVE\n"; |
1136
|
0
|
|
|
|
|
|
for my $month (sort {$a <=> $b} keys %{$months{this}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1137
|
0
|
|
|
|
|
|
printf $fh "%d,%d,%d\n", $month, $months{this}{$month}, $months{that}{$month}; |
1138
|
|
|
|
|
|
|
} |
1139
|
0
|
|
|
|
|
|
$fh->close; |
1140
|
|
|
|
|
|
|
|
1141
|
0
|
|
|
|
|
|
$self->{parent}->_log("writing $results/submit2.txt"); |
1142
|
0
|
|
|
|
|
|
$fh = IO::File->new(">$results/submit2.txt"); |
1143
|
0
|
|
|
|
|
|
print $fh "#INDEX,EXCLUSIVE,INCLUSIVE\n"; |
1144
|
0
|
|
|
|
|
|
for my $dotw (sort {$a <=> $b} keys %{$dotw{this}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1145
|
0
|
|
|
|
|
|
printf $fh "%d,%d,%d\n", $dotw, $dotw{this}{$dotw}, $dotw{that}{$dotw}; |
1146
|
|
|
|
|
|
|
} |
1147
|
0
|
|
|
|
|
|
$fh->close; |
1148
|
|
|
|
|
|
|
|
1149
|
0
|
|
|
|
|
|
$self->{parent}->_log("writing $results/submit3.txt"); |
1150
|
0
|
|
|
|
|
|
$fh = IO::File->new(">$results/submit3.txt"); |
1151
|
0
|
|
|
|
|
|
print $fh "#INDEX,EXCLUSIVE,INCLUSIVE\n"; |
1152
|
0
|
|
|
|
|
|
for my $day (sort {$a <=> $b} keys %{$days{this}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1153
|
0
|
|
|
|
|
|
printf $fh "%d,%d,%d\n", $day, $days{this}{$day}, $days{that}{$day}; |
1154
|
|
|
|
|
|
|
} |
1155
|
0
|
|
|
|
|
|
$fh->close; |
1156
|
|
|
|
|
|
|
|
1157
|
0
|
|
|
|
|
|
$self->{parent}->_log("writing $results/submit4.txt"); |
1158
|
0
|
|
|
|
|
|
$fh = IO::File->new(">$results/submit4.txt"); |
1159
|
0
|
|
|
|
|
|
print $fh "#INDEX,EXCLUSIVE,INCLUSIVE\n"; |
1160
|
0
|
|
|
|
|
|
for my $hour (sort {$a <=> $b} keys %{$hours{this}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1161
|
0
|
|
|
|
|
|
printf $fh "%d,%d,%d\n", $hour, $hours{this}{$hour}, $hours{that}{$hour}; |
1162
|
|
|
|
|
|
|
} |
1163
|
0
|
|
|
|
|
|
$fh->close; |
1164
|
|
|
|
|
|
|
|
1165
|
0
|
|
|
|
|
|
$self->_writepage('rates',\%tvars); |
1166
|
|
|
|
|
|
|
} |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
sub _build_noreports { |
1169
|
0
|
|
|
0
|
|
|
my $self = shift; |
1170
|
0
|
|
|
|
|
|
my $grace = time - 2419200; |
1171
|
|
|
|
|
|
|
|
1172
|
0
|
|
|
|
|
|
my %phrasebook = ( |
1173
|
|
|
|
|
|
|
'LATEST' => 'SELECT x.* FROM ixlatest AS x WHERE oncpan=1', |
1174
|
|
|
|
|
|
|
'NOREPORTS1' => 'SELECT x.* FROM ixlatest AS x LEFT JOIN stats_store AS s ON x.dist=s.dist WHERE oncpan=1 AND s.dist IS NULL ORDER BY x.dist', |
1175
|
|
|
|
|
|
|
'NOREPORTS2' => 'SELECT dist,osname FROM stats_store' |
1176
|
|
|
|
|
|
|
); |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
# load the distributions we can ignore from these lists |
1179
|
0
|
|
|
|
|
|
my $noreports = $self->{parent}->noreports(); |
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
# load the current list of known OSes |
1182
|
0
|
|
|
|
|
|
my $osnames = $self->{parent}->osnames(); |
1183
|
0
|
|
|
|
|
|
my @osnames = map { { osname => $_, ostitle => $osnames->{$_} } } sort {$osnames->{$a} cmp $osnames->{$b}} keys %$osnames; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# load all the latest distributions currently on CPAN |
1186
|
0
|
|
|
|
|
|
my (@rows,%dists,%osmap); |
1187
|
0
|
|
|
|
|
|
my $next = $self->{parent}->{CPANSTATS}->iterator('hash',$phrasebook{LATEST}); |
1188
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
1189
|
0
|
0
|
0
|
|
|
|
next if($noreports && $row->{dist} =~ /^$noreports$/); |
1190
|
0
|
0
|
|
|
|
|
next if($dists{$row->{dist}}); |
1191
|
0
|
0
|
|
|
|
|
next if($row->{released} > $grace); # ignore dists released within the grace period |
1192
|
|
|
|
|
|
|
|
1193
|
0
|
|
|
|
|
|
my @dt = localtime($row->{released}); |
1194
|
0
|
|
|
|
|
|
$row->{datetime} = sprintf "%04d-%02d-%02d", $dt[5]+1900,$dt[4]+1,$dt[3]; |
1195
|
0
|
|
|
|
|
|
$dists{$row->{dist}} = $row; |
1196
|
|
|
|
|
|
|
|
1197
|
0
|
|
|
|
|
|
$osmap{$row->{dist}}{$_->{osname}} = 1 for(@osnames); |
1198
|
|
|
|
|
|
|
} |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
# load all the dists with no OS reports at all |
1201
|
0
|
|
|
|
|
|
$next = $self->{parent}->{CPANSTATS}->iterator('hash',$phrasebook{NOREPORTS1}); |
1202
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
1203
|
0
|
0
|
|
|
|
|
next unless($dists{$row->{dist}}); |
1204
|
|
|
|
|
|
|
|
1205
|
0
|
|
|
|
|
|
push @rows, $dists{$row->{dist}}; |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
# write HTML & CSV files for dists with no reports at all |
1209
|
0
|
|
|
|
|
|
my $tvars = { rows => \@rows, rowcount => scalar(@rows), template => 'noreports', osnames => \@osnames, ostitle => 'ALL' }; |
1210
|
0
|
|
|
|
|
|
$self->_writepage('noreports/all',$tvars); |
1211
|
0
|
|
|
|
|
|
$tvars = { rows => \@rows, rowcount => scalar(@rows), template => 'noreports', extension => 'csv', osnames => \@osnames, ostitle => 'ALL' }; |
1212
|
0
|
|
|
|
|
|
$self->_writepage('noreports/all',$tvars); |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
# load all the dist to osname report mappings from the stats_store |
1216
|
0
|
|
|
|
|
|
$next = $self->{parent}->{CPANSTATS}->iterator('hash',$phrasebook{NOREPORTS2}); |
1217
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
1218
|
0
|
0
|
|
|
|
|
next unless($dists{$row->{dist}}); |
1219
|
|
|
|
|
|
|
|
1220
|
0
|
|
|
|
|
|
delete $osmap{$row->{dist}}{$row->{osname}}; |
1221
|
|
|
|
|
|
|
} |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
# loop for each OS |
1224
|
0
|
|
|
|
|
|
for my $os (@osnames) { |
1225
|
0
|
|
|
|
|
|
@rows = (); |
1226
|
0
|
|
|
|
|
|
for my $dist (sort keys %dists) { |
1227
|
0
|
0
|
|
|
|
|
next unless($osmap{$dist}{$os->{osname}}); |
1228
|
|
|
|
|
|
|
|
1229
|
0
|
|
|
|
|
|
push @rows, $dists{$dist}; |
1230
|
|
|
|
|
|
|
} |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
# write HTML & CSV files for dists without reports for specific OS |
1233
|
0
|
|
|
|
|
|
$tvars = { rows => \@rows, rowcount => scalar(@rows), template => 'noreports', osnames => \@osnames, ostitle => $os->{ostitle}, osname => $os->{osname} }; |
1234
|
0
|
|
|
|
|
|
$self->_writepage('noreports/'.$os->{osname},$tvars); |
1235
|
0
|
|
|
|
|
|
$tvars = { rows => \@rows, rowcount => scalar(@rows), template => 'noreports', extension => 'csv', osnames => \@osnames, ostitle => $os->{ostitle} }; |
1236
|
0
|
|
|
|
|
|
$self->_writepage('noreports/'.$os->{osname},$tvars); |
1237
|
|
|
|
|
|
|
} |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
sub _missing_in_action { |
1241
|
0
|
|
|
0
|
|
|
my $self = shift; |
1242
|
0
|
|
|
|
|
|
my (%tvars,%missing,@missing); |
1243
|
|
|
|
|
|
|
|
1244
|
0
|
|
|
|
|
|
$self->{parent}->_log("building missing in action page"); |
1245
|
|
|
|
|
|
|
|
1246
|
0
|
|
|
|
|
|
my $missing = $self->{parent}->missing(); |
1247
|
0
|
0
|
|
|
|
|
return unless(-f $missing); |
1248
|
0
|
0
|
|
|
|
|
my $fh = IO::File->new($missing) or return; |
1249
|
0
|
|
|
|
|
|
while(<$fh>) { |
1250
|
0
|
|
|
|
|
|
chomp; |
1251
|
0
|
|
|
|
|
|
my ($pauseid,$timestamp,$reason) = /^([a-z]+)[ \t]+([^+]+\+0[01]00) (.*)/i; |
1252
|
0
|
0
|
|
|
|
|
next unless($pauseid); |
1253
|
0
|
|
|
|
|
|
$reason =~ s/</</g; |
1254
|
0
|
|
|
|
|
|
$reason =~ s/>/>/g; |
1255
|
0
|
|
|
|
|
|
$missing{$pauseid}{timestamp} = $timestamp; |
1256
|
0
|
|
|
|
|
|
$missing{$pauseid}{reason} = $reason; |
1257
|
|
|
|
|
|
|
} |
1258
|
0
|
|
|
|
|
|
$fh->close; |
1259
|
|
|
|
|
|
|
|
1260
|
0
|
|
|
|
|
|
for my $pauseid (sort keys %missing) { |
1261
|
0
|
|
|
|
|
|
push @missing, { pauseid => $pauseid, timestamp => $missing{$pauseid}{timestamp}, reason => $missing{$pauseid}{reason} }; |
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
|
1264
|
0
|
0
|
|
|
|
|
$tvars{missing} = \@missing if(@missing); |
1265
|
0
|
|
|
|
|
|
$self->_writepage('missing',\%tvars); |
1266
|
|
|
|
|
|
|
} |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
sub _build_osname_matrix { |
1269
|
0
|
|
|
0
|
|
|
my $self = shift; |
1270
|
|
|
|
|
|
|
|
1271
|
0
|
|
|
|
|
|
my %tvars = (template => 'osmatrix', FULL => 1, MONTH => 0); |
1272
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 1"); |
1273
|
0
|
|
|
|
|
|
my $CONTENT = $self->_osname_matrix($self->{versions},'all',1); |
1274
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1275
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix-full',\%tvars); |
1276
|
|
|
|
|
|
|
|
1277
|
0
|
|
|
|
|
|
%tvars = (template => 'osmatrix', FULL => 1, MONTH => 0, layout => 'layout-wide'); |
1278
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1279
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 2"); |
1280
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix-full-wide',\%tvars); |
1281
|
|
|
|
|
|
|
|
1282
|
0
|
|
|
|
|
|
%tvars = (template => 'osmatrix', FULL => 1, MONTH => 1); |
1283
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 3"); |
1284
|
0
|
|
|
|
|
|
$CONTENT = $self->_osname_matrix($self->{versions},'month',1); |
1285
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1286
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix-full-month',\%tvars); |
1287
|
|
|
|
|
|
|
|
1288
|
0
|
|
|
|
|
|
%tvars = (template => 'osmatrix', FULL => 1, MONTH => 1, layout => 'layout-wide'); |
1289
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1290
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 4"); |
1291
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix-full-month-wide',\%tvars); |
1292
|
|
|
|
|
|
|
|
1293
|
0
|
|
|
|
|
|
my @vers = grep {!/^5\.(11|9|7)\./} @{$self->{versions}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
|
1295
|
0
|
|
|
|
|
|
%tvars = (template => 'osmatrix', FULL => 0, MONTH => 0); |
1296
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 5"); |
1297
|
0
|
|
|
|
|
|
$CONTENT = $self->_osname_matrix(\@vers,'all',0); |
1298
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1299
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix',\%tvars); |
1300
|
|
|
|
|
|
|
|
1301
|
0
|
|
|
|
|
|
%tvars = (template => 'osmatrix', FULL => 0, MONTH => 0, layout => 'layout-wide'); |
1302
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1303
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 6"); |
1304
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix-wide',\%tvars); |
1305
|
|
|
|
|
|
|
|
1306
|
0
|
|
|
|
|
|
%tvars = (template => 'osmatrix', FULL => 0, MONTH => 1); |
1307
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 7"); |
1308
|
0
|
|
|
|
|
|
$CONTENT = $self->_osname_matrix(\@vers,'month',0); |
1309
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1310
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix-month',\%tvars); |
1311
|
|
|
|
|
|
|
|
1312
|
0
|
|
|
|
|
|
%tvars = (template => 'osmatrix', FULL => 0, MONTH => 1, layout => 'layout-wide'); |
1313
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1314
|
0
|
|
|
|
|
|
$self->{parent}->_log("building OS matrix - 8"); |
1315
|
0
|
|
|
|
|
|
$self->_writepage('osmatrix-month-wide',\%tvars); |
1316
|
|
|
|
|
|
|
} |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
sub _osname_matrix { |
1319
|
0
|
|
|
0
|
|
|
my $self = shift; |
1320
|
0
|
0
|
|
|
|
|
my $vers = shift or return ''; |
1321
|
0
|
|
|
|
|
|
my $type = shift; |
1322
|
0
|
|
0
|
|
|
|
my $full = shift || 0; |
1323
|
0
|
0
|
|
|
|
|
return '' unless(@$vers); |
1324
|
|
|
|
|
|
|
|
1325
|
0
|
|
|
|
|
|
my %totals; |
1326
|
0
|
|
|
|
|
|
for my $osname (sort keys %{$self->{osys}}) { |
|
0
|
|
|
|
|
|
|
1327
|
0
|
0
|
|
|
|
|
if($type eq 'month') { |
1328
|
0
|
|
|
|
|
|
my $check = 0; |
1329
|
0
|
0
|
|
|
|
|
for my $perl (@$vers) { $check++ if(defined $self->{osys}{$osname}{$perl}{month}{$self->{dates}{LASTMONTH}}) } |
|
0
|
|
|
|
|
|
|
1330
|
0
|
0
|
|
|
|
|
next if($check == 0); |
1331
|
|
|
|
|
|
|
} |
1332
|
0
|
|
|
|
|
|
for my $perl (@$vers) { |
1333
|
|
|
|
|
|
|
my $count = defined $self->{osys}{$osname}{$perl}{$type} |
1334
|
|
|
|
|
|
|
? ($type eq 'month' |
1335
|
0
|
|
|
|
|
|
? scalar(keys %{$self->{osys}{$osname}{$perl}{month}{$self->{dates}{LASTMONTH}}}) |
1336
|
0
|
0
|
|
|
|
|
: scalar(keys %{$self->{osys}{$osname}{$perl}{$type}})) |
|
0
|
0
|
|
|
|
|
|
1337
|
|
|
|
|
|
|
: 0; |
1338
|
0
|
|
0
|
|
|
|
$count ||= 0; |
1339
|
0
|
|
|
|
|
|
$totals{os}{$osname} += $count; |
1340
|
0
|
|
|
|
|
|
$totals{perl}{$perl} += $count; |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
} |
1343
|
|
|
|
|
|
|
|
1344
|
0
|
|
|
|
|
|
my $index = 0; |
1345
|
|
|
|
|
|
|
my $content = |
1346
|
|
|
|
|
|
|
"\n" |
1347
|
|
|
|
|
|
|
. '<table class="matrix" summary="OS/Perl Matrix">' |
1348
|
|
|
|
|
|
|
. "\n" |
1349
|
|
|
|
|
|
|
. '<tr><th>OS/Perl</th><th></th><th>' |
1350
|
|
|
|
|
|
|
. join( "</th><th>", @$vers ) |
1351
|
|
|
|
|
|
|
. '</th><th></th><th>OS/Perl</th></tr>' |
1352
|
|
|
|
|
|
|
. "\n" |
1353
|
|
|
|
|
|
|
. '<tr><th></th><th class="totals">Totals</th><th class="totals">' |
1354
|
0
|
0
|
|
|
|
|
. join( '</th><th class="totals">', map {$totals{perl}{$_}||0} @$vers ) |
|
0
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
. '</th><th class="totals">Totals</th><th></th></tr>'; |
1356
|
|
|
|
|
|
|
|
1357
|
0
|
0
|
|
|
|
|
for my $osname (sort {$totals{os}{$b} <=> $totals{os}{$a} || $a cmp $b} keys %{$totals{os}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1358
|
0
|
0
|
|
|
|
|
if($type eq 'month') { |
1359
|
0
|
|
|
|
|
|
my $check = 0; |
1360
|
0
|
0
|
|
|
|
|
for my $perl (@$vers) { $check++ if(defined $self->{osys}{$osname}{$perl}{month}{$self->{dates}{LASTMONTH}}) } |
|
0
|
|
|
|
|
|
|
1361
|
0
|
0
|
|
|
|
|
next if($check == 0); |
1362
|
|
|
|
|
|
|
} |
1363
|
0
|
|
|
|
|
|
$content .= "\n" . '<tr><th>' . $osname . '</th><th class="totals">' . $totals{os}{$osname} . '</th>'; |
1364
|
0
|
|
|
|
|
|
for my $perl (@$vers) { |
1365
|
|
|
|
|
|
|
my $count = defined $self->{osys}{$osname}{$perl}{$type} |
1366
|
|
|
|
|
|
|
? ($type eq 'month' |
1367
|
0
|
|
|
|
|
|
? scalar(keys %{$self->{osys}{$osname}{$perl}{month}{$self->{dates}{LASTMONTH}}}) |
1368
|
0
|
0
|
|
|
|
|
: scalar(keys %{$self->{osys}{$osname}{$perl}{$type}})) |
|
0
|
0
|
|
|
|
|
|
1369
|
|
|
|
|
|
|
: 0; |
1370
|
0
|
|
0
|
|
|
|
$count ||= 0; |
1371
|
0
|
0
|
|
|
|
|
if($count) { |
1372
|
0
|
0
|
|
|
|
|
if($self->{list}{osname}{$osname}{$perl}{$type}) { |
1373
|
0
|
|
|
|
|
|
$index = $self->{list}{osname}{$osname}{$perl}{$type}; |
1374
|
|
|
|
|
|
|
} else { |
1375
|
0
|
0
|
|
|
|
|
my %tvars = (template => 'distlist', OS => 1, MONTH => ($type eq 'month' ? 1 : 0), FULL => $full); |
1376
|
0
|
|
|
|
|
|
my @list = sort keys %{$self->{osys}{$osname}{$perl}{$type}}; |
|
0
|
|
|
|
|
|
|
1377
|
0
|
|
|
|
|
|
$tvars{dists} = \@list; |
1378
|
0
|
|
|
|
|
|
$tvars{vplatform} = $osname; |
1379
|
0
|
|
|
|
|
|
$tvars{vperl} = $perl; |
1380
|
0
|
|
|
|
|
|
$tvars{count} = $count; |
1381
|
|
|
|
|
|
|
|
1382
|
0
|
|
|
|
|
|
$index = join('-','osys', $type, $osname, $perl); |
1383
|
0
|
|
|
|
|
|
$index =~ s/[^-.\w]/-/g; |
1384
|
0
|
|
|
|
|
|
$index = 'matrix/' . $index; |
1385
|
0
|
|
|
|
|
|
$self->{list}{osname}{$osname}{$perl}{$type} = $index; |
1386
|
0
|
|
|
|
|
|
$self->_writepage($index,\%tvars); |
1387
|
|
|
|
|
|
|
} |
1388
|
|
|
|
|
|
|
} |
1389
|
|
|
|
|
|
|
|
1390
|
0
|
0
|
|
|
|
|
my $number = ($type eq 'month' ? $self->{osname}{$osname}{$perl}{month}{$self->{dates}{LASTMONTH}} : $self->{osname}{$osname}{$perl}{$type}); |
1391
|
0
|
|
0
|
|
|
|
$number ||= 0; |
1392
|
0
|
|
|
|
|
|
my $class = 'none'; |
1393
|
0
|
0
|
|
|
|
|
$class = 'some' if($number > 0); |
1394
|
0
|
0
|
|
|
|
|
$class = 'more' if($number > $matrix_limits{$type}->[0]); |
1395
|
0
|
0
|
|
|
|
|
$class = 'lots' if($number > $matrix_limits{$type}->[1]); |
1396
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
# count = number of distributions with a pass |
1398
|
|
|
|
|
|
|
# number = number of reports submitted for that platform/perl |
1399
|
0
|
0
|
|
|
|
|
$content .= qq{<td class="$class">} |
1400
|
|
|
|
|
|
|
. ($count ? qq|<a href="$index.html" title="Distribution List for $osname/$perl">$count</a><br />$number| : '-') |
1401
|
|
|
|
|
|
|
. '</td>'; |
1402
|
|
|
|
|
|
|
} |
1403
|
0
|
|
|
|
|
|
$content .= '<th class="totals">' . $totals{os}{$osname} . '</th><th>' . $osname . '</th>'; |
1404
|
0
|
|
|
|
|
|
$content .= '</tr>'; |
1405
|
|
|
|
|
|
|
} |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
$content .= |
1408
|
|
|
|
|
|
|
"\n" |
1409
|
|
|
|
|
|
|
. '<tr><th></th><th class="totals">Totals</th><th class="totals">' |
1410
|
0
|
0
|
|
|
|
|
. join( '</th><th class="totals">', map {$totals{perl}{$_}||0} @$vers ) |
|
0
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
. '</th><th class="totals">Totals</th><th></th></tr>' |
1412
|
|
|
|
|
|
|
. "\n" |
1413
|
|
|
|
|
|
|
. '<tr><th>OS/Perl</th><th></th><th>' |
1414
|
|
|
|
|
|
|
. join( "</th><th>", @$vers ) |
1415
|
|
|
|
|
|
|
. '</th><th></th><th>OS/Perl</th></tr>' |
1416
|
|
|
|
|
|
|
. "\n" . |
1417
|
|
|
|
|
|
|
'</table>'; |
1418
|
|
|
|
|
|
|
|
1419
|
0
|
|
|
|
|
|
return $content; |
1420
|
|
|
|
|
|
|
} |
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
sub _build_platform_matrix { |
1423
|
0
|
|
|
0
|
|
|
my $self = shift; |
1424
|
|
|
|
|
|
|
|
1425
|
0
|
|
|
|
|
|
my %tvars = (template => 'pmatrix', FULL => 1, MONTH => 0); |
1426
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 1"); |
1427
|
0
|
|
|
|
|
|
my $CONTENT = $self->_platform_matrix($self->{versions},'all',1); |
1428
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1429
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix-full',\%tvars); |
1430
|
|
|
|
|
|
|
|
1431
|
0
|
|
|
|
|
|
%tvars = (template => 'pmatrix', FULL => 1, MONTH => 0, layout => 'layout-wide'); |
1432
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1433
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 2"); |
1434
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix-full-wide',\%tvars); |
1435
|
|
|
|
|
|
|
|
1436
|
0
|
|
|
|
|
|
%tvars = (template => 'pmatrix', FULL => 1, MONTH => 1); |
1437
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 3"); |
1438
|
0
|
|
|
|
|
|
$CONTENT = $self->_platform_matrix($self->{versions},'month',1); |
1439
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1440
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix-full-month',\%tvars); |
1441
|
|
|
|
|
|
|
|
1442
|
0
|
|
|
|
|
|
%tvars = (template => 'pmatrix', FULL => 1, MONTH => 1, layout => 'layout-wide'); |
1443
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1444
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 4"); |
1445
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix-full-month-wide',\%tvars); |
1446
|
|
|
|
|
|
|
|
1447
|
0
|
|
|
|
|
|
my @vers = grep {!/^5\.(11|9|7)\./} @{$self->{versions}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
|
1449
|
0
|
|
|
|
|
|
%tvars = (template => 'pmatrix', FULL => 0, MONTH => 0); |
1450
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 5"); |
1451
|
0
|
|
|
|
|
|
$CONTENT = $self->_platform_matrix(\@vers,'all',0); |
1452
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1453
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix',\%tvars); |
1454
|
|
|
|
|
|
|
|
1455
|
0
|
|
|
|
|
|
%tvars = (template => 'pmatrix', FULL => 0, MONTH => 0, layout => 'layout-wide'); |
1456
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1457
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 6"); |
1458
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix-wide',\%tvars); |
1459
|
|
|
|
|
|
|
|
1460
|
0
|
|
|
|
|
|
%tvars = (template => 'pmatrix', FULL => 0, MONTH => 1); |
1461
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 7"); |
1462
|
0
|
|
|
|
|
|
$CONTENT = $self->_platform_matrix(\@vers,'month',0); |
1463
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1464
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix-month',\%tvars); |
1465
|
|
|
|
|
|
|
|
1466
|
0
|
|
|
|
|
|
%tvars = (template => 'pmatrix', FULL => 0, MONTH => 1, layout => 'layout-wide'); |
1467
|
0
|
|
|
|
|
|
$tvars{CONTENT} = $CONTENT; |
1468
|
0
|
|
|
|
|
|
$self->{parent}->_log("building platform matrix - 8"); |
1469
|
0
|
|
|
|
|
|
$self->_writepage('pmatrix-month-wide',\%tvars); |
1470
|
|
|
|
|
|
|
} |
1471
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
sub _platform_matrix { |
1473
|
0
|
|
|
0
|
|
|
my $self = shift; |
1474
|
0
|
0
|
|
|
|
|
my $vers = shift or return ''; |
1475
|
0
|
|
|
|
|
|
my $type = shift; |
1476
|
0
|
|
0
|
|
|
|
my $full = shift || 0; |
1477
|
0
|
0
|
|
|
|
|
return '' unless(@$vers); |
1478
|
|
|
|
|
|
|
|
1479
|
0
|
|
|
|
|
|
my %totals; |
1480
|
0
|
|
|
|
|
|
for my $platform (sort keys %{$self->{pass}}) { |
|
0
|
|
|
|
|
|
|
1481
|
0
|
0
|
|
|
|
|
if($type eq 'month') { |
1482
|
0
|
|
|
|
|
|
my $check = 0; |
1483
|
0
|
0
|
|
|
|
|
for my $perl (@$vers) { $check++ if(defined $self->{pass}{$platform}{$perl}{month}{$self->{dates}{LASTMONTH}}) } |
|
0
|
|
|
|
|
|
|
1484
|
0
|
0
|
|
|
|
|
next if($check == 0); |
1485
|
|
|
|
|
|
|
} |
1486
|
0
|
|
|
|
|
|
for my $perl (@$vers) { |
1487
|
|
|
|
|
|
|
my $count = defined $self->{pass}{$platform}{$perl}{$type} |
1488
|
|
|
|
|
|
|
? ($type eq 'month' |
1489
|
0
|
|
|
|
|
|
? scalar(keys %{$self->{pass}{$platform}{$perl}{month}{$self->{dates}{LASTMONTH}}}) |
1490
|
0
|
0
|
|
|
|
|
: scalar(keys %{$self->{pass}{$platform}{$perl}{$type}})) |
|
0
|
0
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
: 0; |
1492
|
0
|
|
0
|
|
|
|
$count ||= 0; |
1493
|
0
|
|
|
|
|
|
$totals{platform}{$platform} += $count; |
1494
|
0
|
|
|
|
|
|
$totals{perl}{$perl} += $count; |
1495
|
|
|
|
|
|
|
} |
1496
|
|
|
|
|
|
|
} |
1497
|
|
|
|
|
|
|
|
1498
|
0
|
|
|
|
|
|
my $index = 0; |
1499
|
|
|
|
|
|
|
my $content = |
1500
|
|
|
|
|
|
|
"\n" |
1501
|
|
|
|
|
|
|
. '<table class="matrix" summary="Platform/Perl Matrix">' |
1502
|
|
|
|
|
|
|
. "\n" |
1503
|
|
|
|
|
|
|
. '<tr><th>Platform/Perl</th><th></th><th>' |
1504
|
|
|
|
|
|
|
. join( "</th><th>", @$vers ) |
1505
|
|
|
|
|
|
|
. '</th><th></th><th>Platform/Perl</th></tr>' |
1506
|
|
|
|
|
|
|
. "\n" |
1507
|
|
|
|
|
|
|
. '<tr><th></th><th class="totals">Totals</th><th class="totals">' |
1508
|
0
|
0
|
|
|
|
|
. join( '</th><th class="totals">', map {$totals{perl}{$_}||0} @$vers ) |
|
0
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
. '</th><th class="totals">Totals</th><th></th></tr>'; |
1510
|
|
|
|
|
|
|
|
1511
|
0
|
0
|
|
|
|
|
for my $platform (sort {$totals{platform}{$b} <=> $totals{platform}{$a} || $a cmp $b} keys %{$totals{platform}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1512
|
0
|
0
|
|
|
|
|
if($type eq 'month') { |
1513
|
0
|
|
|
|
|
|
my $check = 0; |
1514
|
0
|
0
|
|
|
|
|
for my $perl (@$vers) { $check++ if(defined $self->{pass}{$platform}{$perl}{month}{$self->{dates}{LASTMONTH}}) } |
|
0
|
|
|
|
|
|
|
1515
|
0
|
0
|
|
|
|
|
next if($check == 0); |
1516
|
|
|
|
|
|
|
} |
1517
|
0
|
|
|
|
|
|
$content .= "\n" . '<tr><th>' . $platform . '</th><th class="totals">' . $totals{platform}{$platform} . '</th>'; |
1518
|
0
|
|
|
|
|
|
for my $perl (@$vers) { |
1519
|
|
|
|
|
|
|
my $count = defined $self->{pass}{$platform}{$perl}{$type} |
1520
|
|
|
|
|
|
|
? ($type eq 'month' |
1521
|
0
|
|
|
|
|
|
? scalar(keys %{$self->{pass}{$platform}{$perl}{month}{$self->{dates}{LASTMONTH}}}) |
1522
|
0
|
0
|
|
|
|
|
: scalar(keys %{$self->{pass}{$platform}{$perl}{$type}})) |
|
0
|
0
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
: 0; |
1524
|
0
|
|
0
|
|
|
|
$count ||= 0; |
1525
|
0
|
0
|
|
|
|
|
if($count) { |
1526
|
0
|
0
|
|
|
|
|
if($self->{list}{platform}{$platform}{$perl}{$type}) { |
1527
|
0
|
|
|
|
|
|
$index = $self->{list}{platform}{$platform}{$perl}{$type}; |
1528
|
|
|
|
|
|
|
} else { |
1529
|
0
|
0
|
|
|
|
|
my %tvars = (template => 'distlist', OS => 0, MONTH => ($type eq 'month' ? 1 : 0), FULL => $full); |
1530
|
0
|
|
|
|
|
|
my @list = sort keys %{$self->{pass}{$platform}{$perl}{$type}}; |
|
0
|
|
|
|
|
|
|
1531
|
0
|
|
|
|
|
|
$tvars{dists} = \@list; |
1532
|
0
|
|
|
|
|
|
$tvars{vplatform} = $platform; |
1533
|
0
|
|
|
|
|
|
$tvars{vperl} = $perl; |
1534
|
0
|
|
|
|
|
|
$tvars{count} = $count; |
1535
|
|
|
|
|
|
|
|
1536
|
0
|
|
|
|
|
|
$index = join('-','platform', $type, $platform, $perl); |
1537
|
0
|
|
|
|
|
|
$index =~ s/[^-.\w]/-/g; |
1538
|
0
|
|
|
|
|
|
$index = 'matrix/' . $index; |
1539
|
0
|
|
|
|
|
|
$self->{list}{platform}{$platform}{$perl}{$type} = $index; |
1540
|
0
|
|
|
|
|
|
$self->_writepage($index,\%tvars); |
1541
|
|
|
|
|
|
|
} |
1542
|
|
|
|
|
|
|
} |
1543
|
|
|
|
|
|
|
|
1544
|
0
|
0
|
|
|
|
|
my $number = ($type eq 'month' ? $self->{platform}{$platform}{$perl}{month}{$self->{dates}{LASTMONTH}} : $self->{platform}{$platform}{$perl}{$type}); |
1545
|
0
|
|
0
|
|
|
|
$number ||= 0; |
1546
|
0
|
|
|
|
|
|
my $class = 'none'; |
1547
|
0
|
0
|
|
|
|
|
$class = 'some' if($number > 0); |
1548
|
0
|
0
|
|
|
|
|
$class = 'more' if($number > $matrix_limits{$type}->[0]); |
1549
|
0
|
0
|
|
|
|
|
$class = 'lots' if($number > $matrix_limits{$type}->[1]); |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
# count = number of distributions with a pass |
1552
|
|
|
|
|
|
|
# number = number of reports submitted for that platform/perl |
1553
|
0
|
0
|
|
|
|
|
$content .= qq{<td class="$class">} |
1554
|
|
|
|
|
|
|
. ($count ? qq|<a href="$index.html" title="Distribution List for $platform/$perl">$count</a><br />$number| : '-') |
1555
|
|
|
|
|
|
|
. '</td>'; |
1556
|
|
|
|
|
|
|
} |
1557
|
0
|
|
|
|
|
|
$content .= '<th class="totals">' . $totals{platform}{$platform} . '</th><th>' . $platform . '</th>'; |
1558
|
0
|
|
|
|
|
|
$content .= '</tr>'; |
1559
|
|
|
|
|
|
|
} |
1560
|
|
|
|
|
|
|
$content .= |
1561
|
|
|
|
|
|
|
"\n" |
1562
|
|
|
|
|
|
|
. '<tr><th></th><th class="totals">Totals</th><th class="totals">' |
1563
|
0
|
0
|
|
|
|
|
. join( '</th><th class="totals">', map {$totals{perl}{$_}||0} @$vers ) |
|
0
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
. '</th><th class="totals">Totals</th><th></th></tr>' |
1565
|
|
|
|
|
|
|
. "\n" |
1566
|
|
|
|
|
|
|
. '<tr><th>Platform/Perl</th><th></th><th>' |
1567
|
|
|
|
|
|
|
. join( "</th><th>", @$vers ) |
1568
|
|
|
|
|
|
|
. '</th><th></th><th>Platform/Perl</th></tr>' |
1569
|
|
|
|
|
|
|
. "\n" |
1570
|
|
|
|
|
|
|
. '</table>'; |
1571
|
|
|
|
|
|
|
|
1572
|
0
|
|
|
|
|
|
return $content; |
1573
|
|
|
|
|
|
|
} |
1574
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
# Notes: |
1576
|
|
|
|
|
|
|
# |
1577
|
|
|
|
|
|
|
# * use a JSON store (e.g. cpanstats-platform.json) |
1578
|
|
|
|
|
|
|
# * find the last month stored |
1579
|
|
|
|
|
|
|
# * rebuild from last month to current month |
1580
|
|
|
|
|
|
|
# * store JSON data |
1581
|
|
|
|
|
|
|
|
1582
|
|
|
|
|
|
|
sub _build_monthly_stats { |
1583
|
0
|
|
|
0
|
|
|
my $self = shift; |
1584
|
0
|
|
|
|
|
|
my (%tvars,%stats,%testers,%monthly); |
1585
|
0
|
|
|
|
|
|
my %templates = ( |
1586
|
|
|
|
|
|
|
platform => 'mplatforms', |
1587
|
|
|
|
|
|
|
osname => 'mosname', |
1588
|
|
|
|
|
|
|
perl => 'mperls', |
1589
|
|
|
|
|
|
|
tester => 'mtesters' |
1590
|
|
|
|
|
|
|
); |
1591
|
|
|
|
|
|
|
|
1592
|
0
|
|
|
|
|
|
$self->{parent}->_log("building monthly tables"); |
1593
|
|
|
|
|
|
|
|
1594
|
0
|
|
|
|
|
|
my $query = q!SELECT postdate,%s,count(id) AS count FROM cpanstats ! . |
1595
|
|
|
|
|
|
|
q!WHERE type = 2 %s ! . |
1596
|
|
|
|
|
|
|
q!GROUP BY postdate,%s ORDER BY postdate,count DESC,%s!; |
1597
|
|
|
|
|
|
|
|
1598
|
0
|
|
|
|
|
|
for my $type (qw(platform osname perl)) { |
1599
|
0
|
|
|
|
|
|
$self->{parent}->_log("building monthly $type table"); |
1600
|
0
|
|
|
|
|
|
(%tvars,%stats,%monthly) = (); |
1601
|
0
|
|
|
|
|
|
my $postdate = ''; |
1602
|
|
|
|
|
|
|
|
1603
|
0
|
|
|
|
|
|
my $json = $self->storage_read($type); |
1604
|
0
|
0
|
|
|
|
|
if($json) { |
1605
|
0
|
|
|
|
|
|
my $last = 0; |
1606
|
0
|
|
|
|
|
|
for my $date (keys %{ $json->{monthly} }) { |
|
0
|
|
|
|
|
|
|
1607
|
0
|
0
|
|
|
|
|
$last = $date if($date > $last); |
1608
|
|
|
|
|
|
|
} |
1609
|
|
|
|
|
|
|
|
1610
|
0
|
|
|
|
|
|
delete $json->{$_}{$last} for(qw(monthly stats)); |
1611
|
|
|
|
|
|
|
|
1612
|
0
|
|
|
|
|
|
%monthly = %{ $json->{monthly} }; |
|
0
|
|
|
|
|
|
|
1613
|
0
|
|
|
|
|
|
%stats = %{ $json->{stats} }; |
|
0
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
|
1615
|
0
|
0
|
|
|
|
|
$postdate = "AND postdate >= '$last'" if($last); |
1616
|
|
|
|
|
|
|
} |
1617
|
|
|
|
|
|
|
|
1618
|
0
|
|
|
|
|
|
my $sql = sprintf $query, $type, $postdate, $type, $type; |
1619
|
0
|
|
|
|
|
|
my $next = $self->{parent}->{CPANSTATS}->iterator('hash',$sql); |
1620
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
1621
|
0
|
|
|
|
|
|
$monthly{$row->{postdate}}{$type}{$row->{$type}} = 1; |
1622
|
0
|
0
|
|
|
|
|
$row->{$type} = $self->{parent}->osname($row->{$type}) if($type eq 'osname'); |
1623
|
0
|
|
|
|
|
|
push @{$stats{$row->{postdate}}{list}}, "[$row->{count}] $row->{$type}"; |
|
0
|
|
|
|
|
|
|
1624
|
|
|
|
|
|
|
} |
1625
|
|
|
|
|
|
|
|
1626
|
0
|
|
|
|
|
|
for my $date (sort {$b <=> $a} keys %stats) { |
|
0
|
|
|
|
|
|
|
1627
|
0
|
|
|
|
|
|
$stats{$date}{count} = scalar(@{$stats{$date}{list}}); |
|
0
|
|
|
|
|
|
|
1628
|
0
|
|
|
|
|
|
push @{$tvars{STATS}}, [$date,$stats{$date}{count},join(', ',@{$stats{$date}{list}})]; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1629
|
|
|
|
|
|
|
} |
1630
|
0
|
|
|
|
|
|
$self->_writepage($templates{$type},\%tvars); |
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
# remember monthly counts for monthly files later |
1633
|
0
|
|
|
|
|
|
for my $date (keys %monthly) { |
1634
|
0
|
|
|
|
|
|
$self->{monthly}{$date}{$type} = keys %{ $monthly{$date}{$type} }; |
|
0
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
} |
1636
|
|
|
|
|
|
|
|
1637
|
|
|
|
|
|
|
# store data |
1638
|
0
|
|
|
|
|
|
my $hash = { monthly => \%monthly, stats => \%stats }; |
1639
|
0
|
|
|
|
|
|
$self->storage_write($type,$hash); |
1640
|
|
|
|
|
|
|
} |
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
{ |
1643
|
0
|
|
|
|
|
|
my $type = 'tester'; |
|
0
|
|
|
|
|
|
|
1644
|
0
|
|
|
|
|
|
$self->{parent}->_log("building monthly $type table"); |
1645
|
0
|
|
|
|
|
|
(%tvars,%stats,%monthly) = (); |
1646
|
0
|
|
|
|
|
|
my $postdate = ''; |
1647
|
|
|
|
|
|
|
|
1648
|
0
|
|
|
|
|
|
my $json = $self->storage_read($type); |
1649
|
0
|
0
|
|
|
|
|
if($json) { |
1650
|
0
|
|
|
|
|
|
my $last = 0; |
1651
|
0
|
|
|
|
|
|
for my $date (keys %{ $json->{monthly} }) { |
|
0
|
|
|
|
|
|
|
1652
|
0
|
0
|
|
|
|
|
$last = $date if($date > $last); |
1653
|
|
|
|
|
|
|
} |
1654
|
|
|
|
|
|
|
|
1655
|
0
|
|
|
|
|
|
delete $json->{$_}{$last} for(qw(monthly stats)); |
1656
|
|
|
|
|
|
|
|
1657
|
0
|
|
|
|
|
|
%monthly = %{ $json->{monthly} }; |
|
0
|
|
|
|
|
|
|
1658
|
0
|
|
|
|
|
|
%stats = %{ $json->{stats} }; |
|
0
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
|
1660
|
0
|
0
|
|
|
|
|
$postdate = "AND postdate >= '$last'" if($last); |
1661
|
|
|
|
|
|
|
} |
1662
|
|
|
|
|
|
|
|
1663
|
0
|
|
|
|
|
|
my $sql = sprintf $query, $type, $postdate, $type, $type; |
1664
|
0
|
|
|
|
|
|
my $next = $self->{parent}->{CPANSTATS}->iterator('hash',$sql); |
1665
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
1666
|
0
|
|
|
|
|
|
my ($name) = $self->{parent}->tester($row->{tester}); |
1667
|
0
|
|
|
|
|
|
$testers{$name} += $row->{count}; |
1668
|
0
|
|
|
|
|
|
$stats{$row->{postdate}}{list}{$name} += $row->{count}; |
1669
|
0
|
|
|
|
|
|
$monthly{$row->{postdate}}{$type}{$name} = 1; |
1670
|
|
|
|
|
|
|
} |
1671
|
|
|
|
|
|
|
|
1672
|
0
|
|
|
|
|
|
for my $date (sort {$b <=> $a} keys %stats) { |
|
0
|
|
|
|
|
|
|
1673
|
0
|
|
|
|
|
|
$stats{$date}{count} = keys %{$stats{$date}{list}}; |
|
0
|
|
|
|
|
|
|
1674
|
0
|
|
|
|
|
|
push @{$tvars{STATS}}, [$date,$stats{$date}{count}, |
1675
|
|
|
|
|
|
|
join(', ', |
1676
|
0
|
|
|
|
|
|
map {"[$stats{$date}{list}{$_}] $_"} |
1677
|
0
|
0
|
|
|
|
|
sort {$stats{$date}{list}{$b} <=> $stats{$date}{list}{$a} || $a cmp $b} |
1678
|
0
|
|
|
|
|
|
keys %{$stats{$date}{list}})]; |
|
0
|
|
|
|
|
|
|
1679
|
|
|
|
|
|
|
} |
1680
|
0
|
|
|
|
|
|
$self->_writepage($templates{$type},\%tvars); |
1681
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
# remember monthly counts for monthly files later |
1683
|
0
|
|
|
|
|
|
for my $date (keys %monthly) { |
1684
|
0
|
|
|
|
|
|
$self->{monthly}{$date}{$type} = keys %{ $monthly{$date}{$type} }; |
|
0
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
} |
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
# store data |
1688
|
0
|
|
|
|
|
|
my $hash = { monthly => \%monthly, stats => \%stats }; |
1689
|
0
|
|
|
|
|
|
$self->storage_write($type,$hash); |
1690
|
|
|
|
|
|
|
} |
1691
|
|
|
|
|
|
|
} |
1692
|
|
|
|
|
|
|
|
1693
|
|
|
|
|
|
|
sub _build_osname_leaderboards { |
1694
|
0
|
|
|
0
|
|
|
my $self = shift; |
1695
|
|
|
|
|
|
|
|
1696
|
0
|
|
|
|
|
|
$self->{parent}->_log("building osname leaderboards"); |
1697
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
# set dates |
1699
|
0
|
|
|
|
|
|
my $post0 = '999999'; |
1700
|
0
|
|
|
|
|
|
my $post1 = $self->{dates}{THATMONTH}; |
1701
|
0
|
|
|
|
|
|
my $post2 = $self->{dates}{LASTMONTH}; |
1702
|
0
|
|
|
|
|
|
my $post3 = $self->{dates}{THISMONTH}; |
1703
|
|
|
|
|
|
|
|
1704
|
0
|
|
|
|
|
|
my @dates = ($post0, $post1, $post2, $post3); |
1705
|
0
|
|
|
|
|
|
my %dates = map {$_ => 1} @dates; |
|
0
|
|
|
|
|
|
|
1706
|
|
|
|
|
|
|
|
1707
|
0
|
|
|
|
|
|
$self->{parent}->_log("1.post0=$post0"); |
1708
|
0
|
|
|
|
|
|
$self->{parent}->_log("2.post1=$post1"); |
1709
|
0
|
|
|
|
|
|
$self->{parent}->_log("3.post2=$post2"); |
1710
|
0
|
|
|
|
|
|
$self->{parent}->_log("4.post3=$post3"); |
1711
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
# load data |
1713
|
0
|
|
|
|
|
|
my $data = $self->{parent}->leaderboard( results => \@dates ); |
1714
|
0
|
|
|
|
|
|
$self->{parent}->tester( 'test' ); |
1715
|
|
|
|
|
|
|
|
1716
|
0
|
|
|
|
|
|
my @posts = sort keys %$data; |
1717
|
0
|
|
|
|
|
|
$self->{parent}->_log("5.posts[0]=$posts[0]"); |
1718
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
# store data for the last 3 months, and in total |
1720
|
0
|
|
|
|
|
|
my %oses; |
1721
|
0
|
|
|
|
|
|
for my $post (keys %$data) { |
1722
|
0
|
0
|
|
|
|
|
if($dates{$post}) { |
1723
|
0
|
|
|
|
|
|
for my $os (keys %{$data->{$post}}) { |
|
0
|
|
|
|
|
|
|
1724
|
0
|
0
|
|
|
|
|
next unless($os); |
1725
|
0
|
|
|
|
|
|
$oses{$os} = 1; |
1726
|
0
|
|
|
|
|
|
for my $tester (keys %{$data->{$post}{$os}}) { |
|
0
|
|
|
|
|
|
|
1727
|
0
|
|
0
|
|
|
|
$data->{$post0}{$os}{$tester} ||= 0; # make sure we include all testers |
1728
|
|
|
|
|
|
|
} |
1729
|
|
|
|
|
|
|
} |
1730
|
|
|
|
|
|
|
} else { |
1731
|
0
|
|
|
|
|
|
for my $os (keys %{$data->{$post}}) { |
|
0
|
|
|
|
|
|
|
1732
|
0
|
0
|
|
|
|
|
next unless($os); |
1733
|
0
|
|
|
|
|
|
$oses{$os} = 1; |
1734
|
0
|
|
|
|
|
|
for my $tester (keys %{$data->{$post}{$os}}) { |
|
0
|
|
|
|
|
|
|
1735
|
0
|
|
|
|
|
|
$data->{$post0}{$os}{$tester} += $data->{$post}{$os}{$tester}; |
1736
|
|
|
|
|
|
|
} |
1737
|
|
|
|
|
|
|
} |
1738
|
0
|
|
|
|
|
|
delete $data->{$post}; |
1739
|
|
|
|
|
|
|
} |
1740
|
|
|
|
|
|
|
} |
1741
|
|
|
|
|
|
|
|
1742
|
|
|
|
|
|
|
#$self->{parent}->_log("6.data=".Dumper($data)); |
1743
|
|
|
|
|
|
|
|
1744
|
|
|
|
|
|
|
# reorganise data |
1745
|
0
|
|
|
|
|
|
my %hash; |
1746
|
0
|
|
|
|
|
|
for my $os (keys %oses) { |
1747
|
0
|
|
|
|
|
|
for my $tester (keys %{$data->{$post0}{$os}}) { |
|
0
|
|
|
|
|
|
|
1748
|
0
|
|
0
|
|
|
|
$hash{$os}{$tester}{this} = $data->{$post3}{$os}{$tester} || 0; |
1749
|
0
|
|
0
|
|
|
|
$hash{$os}{$tester}{that} = $data->{$post2}{$os}{$tester} || 0; |
1750
|
|
|
|
|
|
|
$hash{$os}{$tester}{all} = ($data->{$post3}{$os}{$tester} || 0) + ($data->{$post2}{$os}{$tester} || 0) + |
1751
|
0
|
|
0
|
|
|
|
($data->{$post1}{$os}{$tester} || 0) + ($data->{$post0}{$os}{$tester} || 0); |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1752
|
|
|
|
|
|
|
} |
1753
|
|
|
|
|
|
|
} |
1754
|
|
|
|
|
|
|
|
1755
|
0
|
|
|
|
|
|
$self->{parent}->_log("1.reorg"); |
1756
|
|
|
|
|
|
|
|
1757
|
0
|
|
|
|
|
|
my %titles = ( |
1758
|
|
|
|
|
|
|
this => 'This Month', |
1759
|
|
|
|
|
|
|
that => 'Last Month', |
1760
|
|
|
|
|
|
|
all => 'All Months' |
1761
|
|
|
|
|
|
|
); |
1762
|
|
|
|
|
|
|
|
1763
|
0
|
|
|
|
|
|
my $sql = 'SELECT * FROM osname ORDER BY ostitle'; |
1764
|
0
|
|
|
|
|
|
my @rows = $self->{parent}->{CPANSTATS}->get_query('hash',$sql); |
1765
|
0
|
|
|
|
|
|
my @oses = grep {$_->{osname}} @rows; |
|
0
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
|
1767
|
0
|
|
|
|
|
|
for my $osname (keys %oses) { |
1768
|
0
|
0
|
|
|
|
|
next unless($osname); |
1769
|
0
|
|
|
|
|
|
for my $type (qw(this that all)) { |
1770
|
0
|
|
|
|
|
|
my @leaders; |
1771
|
0
|
0
|
0
|
|
|
|
for my $tester (sort {($hash{$osname}{$b}{$type} || 0) <=> ($hash{$osname}{$a}{$type} || 0) || $a cmp $b} keys %{$hash{$osname}}) { |
|
0
|
|
0
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1772
|
|
|
|
|
|
|
push @leaders, |
1773
|
|
|
|
|
|
|
{ col2 => $hash{$osname}{$tester}{this}, |
1774
|
|
|
|
|
|
|
col1 => $hash{$osname}{$tester}{that}, |
1775
|
|
|
|
|
|
|
col3 => $hash{$osname}{$tester}{all}, |
1776
|
0
|
|
|
|
|
|
tester => $tester |
1777
|
|
|
|
|
|
|
} ; |
1778
|
|
|
|
|
|
|
} |
1779
|
|
|
|
|
|
|
|
1780
|
0
|
|
|
|
|
|
my $os = lc $osname; |
1781
|
|
|
|
|
|
|
|
1782
|
0
|
|
|
|
|
|
my %tvars; |
1783
|
0
|
|
|
|
|
|
$tvars{osnames} = \@oses; |
1784
|
0
|
|
|
|
|
|
$tvars{template} = 'leaderos'; |
1785
|
0
|
|
|
|
|
|
$tvars{osname} = $self->{parent}->osname($osname); |
1786
|
0
|
|
|
|
|
|
$tvars{leaders} = \@leaders; |
1787
|
0
|
|
|
|
|
|
$tvars{headers} = { col1 => $post2, col2 => $post3, title => "$tvars{osname} Leaderboard ($titles{$type})" }; |
1788
|
0
|
0
|
|
|
|
|
$tvars{links}{this} = $type eq 'this' ? '' : "leaders-$os-this.html"; |
1789
|
0
|
0
|
|
|
|
|
$tvars{links}{that} = $type eq 'that' ? '' : "leaders-$os-that.html"; |
1790
|
0
|
0
|
|
|
|
|
$tvars{links}{all} = $type eq 'all' ? '' : "leaders-$os-all.html"; |
1791
|
0
|
|
|
|
|
|
$self->{parent}->_log("1.leaders/leaders-$os-$type"); |
1792
|
|
|
|
|
|
|
|
1793
|
0
|
|
|
|
|
|
$self->_writepage("leaders/leaders-$os-$type",\%tvars); |
1794
|
|
|
|
|
|
|
} |
1795
|
|
|
|
|
|
|
} |
1796
|
|
|
|
|
|
|
|
1797
|
0
|
|
|
|
|
|
$self->{parent}->_log("building leader board"); |
1798
|
0
|
|
|
|
|
|
my (%tvars,%stats,%testers) = (); |
1799
|
|
|
|
|
|
|
|
1800
|
0
|
|
|
|
|
|
$tvars{osnames} = \@oses; |
1801
|
0
|
|
|
|
|
|
for my $post ($post0, $post1, $post2, $post3) { |
1802
|
0
|
|
|
|
|
|
for my $os (keys %{$data->{$post}}) { |
|
0
|
|
|
|
|
|
|
1803
|
0
|
0
|
|
|
|
|
next unless($os); |
1804
|
0
|
|
|
|
|
|
for my $tester (keys %{$data->{$post}{$os}}) { |
|
0
|
|
|
|
|
|
|
1805
|
0
|
|
|
|
|
|
$testers{$tester} += $data->{$post}{$os}{$tester}; |
1806
|
|
|
|
|
|
|
} |
1807
|
|
|
|
|
|
|
} |
1808
|
|
|
|
|
|
|
} |
1809
|
|
|
|
|
|
|
|
1810
|
0
|
|
|
|
|
|
my $count = 1; |
1811
|
0
|
0
|
|
|
|
|
for my $tester (sort {$testers{$b} <=> $testers{$a} || $a cmp $b} keys %testers) { |
|
0
|
|
|
|
|
|
|
1812
|
0
|
|
|
|
|
|
push @{$tvars{STATS}}, [$count++, $testers{$tester}, $tester]; |
|
0
|
|
|
|
|
|
|
1813
|
|
|
|
|
|
|
} |
1814
|
|
|
|
|
|
|
|
1815
|
0
|
|
|
|
|
|
$count--; |
1816
|
|
|
|
|
|
|
|
1817
|
0
|
|
|
|
|
|
$self->{parent}->tester_loader(); |
1818
|
|
|
|
|
|
|
|
1819
|
0
|
|
|
|
|
|
$self->{parent}->_log("Unknown Addresses: ".($count-$self->{parent}->known_t)); |
1820
|
0
|
|
|
|
|
|
$self->{parent}->_log("Known Addresses: ".($self->{parent}->known_s)); |
1821
|
0
|
|
|
|
|
|
$self->{parent}->_log("Listed Addresses: ".($self->{parent}->known_s + $count - $self->{parent}->known_t)); |
1822
|
0
|
|
|
|
|
|
$self->{parent}->_log("Unknown Testers: ".($count-$self->{parent}->known_t)); |
1823
|
0
|
|
|
|
|
|
$self->{parent}->_log("Known Testers: ".($self->{parent}->known_t)); |
1824
|
0
|
|
|
|
|
|
$self->{parent}->_log("Listed Testers: ".($count)); |
1825
|
|
|
|
|
|
|
|
1826
|
0
|
|
|
|
|
|
push @{$tvars{COUNTS}}, |
1827
|
|
|
|
|
|
|
($count-$self->{parent}->known_t), |
1828
|
|
|
|
|
|
|
$self->{parent}->known_s, |
1829
|
|
|
|
|
|
|
($self->{parent}->known_s + $count - $self->{parent}->known_t), |
1830
|
|
|
|
|
|
|
($count - $self->{parent}->known_t), |
1831
|
|
|
|
|
|
|
$self->{parent}->known_t, |
1832
|
0
|
|
|
|
|
|
$count; |
1833
|
|
|
|
|
|
|
|
1834
|
0
|
|
|
|
|
|
$self->_writepage('testers',\%tvars); |
1835
|
|
|
|
|
|
|
} |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
sub _build_monthly_stats_files { |
1838
|
0
|
|
|
0
|
|
|
my $self = shift; |
1839
|
0
|
|
|
|
|
|
my %tvars; |
1840
|
|
|
|
|
|
|
|
1841
|
0
|
|
|
|
|
|
my $directory = $self->{parent}->directory; |
1842
|
0
|
|
|
|
|
|
my $results = "$directory/stats"; |
1843
|
0
|
|
|
|
|
|
mkpath($results); |
1844
|
|
|
|
|
|
|
|
1845
|
0
|
|
|
|
|
|
$self->{parent}->_log("building monthly stats for graphs - 1,3,pcent1"); |
1846
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
#print "DATE,UPLOADS,REPORTS,NA,PASS,FAIL,UNKNOWN\n"; |
1848
|
0
|
|
|
|
|
|
my $fh1 = IO::File->new(">$results/stats1.txt"); |
1849
|
0
|
|
|
|
|
|
print $fh1 "#DATE,UPLOADS,REPORTS,PASS,FAIL\n"; |
1850
|
|
|
|
|
|
|
|
1851
|
0
|
|
|
|
|
|
my $fh2 = IO::File->new(">$results/pcent1.txt"); |
1852
|
0
|
|
|
|
|
|
print $fh2 "#DATE,FAIL,OTHER,PASS\n"; |
1853
|
|
|
|
|
|
|
|
1854
|
0
|
|
|
|
|
|
my $fh3 = IO::File->new(">$results/stats3.txt"); |
1855
|
0
|
|
|
|
|
|
print $fh3 "#DATE,FAIL,NA,UNKNOWN\n"; |
1856
|
|
|
|
|
|
|
|
1857
|
0
|
|
|
|
|
|
for my $date (sort keys %{$self->{stats}}) { |
|
0
|
|
|
|
|
|
|
1858
|
0
|
0
|
|
|
|
|
next if($date > $self->{dates}{THISMONTH}); |
1859
|
|
|
|
|
|
|
|
1860
|
0
|
|
0
|
|
|
|
my $uploads = ($self->{pause}{$date} || 0); |
1861
|
0
|
|
0
|
|
|
|
my $reports = ($self->{stats}{$date}{reports} || 0); |
1862
|
0
|
|
0
|
|
|
|
my $passes = ($self->{stats}{$date}{state}{pass} || 0); |
1863
|
0
|
|
0
|
|
|
|
my $fails = ($self->{stats}{$date}{state}{fail} || 0); |
1864
|
0
|
|
|
|
|
|
my $others = $reports - $passes - $fails; |
1865
|
|
|
|
|
|
|
|
1866
|
0
|
|
|
|
|
|
my @fields = ( |
1867
|
|
|
|
|
|
|
$date, $uploads, $reports, $passes, $fails |
1868
|
|
|
|
|
|
|
); |
1869
|
|
|
|
|
|
|
|
1870
|
0
|
0
|
|
|
|
|
my @pcent = ( |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
$date, |
1872
|
|
|
|
|
|
|
($reports > 0 ? int($fails / $reports * 100) : 0), |
1873
|
|
|
|
|
|
|
($reports > 0 ? int($others / $reports * 100) : 0), |
1874
|
|
|
|
|
|
|
($reports > 0 ? int($passes / $reports * 100) : 0) |
1875
|
|
|
|
|
|
|
); |
1876
|
|
|
|
|
|
|
|
1877
|
0
|
|
|
|
|
|
unshift @{$tvars{STATS}}, |
1878
|
|
|
|
|
|
|
[ @fields, |
1879
|
|
|
|
|
|
|
$self->{stats}{$date}{state}{na}, |
1880
|
0
|
|
|
|
|
|
$self->{stats}{$date}{state}{unknown}]; |
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
# graphs don't include current month |
1883
|
0
|
0
|
|
|
|
|
next if($date > $self->{dates}{THISMONTH}-1); |
1884
|
|
|
|
|
|
|
|
1885
|
0
|
|
|
|
|
|
my $content = sprintf "%d,%d,%d,%d,%d\n", @fields; |
1886
|
0
|
|
|
|
|
|
print $fh1 $content; |
1887
|
|
|
|
|
|
|
|
1888
|
0
|
|
|
|
|
|
$content = sprintf "%d,%d,%d,%d\n", @pcent; |
1889
|
0
|
|
|
|
|
|
print $fh2 $content; |
1890
|
|
|
|
|
|
|
|
1891
|
|
|
|
|
|
|
$content = sprintf "%d,%d,%d,%d\n", |
1892
|
|
|
|
|
|
|
$date, |
1893
|
|
|
|
|
|
|
($self->{stats}{$date}{state}{fail} || 0), |
1894
|
|
|
|
|
|
|
($self->{stats}{$date}{state}{na} || 0), |
1895
|
0
|
|
0
|
|
|
|
($self->{stats}{$date}{state}{unknown} || 0); |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1896
|
0
|
|
|
|
|
|
print $fh3 $content; |
1897
|
|
|
|
|
|
|
} |
1898
|
0
|
|
|
|
|
|
$fh1->close; |
1899
|
0
|
|
|
|
|
|
$fh2->close; |
1900
|
0
|
|
|
|
|
|
$fh3->close; |
1901
|
|
|
|
|
|
|
|
1902
|
0
|
|
|
|
|
|
$self->_writepage('mreports',\%tvars); |
1903
|
|
|
|
|
|
|
|
1904
|
0
|
|
|
|
|
|
$self->{parent}->_log("building monthly stats for graphs - 2"); |
1905
|
|
|
|
|
|
|
|
1906
|
|
|
|
|
|
|
#print "DATE,TESTERS,PLATFORMS,PERLS\n"; |
1907
|
0
|
|
|
|
|
|
$fh2 = IO::File->new(">$results/stats2.txt"); |
1908
|
0
|
|
|
|
|
|
print $fh2 "#DATE,TESTERS,PLATFORMS,PERLS\n"; |
1909
|
|
|
|
|
|
|
|
1910
|
0
|
|
|
|
|
|
for my $date (sort keys %{$self->{stats}}) { |
|
0
|
|
|
|
|
|
|
1911
|
0
|
0
|
|
|
|
|
next if($date > $self->{dates}{THISMONTH}-1); |
1912
|
|
|
|
|
|
|
printf $fh2 "%d,%d,%d,%d\n", |
1913
|
|
|
|
|
|
|
$date, |
1914
|
|
|
|
|
|
|
($self->{monthly}{$date}{tester} || 0), |
1915
|
|
|
|
|
|
|
($self->{monthly}{$date}{platform} || 0), |
1916
|
0
|
|
0
|
|
|
|
($self->{monthly}{$date}{perl} || 0); |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1917
|
|
|
|
|
|
|
} |
1918
|
0
|
|
|
|
|
|
$fh2->close; |
1919
|
|
|
|
|
|
|
|
1920
|
0
|
|
|
|
|
|
$self->{parent}->_log("building monthly stats for graphs - 4"); |
1921
|
|
|
|
|
|
|
|
1922
|
|
|
|
|
|
|
#print "DATE,ALL,FIRST,LAST\n"; |
1923
|
0
|
|
|
|
|
|
$fh1 = IO::File->new(">$results/stats4.txt"); |
1924
|
0
|
|
|
|
|
|
print $fh1 "#DATE,ALL,FIRST,LAST\n"; |
1925
|
|
|
|
|
|
|
|
1926
|
0
|
|
|
|
|
|
for my $date (sort keys %{ $self->{stats} }) { |
|
0
|
|
|
|
|
|
|
1927
|
0
|
0
|
|
|
|
|
next if($date > $self->{dates}{THISMONTH}-1); |
1928
|
|
|
|
|
|
|
|
1929
|
0
|
0
|
|
|
|
|
if(defined $self->{counts}{$date}) { |
1930
|
0
|
|
|
|
|
|
$self->{counts}{$date}{all} = scalar(keys %{$self->{counts}{$date}{testers}}); |
|
0
|
|
|
|
|
|
|
1931
|
|
|
|
|
|
|
} |
1932
|
0
|
|
0
|
|
|
|
$self->{counts}{$date}{all} ||= 0; |
1933
|
0
|
|
0
|
|
|
|
$self->{counts}{$date}{first} ||= 0; |
1934
|
0
|
|
0
|
|
|
|
$self->{counts}{$date}{last} ||= 0; |
1935
|
0
|
0
|
|
|
|
|
$self->{counts}{$date}{last} = '' if($date > $self->{dates}{LASTMONTH}); |
1936
|
|
|
|
|
|
|
|
1937
|
|
|
|
|
|
|
printf $fh1 "%d,%s,%s,%s\n", |
1938
|
|
|
|
|
|
|
$date, |
1939
|
|
|
|
|
|
|
$self->{counts}{$date}{all}, |
1940
|
|
|
|
|
|
|
$self->{counts}{$date}{first}, |
1941
|
0
|
|
|
|
|
|
$self->{counts}{$date}{last}; |
1942
|
|
|
|
|
|
|
} |
1943
|
0
|
|
|
|
|
|
$fh1->close; |
1944
|
|
|
|
|
|
|
} |
1945
|
|
|
|
|
|
|
|
1946
|
|
|
|
|
|
|
sub _build_failure_rates { |
1947
|
0
|
|
|
0
|
|
|
my $self = shift; |
1948
|
0
|
|
|
|
|
|
my (%tvars,%dists); |
1949
|
|
|
|
|
|
|
|
1950
|
0
|
|
|
|
|
|
$self->{parent}->_log("building failure rates"); |
1951
|
|
|
|
|
|
|
|
1952
|
0
|
|
|
|
|
|
my $query = |
1953
|
|
|
|
|
|
|
'SELECT x.dist,x.version,u.released FROM ixlatest AS x '. |
1954
|
|
|
|
|
|
|
'INNER JOIN uploads AS u ON u.dist=x.dist AND u.version=x.version '. |
1955
|
|
|
|
|
|
|
"WHERE u.type != 'backpan'"; |
1956
|
0
|
|
|
|
|
|
my $next = $self->{parent}->{CPANSTATS}->iterator('hash',$query); |
1957
|
0
|
|
|
|
|
|
while(my $row = $next->()) { |
1958
|
0
|
|
|
|
|
|
$dists{$row->{dist}}{$row->{version}} = $row->{released}; |
1959
|
|
|
|
|
|
|
} |
1960
|
|
|
|
|
|
|
|
1961
|
0
|
|
|
|
|
|
$self->{parent}->_log("selecting failure rates"); |
1962
|
|
|
|
|
|
|
|
1963
|
|
|
|
|
|
|
# select worst failure rates - latest version, and ignoring backpan only. |
1964
|
0
|
|
|
|
|
|
my %worst; |
1965
|
0
|
|
|
|
|
|
for my $dist (keys %{ $self->{fails} }) { |
|
0
|
|
|
|
|
|
|
1966
|
0
|
0
|
|
|
|
|
next unless($dists{$dist}); |
1967
|
0
|
|
|
|
|
|
my ($version) = sort {$dists{$dist}{$b} <=> $dists{$dist}{$a}} keys %{$dists{$dist}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1968
|
|
|
|
|
|
|
|
1969
|
0
|
|
|
|
|
|
$worst{"$dist-$version"} = $self->{fails}->{$dist}{$version}; |
1970
|
0
|
|
|
|
|
|
$worst{"$dist-$version"}->{dist} = $dist; |
1971
|
|
|
|
|
|
|
$worst{"$dist-$version"}->{pcent} = $self->{fails}{$dist}{$version}{fail} |
1972
|
0
|
0
|
|
|
|
|
? int(($self->{fails}{$dist}{$version}{fail}/$self->{fails}{$dist}{$version}{total})*10000)/100 |
1973
|
|
|
|
|
|
|
: 0.00; |
1974
|
0
|
|
0
|
|
|
|
$worst{"$dist-$version"}->{pass} ||= 0; |
1975
|
0
|
|
0
|
|
|
|
$worst{"$dist-$version"}->{fail} ||= 0; |
1976
|
|
|
|
|
|
|
|
1977
|
0
|
|
|
|
|
|
my @post = localtime($dists{$dist}{$version}); |
1978
|
0
|
|
|
|
|
|
$worst{"$dist-$version"}->{post} = sprintf "%04d%02d", $post[5]+1900, $post[4]+1; |
1979
|
|
|
|
|
|
|
} |
1980
|
|
|
|
|
|
|
|
1981
|
0
|
|
|
|
|
|
$self->{parent}->_log("worst = " . scalar(keys %worst) . " entries"); |
1982
|
0
|
|
|
|
|
|
$self->{parent}->_log("building failure counts"); |
1983
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
# calculate worst failure rates - by failure count |
1985
|
0
|
|
|
|
|
|
my $count = 1; |
1986
|
0
|
0
|
|
|
|
|
for my $dist (sort {$worst{$b}->{fail} <=> $worst{$a}->{fail} || $worst{$b}->{pcent} <=> $worst{$a}->{pcent}} keys %worst) { |
|
0
|
|
|
|
|
|
|
1987
|
0
|
0
|
|
|
|
|
last unless($worst{$dist}->{fail}); |
1988
|
0
|
|
|
|
|
|
my $pcent = sprintf "%3.2f%%", $worst{$dist}->{pcent}; |
1989
|
0
|
|
|
|
|
|
push @{$tvars{WORST}}, [$count++, $worst{$dist}->{fail}, $dist, $worst{$dist}->{post}, $worst{$dist}->{pass}, $worst{$dist}->{total}, $pcent, $worst{$dist}->{dist}]; |
|
0
|
|
|
|
|
|
|
1990
|
0
|
0
|
|
|
|
|
last if($count > 100); |
1991
|
|
|
|
|
|
|
} |
1992
|
|
|
|
|
|
|
|
1993
|
0
|
|
|
|
|
|
$self->_writepage('wdists',\%tvars); |
1994
|
0
|
|
|
|
|
|
undef %tvars; |
1995
|
|
|
|
|
|
|
|
1996
|
0
|
|
|
|
|
|
$self->{parent}->_log("building failure pecentages"); |
1997
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
# calculate worst failure rates - by percentage |
1999
|
0
|
|
|
|
|
|
$count = 1; |
2000
|
0
|
0
|
|
|
|
|
for my $dist (sort {$worst{$b}->{pcent} <=> $worst{$a}->{pcent} || $worst{$b}->{fail} <=> $worst{$a}->{fail}} keys %worst) { |
|
0
|
|
|
|
|
|
|
2001
|
0
|
0
|
|
|
|
|
last unless($worst{$dist}->{fail}); |
2002
|
0
|
|
|
|
|
|
my $pcent = sprintf "%3.2f%%", $worst{$dist}->{pcent}; |
2003
|
0
|
|
|
|
|
|
push @{$tvars{WORST}}, [$count++, $worst{$dist}->{fail}, $dist, $worst{$dist}->{post}, $worst{$dist}->{pass}, $worst{$dist}->{total}, $pcent, $worst{$dist}->{dist}]; |
|
0
|
|
|
|
|
|
|
2004
|
0
|
0
|
|
|
|
|
last if($count > 100); |
2005
|
|
|
|
|
|
|
} |
2006
|
|
|
|
|
|
|
|
2007
|
0
|
|
|
|
|
|
$self->_writepage('wpcent',\%tvars); |
2008
|
0
|
|
|
|
|
|
undef %tvars; |
2009
|
|
|
|
|
|
|
|
2010
|
0
|
|
|
|
|
|
$self->{parent}->_log("done building failure rates"); |
2011
|
|
|
|
|
|
|
|
2012
|
|
|
|
|
|
|
# now we do as above but for the last 6 months |
2013
|
|
|
|
|
|
|
|
2014
|
0
|
|
|
|
|
|
my @recent = localtime(time() - 15778463); # 6 months ago |
2015
|
0
|
|
|
|
|
|
my $recent = sprintf "%04d%02d", $recent[5]+1900, $recent[4]+1; |
2016
|
|
|
|
|
|
|
|
2017
|
0
|
|
|
|
|
|
for my $dist (keys %worst) { |
2018
|
0
|
0
|
|
|
|
|
next if($worst{$dist}->{post} ge $recent); |
2019
|
0
|
|
|
|
|
|
delete $worst{$dist}; |
2020
|
|
|
|
|
|
|
} |
2021
|
|
|
|
|
|
|
|
2022
|
|
|
|
|
|
|
# calculate worst failure rates - by failure count |
2023
|
0
|
|
|
|
|
|
$count = 1; |
2024
|
0
|
0
|
|
|
|
|
for my $dist (sort {$worst{$b}->{fail} <=> $worst{$a}->{fail} || $worst{$b}->{pcent} <=> $worst{$a}->{pcent}} keys %worst) { |
|
0
|
|
|
|
|
|
|
2025
|
0
|
0
|
|
|
|
|
last unless($worst{$dist}->{fail}); |
2026
|
0
|
|
|
|
|
|
my $pcent = sprintf "%3.2f%%", $worst{$dist}->{pcent}; |
2027
|
0
|
|
|
|
|
|
push @{$tvars{WORST}}, [$count++, $worst{$dist}->{fail}, $dist, $worst{$dist}->{post}, $worst{$dist}->{pass}, $worst{$dist}->{total}, $pcent, $worst{$dist}->{dist}]; |
|
0
|
|
|
|
|
|
|
2028
|
0
|
0
|
|
|
|
|
last if($count > 100); |
2029
|
|
|
|
|
|
|
} |
2030
|
|
|
|
|
|
|
|
2031
|
0
|
|
|
|
|
|
$self->_writepage('wdists-recent',\%tvars); |
2032
|
0
|
|
|
|
|
|
undef %tvars; |
2033
|
|
|
|
|
|
|
|
2034
|
0
|
|
|
|
|
|
$self->{parent}->_log("building failure pecentages"); |
2035
|
|
|
|
|
|
|
|
2036
|
|
|
|
|
|
|
# calculate worst failure rates - by percentage |
2037
|
0
|
|
|
|
|
|
$count = 1; |
2038
|
0
|
0
|
|
|
|
|
for my $dist (sort {$worst{$b}->{pcent} <=> $worst{$a}->{pcent} || $worst{$b}->{fail} <=> $worst{$a}->{fail}} keys %worst) { |
|
0
|
|
|
|
|
|
|
2039
|
0
|
0
|
|
|
|
|
last unless($worst{$dist}->{fail}); |
2040
|
0
|
|
|
|
|
|
my $pcent = sprintf "%3.2f%%", $worst{$dist}->{pcent}; |
2041
|
0
|
|
|
|
|
|
push @{$tvars{WORST}}, [$count++, $worst{$dist}->{fail}, $dist, $worst{$dist}->{post}, $worst{$dist}->{pass}, $worst{$dist}->{total}, $pcent, $worst{$dist}->{dist}]; |
|
0
|
|
|
|
|
|
|
2042
|
0
|
0
|
|
|
|
|
last if($count > 100); |
2043
|
|
|
|
|
|
|
} |
2044
|
|
|
|
|
|
|
|
2045
|
0
|
|
|
|
|
|
$self->_writepage('wpcent-recent',\%tvars); |
2046
|
|
|
|
|
|
|
} |
2047
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
sub _build_performance_stats { |
2049
|
0
|
|
|
0
|
|
|
my $self = shift; |
2050
|
|
|
|
|
|
|
|
2051
|
0
|
|
|
|
|
|
my $directory = $self->{parent}->directory; |
2052
|
0
|
|
|
|
|
|
my $results = "$directory/stats"; |
2053
|
0
|
|
|
|
|
|
mkpath($results); |
2054
|
|
|
|
|
|
|
|
2055
|
0
|
|
|
|
|
|
$self->{parent}->_log("building peformance stats for graphs"); |
2056
|
|
|
|
|
|
|
|
2057
|
0
|
|
|
|
|
|
my $fh = IO::File->new(">$results/build1.txt"); |
2058
|
0
|
|
|
|
|
|
print $fh "#DATE,REQUESTS,PAGES,REPORTS\n"; |
2059
|
|
|
|
|
|
|
|
2060
|
0
|
|
|
|
|
|
my $count = scalar(keys %{$self->{build}}); |
|
0
|
|
|
|
|
|
|
2061
|
0
|
|
0
|
|
|
|
my $limit = $self->{parent}->build_history || 90; |
2062
|
0
|
|
|
|
|
|
my $diff = $count - $limit; |
2063
|
|
|
|
|
|
|
|
2064
|
0
|
|
|
|
|
|
for my $date (sort {$a <=> $b} keys %{$self->{build}}) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2065
|
0
|
0
|
|
|
|
|
next if(--$diff > 0); |
2066
|
|
|
|
|
|
|
|
2067
|
|
|
|
|
|
|
#$self->{parent}->_log("build_stats: date=$date, old=$self->{build}{$date}->{old}"); |
2068
|
0
|
0
|
|
|
|
|
next if($self->{build}{$date}->{old} == 2); # ignore todays tally |
2069
|
|
|
|
|
|
|
#next if($date > $self->{dates}{THISMONTH}-1); |
2070
|
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
printf $fh "%d,%d,%d,%d\n", |
2072
|
|
|
|
|
|
|
$date, |
2073
|
|
|
|
|
|
|
($self->{build}{$date}{webtotal} || 0), |
2074
|
|
|
|
|
|
|
($self->{build}{$date}{webunique} || 0), |
2075
|
0
|
|
0
|
|
|
|
($self->{build}{$date}{reports} || 0); |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
2076
|
|
|
|
|
|
|
} |
2077
|
0
|
|
|
|
|
|
$fh->close; |
2078
|
|
|
|
|
|
|
} |
2079
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
sub _build_sizes { |
2081
|
0
|
|
|
0
|
|
|
my $self = shift; |
2082
|
0
|
|
|
|
|
|
my $du = 'du -h --max-depth=0'; |
2083
|
|
|
|
|
|
|
|
2084
|
0
|
|
|
|
|
|
for my $dir (qw( dir_cpan dir_backpan dir_reports )) { |
2085
|
0
|
|
|
|
|
|
my $path = $self->{parent}->$dir(); |
2086
|
0
|
|
|
|
|
|
my $res =`$du $path`; |
2087
|
0
|
|
0
|
|
|
|
$res ||= ''; |
2088
|
0
|
0
|
|
|
|
|
$res =~ s/\s.*$//s if($res); |
2089
|
0
|
|
|
|
|
|
$self->{sizes}{$dir} = $res; |
2090
|
0
|
|
|
|
|
|
$self->{parent}->_log(".. size for $dir ($path) = $res"); |
2091
|
|
|
|
|
|
|
} |
2092
|
|
|
|
|
|
|
} |
2093
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
=item * _writepage |
2095
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
Creates a single HTML page. |
2097
|
|
|
|
|
|
|
|
2098
|
|
|
|
|
|
|
=cut |
2099
|
|
|
|
|
|
|
|
2100
|
|
|
|
|
|
|
sub _writepage { |
2101
|
0
|
|
|
0
|
|
|
my ($self,$page,$vars) = @_; |
2102
|
0
|
|
|
|
|
|
my $directory = $self->{parent}->directory; |
2103
|
0
|
|
|
|
|
|
my $templates = $self->{parent}->templates; |
2104
|
|
|
|
|
|
|
|
2105
|
|
|
|
|
|
|
#$self->{parent}->_log("_writepage: page=$page"); |
2106
|
|
|
|
|
|
|
|
2107
|
0
|
|
0
|
|
|
|
my $extension = $vars->{extension} || 'html'; |
2108
|
0
|
|
0
|
|
|
|
my $template = $vars->{template} || $page; |
2109
|
0
|
|
0
|
|
|
|
my $tlayout = $vars->{layout} || 'layout'; |
2110
|
0
|
|
|
|
|
|
my $layout = "$tlayout.$extension"; |
2111
|
0
|
|
|
|
|
|
my $source = "$template.$extension"; |
2112
|
0
|
|
|
|
|
|
my $target = "$directory/$page.$extension"; |
2113
|
|
|
|
|
|
|
|
2114
|
|
|
|
|
|
|
#$self->{parent}->_log("_writepage: layout=$layout, source=$source, target=$target"); |
2115
|
|
|
|
|
|
|
|
2116
|
0
|
|
|
|
|
|
mkdir(dirname($target)); |
2117
|
|
|
|
|
|
|
|
2118
|
0
|
|
|
|
|
|
$vars->{SOURCE} = $source; |
2119
|
0
|
|
|
|
|
|
$vars->{VERSION} = $VERSION; |
2120
|
0
|
|
|
|
|
|
$vars->{copyright} = $self->{parent}->copyright; |
2121
|
0
|
|
|
|
|
|
$vars->{$_} = $self->{dates}{$_} for(keys %{ $self->{dates} }); |
|
0
|
|
|
|
|
|
|
2122
|
|
|
|
|
|
|
|
2123
|
|
|
|
|
|
|
#if($page =~ /(statscpan|interest)/) { |
2124
|
|
|
|
|
|
|
# $self->{parent}->_log("$page:" . Dumper($vars)); |
2125
|
|
|
|
|
|
|
#} |
2126
|
|
|
|
|
|
|
|
2127
|
0
|
|
|
|
|
|
my %config = ( # provide config info |
2128
|
|
|
|
|
|
|
RELATIVE => 1, |
2129
|
|
|
|
|
|
|
ABSOLUTE => 1, |
2130
|
|
|
|
|
|
|
INCLUDE_PATH => $templates, |
2131
|
|
|
|
|
|
|
INTERPOLATE => 0, |
2132
|
|
|
|
|
|
|
POST_CHOMP => 1, |
2133
|
|
|
|
|
|
|
TRIM => 1, |
2134
|
|
|
|
|
|
|
); |
2135
|
|
|
|
|
|
|
|
2136
|
0
|
|
|
|
|
|
my $parser = Template->new(\%config); # initialise parser |
2137
|
0
|
0
|
|
|
|
|
$parser->process($layout,$vars,$target) # parse the template |
2138
|
|
|
|
|
|
|
or die $parser->error() . "\n"; |
2139
|
|
|
|
|
|
|
} |
2140
|
|
|
|
|
|
|
|
2141
|
|
|
|
|
|
|
# Provides the ordinal for dates. |
2142
|
|
|
|
|
|
|
|
2143
|
|
|
|
|
|
|
sub _ext { |
2144
|
0
|
|
|
0
|
|
|
my $num = shift; |
2145
|
0
|
0
|
0
|
|
|
|
return 'st' if($num == 1 || $num == 21 || $num == 31); |
|
|
|
0
|
|
|
|
|
2146
|
0
|
0
|
0
|
|
|
|
return 'nd' if($num == 2 || $num == 22); |
2147
|
0
|
0
|
0
|
|
|
|
return 'rd' if($num == 3 || $num == 23); |
2148
|
0
|
|
|
|
|
|
return 'th'; |
2149
|
|
|
|
|
|
|
} |
2150
|
|
|
|
|
|
|
|
2151
|
|
|
|
|
|
|
sub _parsedate { |
2152
|
0
|
|
|
0
|
|
|
my $time = shift; |
2153
|
0
|
|
|
|
|
|
my @time = localtime($time); |
2154
|
0
|
|
|
|
|
|
return sprintf "%04d%02d", $time[5]+1900,$time[4]+1; |
2155
|
|
|
|
|
|
|
} |
2156
|
|
|
|
|
|
|
|
2157
|
|
|
|
|
|
|
sub _count_mailrc { |
2158
|
0
|
|
|
0
|
|
|
my $self = shift; |
2159
|
0
|
|
|
|
|
|
my $count = 0; |
2160
|
0
|
|
|
|
|
|
my $mailrc = $self->{parent}->mailrc(); |
2161
|
|
|
|
|
|
|
|
2162
|
0
|
0
|
|
|
|
|
my $fh = IO::File->new($mailrc,'r') or die "Cannot read file [$mailrc]: $!\n"; |
2163
|
0
|
|
|
|
|
|
while(<$fh>) { |
2164
|
0
|
0
|
|
|
|
|
next unless(/^alias\s*(\w+)\s+"([\s\w]+)\s+<[^>]+>"/); |
2165
|
0
|
|
|
|
|
|
$self->{alias}{$1} = $2; |
2166
|
0
|
|
|
|
|
|
$count++; |
2167
|
|
|
|
|
|
|
} |
2168
|
0
|
|
|
|
|
|
$fh->close; |
2169
|
|
|
|
|
|
|
|
2170
|
0
|
|
|
|
|
|
return $count; |
2171
|
|
|
|
|
|
|
} |
2172
|
|
|
|
|
|
|
|
2173
|
|
|
|
|
|
|
q("Will code for Guinness!"); |
2174
|
|
|
|
|
|
|
|
2175
|
|
|
|
|
|
|
__END__ |
2176
|
|
|
|
|
|
|
|
2177
|
|
|
|
|
|
|
=back |
2178
|
|
|
|
|
|
|
|
2179
|
|
|
|
|
|
|
=head1 CPAN TESTERS FUND |
2180
|
|
|
|
|
|
|
|
2181
|
|
|
|
|
|
|
CPAN Testers wouldn't exist without the help and support of the Perl |
2182
|
|
|
|
|
|
|
community. However, since 2008 CPAN Testers has grown far beyond the |
2183
|
|
|
|
|
|
|
expectations of it's original creators. As a consequence it now requires |
2184
|
|
|
|
|
|
|
considerable funding to help support the infrastructure. |
2185
|
|
|
|
|
|
|
|
2186
|
|
|
|
|
|
|
In early 2012 the Enlightened Perl Organisation very kindly set-up a |
2187
|
|
|
|
|
|
|
CPAN Testers Fund within their donatation structure, to help the project |
2188
|
|
|
|
|
|
|
cover the costs of servers and services. |
2189
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
If you would like to donate to the CPAN Testers Fund, please follow the link |
2191
|
|
|
|
|
|
|
below to the Enlightened Perl Organisation's donation site. |
2192
|
|
|
|
|
|
|
|
2193
|
|
|
|
|
|
|
F<https://members.enlightenedperl.org/drupal/donate-cpan-testers> |
2194
|
|
|
|
|
|
|
|
2195
|
|
|
|
|
|
|
If your company would like to support us, you can donate financially via the |
2196
|
|
|
|
|
|
|
fund link above, or if you have servers or services that we might use, please |
2197
|
|
|
|
|
|
|
send an email to admin@cpantesters.org with details. |
2198
|
|
|
|
|
|
|
|
2199
|
|
|
|
|
|
|
Our full list of current sponsors can be found at our I <3 CPAN Testers site. |
2200
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
F<http://iheart.cpantesters.org> |
2202
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
=head1 BUGS, PATCHES & FIXES |
2204
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
There are no known bugs at the time of this release. However, if you spot a |
2206
|
|
|
|
|
|
|
bug or are experiencing difficulties, that is not explained within the POD |
2207
|
|
|
|
|
|
|
documentation, please send bug reports and patches to the RT Queue (see below). |
2208
|
|
|
|
|
|
|
|
2209
|
|
|
|
|
|
|
Fixes are dependent upon their severity and my availability. Should a fix not |
2210
|
|
|
|
|
|
|
be forthcoming, please feel free to (politely) remind me. |
2211
|
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
RT Queue - |
2213
|
|
|
|
|
|
|
http://rt.cpan.org/Public/Dist/Display.html?Name=CPAN-Testers-WWW-Statistics |
2214
|
|
|
|
|
|
|
|
2215
|
|
|
|
|
|
|
=head1 SEE ALSO |
2216
|
|
|
|
|
|
|
|
2217
|
|
|
|
|
|
|
L<CPAN::Testers::Data::Generator>, |
2218
|
|
|
|
|
|
|
L<CPAN::Testers::WWW::Reports> |
2219
|
|
|
|
|
|
|
|
2220
|
|
|
|
|
|
|
F<http://www.cpantesters.org/>, |
2221
|
|
|
|
|
|
|
F<http://stats.cpantesters.org/>, |
2222
|
|
|
|
|
|
|
F<http://wiki.cpantesters.org/> |
2223
|
|
|
|
|
|
|
|
2224
|
|
|
|
|
|
|
=head1 AUTHOR |
2225
|
|
|
|
|
|
|
|
2226
|
|
|
|
|
|
|
Barbie, <barbie@cpan.org> |
2227
|
|
|
|
|
|
|
for Miss Barbell Productions <http://www.missbarbell.co.uk>. |
2228
|
|
|
|
|
|
|
|
2229
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
2230
|
|
|
|
|
|
|
|
2231
|
|
|
|
|
|
|
Copyright (C) 2005-2017 Barbie for Miss Barbell Productions. |
2232
|
|
|
|
|
|
|
|
2233
|
|
|
|
|
|
|
This distribution is free software; you can redistribute it and/or |
2234
|
|
|
|
|
|
|
modify it under the Artistic Licence v2. |
2235
|
|
|
|
|
|
|
|
2236
|
|
|
|
|
|
|
=cut |