| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Module::Advisor; |
|
2
|
1
|
|
|
1
|
|
23608
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
32
|
|
|
3
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
23
|
|
|
4
|
1
|
|
|
1
|
|
18
|
use 5.008008; |
|
|
1
|
|
|
|
|
7
|
|
|
|
1
|
|
|
|
|
49
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.17'; |
|
6
|
1
|
|
|
1
|
|
901
|
use Module::Metadata; |
|
|
1
|
|
|
|
|
21499
|
|
|
|
1
|
|
|
|
|
39
|
|
|
7
|
1
|
|
|
1
|
|
1703
|
use CPAN::Meta::Requirements; |
|
|
1
|
|
|
|
|
3354
|
|
|
|
1
|
|
|
|
|
24
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
1139
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our @SECURITY = ( |
|
11
|
|
|
|
|
|
|
['Digest' => '< 1.17', 'have a security issue. which could lead to the injection of arbitrary Perl code'], |
|
12
|
|
|
|
|
|
|
['Encode' => '< 2.44', 'heap overflow'], |
|
13
|
|
|
|
|
|
|
['Encode' => '< 2.49', 'memory leaks'], |
|
14
|
|
|
|
|
|
|
); |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our @PERFORMANCE = ( |
|
17
|
|
|
|
|
|
|
['UNIVERSAL::require', '< 0.11', 'is 400% faster'], |
|
18
|
|
|
|
|
|
|
); |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our @BUG = ( |
|
21
|
|
|
|
|
|
|
['Plack' => '< 0.9982', 'sanity check to remove newlines from headers'], |
|
22
|
|
|
|
|
|
|
['Time::Piece' => '< 1.16', 'have timezone related issue'], |
|
23
|
|
|
|
|
|
|
['DBD::SQLite' => '< 1.20', 'a lot of bugs.'], |
|
24
|
|
|
|
|
|
|
['Mouse' => '>= 1.07, < 1.12', 'Memory leaks in trigger'], |
|
25
|
|
|
|
|
|
|
['Text::Xslate' => '< 1.0011', '' bug.'], |
|
26
|
|
|
|
|
|
|
['Text::Xslate' => '< 1.5021', 'segv in "render" recursion call'], |
|
27
|
|
|
|
|
|
|
['Text::Xslate' => '< 1.6001', 'possibly memory leaks on VM stack frames. see https://github.com/xslate/p5-Text-Xslate/issues/71'], |
|
28
|
|
|
|
|
|
|
['Text::Xslate' => '< 2.0005', 'Nested WRAPPER broken https://github.com/xslate/p5-Text-Xslate/issues/79'], |
|
29
|
|
|
|
|
|
|
['Furl' => '< 0.39', 'unexpected eof in reading chunked body. It makes busy loop.'], |
|
30
|
|
|
|
|
|
|
['AnyEvent::MPRPC' => '< 0.15', 'switch to Data::MessagePack::Stream'], |
|
31
|
|
|
|
|
|
|
['Data::MessagePack' => '< 0.46', 'fixed unpacking issue on big-endian system.'], |
|
32
|
|
|
|
|
|
|
['Data::MessagePack' => '< 0.39', 'packing float numbers fails on some cases'], |
|
33
|
|
|
|
|
|
|
['FCGI::Client' => '< 0.06', 'fixed large packet issue'], |
|
34
|
|
|
|
|
|
|
['Starlet' => '< 0.12', 'fix infinite loop when connection is closed while receiving response content'], |
|
35
|
|
|
|
|
|
|
['Starman' => '< 0.2014', '$res->[1] is broken after output (This is actualized with Plack::Middleware::AccessLog::Timed) https://github.com/miyagawa/Starman/pull/31'], |
|
36
|
|
|
|
|
|
|
['Starman' => '< 0.1006', 'Fixed 100% CPU loop when an unexpected EOF happens'], |
|
37
|
|
|
|
|
|
|
['Twiggy' => '< 0.1000', 'busy loop'], |
|
38
|
|
|
|
|
|
|
['Teng', '< 0.14', 'fixed deflate bug.'], |
|
39
|
|
|
|
|
|
|
['DBIx::Skinny', '< 0.0742', 'txn_scope bug fixed'], |
|
40
|
|
|
|
|
|
|
['DBIx::TransactionManager', '< 1.11', 'not execute begin_work at AutoCommit=0.'], |
|
41
|
|
|
|
|
|
|
['HTTP::MobileAgent' => '< 0.36', 'new x-up-devcap-multimedia(StandAloneGPS) support'], |
|
42
|
|
|
|
|
|
|
['HTTP::MobileAgent' => '< 0.35', 'Updated $HTMLVerMap and $GPSModelsRe in DoCoMo.pm'], |
|
43
|
|
|
|
|
|
|
['Encode::JP::Mobile' => '< 0.25', 'resolved FULLWIDTH TILDE issue, etc.'], |
|
44
|
|
|
|
|
|
|
['Template' => '< 2.15', 'uri filter does not works properly https://rt.cpan.org/Public/Bug/Display.html?id=19593'], |
|
45
|
|
|
|
|
|
|
['HTML::FillInForm::Lite' => '< 1.11', 'HTML5 style tags support'], |
|
46
|
|
|
|
|
|
|
['Proc::Daemon' => '< 0.12', 'Init() did not close all filehandles reliably in some cases.'], |
|
47
|
|
|
|
|
|
|
['ExclusiveLock::Guard' => '< 0.04', 'change of the file stat timing (measures under high load)'], |
|
48
|
|
|
|
|
|
|
['autobox', '< 2.78', 'segv in END block https://rt.cpan.org/Ticket/Display.html?id=80400'], |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# Broken in specific versions |
|
51
|
|
|
|
|
|
|
['Amon2::DBI' => '== 0.31', 'transaction management bug'], |
|
52
|
|
|
|
|
|
|
['Math::Random::MT' => '== 1.15', 'rand() took no notice of argument RT #78200'], |
|
53
|
|
|
|
|
|
|
['Module::Install' => '== 1.04', 'Broken, http://weblog.bulknews.net/post/33907905561/do-not-ship-modules-with-module-install-1-04'], |
|
54
|
|
|
|
|
|
|
['Mouse' => '== 1.04', 'Broken, http://d.hatena.ne.jp/gfx/20130208/1360283357'], |
|
55
|
|
|
|
|
|
|
['Plack::Middleware::AxsLog' => '== 0.20', 'Missing \n'], |
|
56
|
|
|
|
|
|
|
); |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
our @XS = ( |
|
59
|
|
|
|
|
|
|
['JSON' => 'JSON::XS'], |
|
60
|
|
|
|
|
|
|
# ['PPI' => 'PPI::XS'], # I think PPI::XS is outdated. |
|
61
|
|
|
|
|
|
|
['Plack' => 'HTTP::Parser::XS'], |
|
62
|
|
|
|
|
|
|
); |
|
63
|
|
|
|
|
|
|
if ($^O eq 'linux') { |
|
64
|
|
|
|
|
|
|
push @XS, ['Filesys::Notify::Simple', 'Linux::Inotify2']; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
our @FEATURE = ( |
|
68
|
|
|
|
|
|
|
['Amon2' => '< 3.29', 'JSON hijacking detection.'], |
|
69
|
|
|
|
|
|
|
['Log::Minimal' => '< 0.10', 'LM_COLOR'], |
|
70
|
|
|
|
|
|
|
['Log::Minimal' => '< 0.08', 'colourful logging'], |
|
71
|
|
|
|
|
|
|
['Log::Minimal' => '< 0.03', 'ddf'], |
|
72
|
|
|
|
|
|
|
['Proclet' => '< 0.12', 'Proclet::Declare'], |
|
73
|
|
|
|
|
|
|
['DBI', '< 1.614' => 'AutoInactiveDestroy'], |
|
74
|
|
|
|
|
|
|
['Module::Install::XSUtil', '< 0.44' => 'PUREPERL_ONLY=1'], |
|
75
|
|
|
|
|
|
|
); |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
our @OPTIONAL_MODULES = ( |
|
78
|
|
|
|
|
|
|
['LWP', 'LWP::Protocol::https', 'Need to support https'], |
|
79
|
|
|
|
|
|
|
); |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# ref. Module::Version |
|
82
|
|
|
|
|
|
|
sub get_version { |
|
83
|
0
|
0
|
|
0
|
0
|
|
my $module = shift or croak 'Must get a module name'; |
|
84
|
0
|
|
|
|
|
|
my $metadata = Module::Metadata->new_from_module($module); |
|
85
|
0
|
0
|
|
|
|
|
$metadata ? $metadata->version : undef; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub debugf { |
|
89
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
90
|
0
|
0
|
|
|
|
|
print "# @_\n" if $self->{verbose}; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub new { |
|
94
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
|
95
|
0
|
0
|
|
|
|
|
my %args = @_==1 ? %{$_[0]} : @_; |
|
|
0
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
|
bless {%args}, $class; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub check { |
|
100
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
|
101
|
0
|
|
|
|
|
|
my $failed = 0; |
|
102
|
0
|
|
|
|
|
|
$failed += $self->check_security(); |
|
103
|
0
|
|
|
|
|
|
$failed += $self->check_performance(); |
|
104
|
0
|
|
|
|
|
|
$failed += $self->check_bugs(); |
|
105
|
0
|
|
|
|
|
|
$failed += $self->check_xs_installed(); |
|
106
|
0
|
|
|
|
|
|
$failed += $self->check_feature(); |
|
107
|
0
|
|
|
|
|
|
return $failed; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub matches_version { |
|
111
|
0
|
|
|
0
|
0
|
|
my($self, $module, $spec, $version) = @_; |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
my $requirements = CPAN::Meta::Requirements->new; |
|
114
|
0
|
|
|
|
|
|
$requirements->add_string_requirement($module, $spec); |
|
115
|
|
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
$requirements->accepts_module($module, $version); |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub _check_issue { |
|
120
|
0
|
|
|
0
|
|
|
my ($self, $patterns, $type_name) = @_; |
|
121
|
0
|
|
|
|
|
|
my $failed = 0; |
|
122
|
0
|
|
|
|
|
|
for my $row (@$patterns) { |
|
123
|
0
|
|
|
|
|
|
my $ver = get_version($row->[0]); |
|
124
|
0
|
0
|
|
|
|
|
if (defined $ver) { |
|
125
|
0
|
|
|
|
|
|
$self->debugf("$row->[0] $ver"); |
|
126
|
0
|
0
|
|
|
|
|
if ($self->matches_version($row->[0], $row->[1], $ver)) { |
|
127
|
0
|
|
|
|
|
|
printf "[$type_name] %s %s %s: %s\n", $row->[0], $ver, $row->[1], $row->[2]; |
|
128
|
0
|
|
|
|
|
|
$failed++; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
} else { |
|
131
|
0
|
|
|
|
|
|
$self->debugf("$row->[0] is not found"); |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
} |
|
134
|
0
|
|
|
|
|
|
return $failed; |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub check_security { |
|
138
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
139
|
0
|
|
|
|
|
|
$self->_check_issue(\@SECURITY, 'SECURITY'); |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub check_performance { |
|
143
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
144
|
0
|
|
|
|
|
|
$self->_check_issue(\@PERFORMANCE, 'PERFORMANCE'); |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub check_bugs { |
|
148
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
149
|
0
|
|
|
|
|
|
$self->_check_issue(\@BUG, 'BUG'); |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub check_xs_installed { |
|
153
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
|
154
|
0
|
|
|
|
|
|
my $failed = 0; |
|
155
|
0
|
|
|
|
|
|
for my $row (@XS) { |
|
156
|
0
|
|
|
|
|
|
my $pmver = get_version($row->[0]); |
|
157
|
0
|
0
|
|
|
|
|
if (defined $pmver) { |
|
158
|
0
|
|
|
|
|
|
my $xsver = get_version($row->[1]); |
|
159
|
0
|
0
|
|
|
|
|
if (defined $xsver) { |
|
160
|
0
|
|
|
|
|
|
$self->debugf("$row->[1] is also installed"); |
|
161
|
|
|
|
|
|
|
} else { |
|
162
|
0
|
|
|
|
|
|
printf "[XS] %s is need to install for better performance for %s\n", $row->[1], $row->[0]; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
} else { |
|
165
|
0
|
|
|
|
|
|
$self->debugf("$row->[0] is not installed"); |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub _check_optional { |
|
171
|
0
|
|
|
0
|
|
|
my ($self, $rules, $type_name) = @_; |
|
172
|
0
|
|
|
|
|
|
my $failed = 0; |
|
173
|
0
|
|
|
|
|
|
for my $row (@$rules) { |
|
174
|
0
|
|
|
|
|
|
my $pmver = get_version($row->[0]); |
|
175
|
0
|
0
|
|
|
|
|
if (defined $pmver) { |
|
176
|
0
|
|
|
|
|
|
my $xsver = get_version($row->[1]); |
|
177
|
0
|
0
|
|
|
|
|
if (defined $xsver) { |
|
178
|
0
|
|
|
|
|
|
$self->debugf("$row->[1] is also installed"); |
|
179
|
|
|
|
|
|
|
} else { |
|
180
|
0
|
|
|
|
|
|
printf "[$type_name] %s => %s: %s\n", $row->[1], $row->[0], $row->[2]; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
} else { |
|
183
|
0
|
|
|
|
|
|
$self->debugf("$row->[0] is not installed"); |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub check_feature { |
|
189
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
190
|
0
|
|
|
|
|
|
$self->_check_optional(\@OPTIONAL_MODULES, 'OPTIONAL_MODULES'); |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
if (not defined caller(0)) { |
|
194
|
|
|
|
|
|
|
my $checker = __PACKAGE__->new(); |
|
195
|
|
|
|
|
|
|
$checker->{verbose}++ if $ENV{DEBUG}; |
|
196
|
|
|
|
|
|
|
$checker->check() or print "OK\n"; |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
1; |