File Coverage

lib/Gentoo/Util/MetaCPAN.pm
Criterion Covered Total %
statement 63 147 42.8
branch 2 20 10.0
condition 0 5 0.0
subroutine 18 36 50.0
pod 6 6 100.0
total 89 214 41.5


line stmt bran cond sub pod time code
1 3     3   57421 use 5.006;
  3         10  
  3         105  
2 3     3   12 use strict;
  3         3  
  3         83  
3 3     3   12 use warnings;
  3         4  
  3         172  
4              
5             package Gentoo::Util::MetaCPAN;
6              
7             our $VERSION = '0.001000'; # TRIAL
8              
9             # ABSTRACT: Gentoo Specific MetaCPAN Utilities.
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 3     3   1588 use Moo;
  3         37897  
  3         15  
14 3     3   5058 use MooX::Lsub qw( lsub );
  3         19890  
  3         15  
15 3     3   1098 use File::Spec;
  3         4  
  3         74  
16 3     3   18 use Sub::Exporter::Progressive -setup => { exports => ['mcpan'] };
  3         4  
  3         24  
17 3     3   2315 use Path::Tiny qw( path );
  3         32474  
  3         1863  
18              
19             sub _mk_cache {
20 2     2   6 my ( $name, %opts ) = @_;
21 2         197 my $root = path( File::Spec->tmpdir );
22 2         62 my $child = $root->child('gentoo-metacpan-cache');
23 2         117 $child->mkpath;
24 2         136 my $db = $child->child($name);
25 2         1009 require Data::Serializer::Sereal;
26 2         7260 require Sereal;
27 2         808 my $serial = Data::Serializer::Sereal->new( encoder => Sereal::Encoder->new( { compress => 1, canonincal => 1 } ) );
28 2         13671 $db->mkpath;
29 2         479 require CHI;
30 0         0 require CHI::Driver::LMDB;
31 0         0 return CHI->new(
32             driver => 'LMDB',
33             root_dir => "$db",
34             expires_in => '6 hour',
35             expires_variance => '0.2',
36             namespace => $name,
37             cache_size => '30m',
38             key_serializer => $serial,
39             serializer => $serial,
40             %opts,
41             );
42             }
43              
44 0     0   0 lsub 'www_cache' => sub { _mk_cache('web') };
45 2     2   746 lsub 'object_cache' => sub { _mk_cache('objects') };
46              
47             lsub 'debug' => sub {
48 0 0   0   0 return unless defined $ENV{WWW_MECH_DEBUG};
49 0         0 return $ENV{WWW_MECH_DEBUG};
50             };
51             lsub 'nocache' => sub {
52 2 50   2   831 return unless defined $ENV{WWW_MECH_NOCACHE};
53 0         0 return $ENV{WWW_MECH_NOCACHE};
54             };
55             lsub 'mechua' => sub {
56 0     0   0 my ($self) = @_;
57 0         0 my $mech;
58 0 0       0 if ( $self->nocache ) {
59 0         0 require LWP::UserAgent;
60 0         0 $mech = LWP::UserAgent->new();
61             }
62             else {
63 0         0 require WWW::Mechanize::Cached;
64 0         0 $mech = WWW::Mechanize::Cached->new(
65             cache => $self->www_cache,
66             timeout => 20_000,
67             autocheck => 1,
68             );
69             }
70 0 0 0     0 if ( ( $self->debug || 0 ) > 1 ) {
    0          
71             $mech->add_handler(
72             'request_send' => sub {
73 0     0   0 *STDERR->printf( "%s\n", $_[0]->as_string );
74 0         0 return;
75             },
76 0         0 );
77             $mech->add_handler(
78             'response_done' => sub {
79 0     0   0 *STDERR->printf( "%s\n", $_[0]->content );
80 0         0 return;
81             },
82 0         0 );
83             }
84             elsif ( $self->debug ) {
85             $mech->add_handler(
86             'request_send' => sub {
87 0     0   0 *STDERR->printf( "%s\n", $_[0]->dump );
88 0         0 return;
89             },
90 0         0 );
91             $mech->add_handler(
92             'response_done' => sub {
93 0     0   0 *STDERR->printf( "%s\n", $_[0]->dump );
94 0         0 return;
95             },
96 0         0 );
97             }
98 0         0 return $mech;
99             };
100             lsub 'tinymech' => sub {
101 0     0   0 my ($self) = @_;
102 0         0 require HTTP::Tiny::Mech;
103 0         0 HTTP::Tiny::Mech->new( mechua => $self->mechua );
104             };
105             lsub 'client' => sub {
106 0     0   0 my ($self) = @_;
107 0         0 require MetaCPAN::Client;
108 0         0 MetaCPAN::Client->new( ua => $self->tinymech );
109             };
110              
111             sub _cache_object {
112 2     2   5 my ( $self, $key, $time, $code ) = @_;
113 2 50       7 if ( $self->nocache ) {
114 0         0 return $code->();
115             }
116 2         9 return $self->object_cache->compute( $key, $time, $code );
117             }
118             {
119             ## HACK: This exists because its not supported natively yet.
120             ## no critic (TestingAndDebugging::ProhibitNoWarnings,Subroutines::ProhibitQualifiedSubDeclarations)
121 3     3   17 no warnings 'redefine';
  3         23  
  3         106  
122              
123 3     3   1380 use MetaCPAN::Client::ResultSet;
  3         49739  
  3         2252  
124              
125             sub MetaCPAN::Client::ResultSet::next {
126 0     0 1 0 my $self = shift;
127 0         0 my $result =
128             $self->has_scroller
129             ? $self->scroller->next
130 0 0       0 : shift @{ $self->items };
131              
132 0 0       0 defined $result or return;
133              
134 0 0       0 my $class = exists $self->{'class'} ? $self->{class} : 'MetaCPAN::Client::' . ucfirst $self->type;
135 0   0     0 return $class->new_from_request( $result->{'_source'} || $result->{'fields'} );
136             }
137             }
138              
139             # More hacks because the native MetaCPAN client is a bit broken
140             sub _raw_scroll_query {
141 0     0   0 my ( $self, $config ) = @_;
142              
143 0         0 my $creq = $self->client->request;
144              
145 0         0 my $class = delete $config->{'class'};
146 0         0 my $type = delete $config->{type};
147              
148 0         0 my $scroller = $creq->ssearch( $type, { bogus => 1 }, $config );
149              
150 0 0       0 if ( not $class ) {
151 0         0 $class = 'MetaCPAN::Client::' . ucfirst( $config->{type} );
152             }
153 0         0 my $rs = MetaCPAN::Client::ResultSet->new(
154             type => $type,
155             scroller => $scroller,
156             );
157 0         0 $rs->{class} = $class;
158 0         0 return $rs;
159             }
160              
161             sub _scroll_to_list {
162 0     0   0 my ( undef, $scroll ) = @_;
163 0         0 my @out;
164 0         0 while ( my $item = $scroll->next ) {
165 0         0 push @out, $item;
166             }
167 0         0 return @out;
168             }
169              
170             sub find_release {
171 1     1 1 1114 my ( $self, $author, $dist ) = @_;
172 1         381 require Gentoo::Util::MetaCPAN::Release;
173 1         11 my $query = {
174             type => 'release',
175             class => 'Gentoo::Util::MetaCPAN::Release',
176             body => {
177             query => {
178             bool => {
179             must => [
180             { term => { name => $dist } }, #
181             { term => { author => $author } }, #
182             ],
183             },
184             },
185             },
186             };
187             my $result = $self->_cache_object(
188             [ 'find_release', $author, $dist ] => undef,
189             => sub {
190 0     0   0 return [ $self->_scroll_to_list( $self->_raw_scroll_query($query) ), ];
191             },
192 1         8 );
193 0         0 return @{$result};
  0         0  
194             }
195              
196             sub find_files_providing {
197 0     0 1 0 my ( $self, $module_name ) = @_;
198 0         0 require Gentoo::Util::MetaCPAN::File;
199              
200 0         0 my @terms;
201 0         0 push @terms, { term => { 'module.authorized' => 1 } };
202 0         0 push @terms, { term => { 'module.indexed' => 1 } };
203 0         0 push @terms, { term => { 'module.name' => $module_name } };
204              
205 0         0 my $nested_query = {
206             constant_score => {
207             filter => {
208             and => \@terms,
209             },
210             },
211             };
212 0         0 my $query = {
213             filtered => {
214             query => {
215             nested => {
216             path => 'module',
217             query => $nested_query,
218             },
219             },
220             },
221             };
222 0         0 my $config = {
223             type => 'file',
224             class => 'Gentoo::Util::MetaCPAN::File',
225             body => {
226             query => $query,
227             },
228             };
229             my $result = $self->_cache_object(
230             [ 'find_files_providing', $module_name ] => undef,
231             => sub {
232 0     0   0 return [ $self->_scroll_to_list( $self->_raw_scroll_query($config) ) ];
233             },
234 0         0 );
235 0         0 return @{$result};
  0         0  
236             }
237              
238             sub find_latest_files_providing {
239 1     1 1 1221 my ( $self, $module_name ) = @_;
240 1         408 require Gentoo::Util::MetaCPAN::File;
241              
242 1         3 my @terms;
243 1         5 push @terms, { term => { 'module.authorized' => 1 } };
244 1         3 push @terms, { term => { 'module.indexed' => 1 } };
245 1         3 push @terms, { term => { 'module.name' => $module_name } };
246              
247 1         5 my $nested_query = {
248             constant_score => {
249             filter => {
250             and => \@terms,
251             },
252             },
253             };
254 1         5 my $query = {
255             filtered => {
256             query => {
257             nested => {
258             path => 'module',
259             query => $nested_query,
260             },
261             },
262             },
263             };
264 1         7 my $config = {
265             type => 'file',
266             class => 'Gentoo::Util::MetaCPAN::File',
267              
268             body => {
269             fields => q[*],
270             script_fields => { latest => { 'metacpan_script' => 'status_is_latest' } },
271             query => $query,
272             },
273             };
274             my $result = $self->_cache_object(
275             [ 'find_latest_files_providing', $module_name ] => undef,
276             => sub {
277 0     0   0 return [ grep { $_->latest } $self->_scroll_to_list( $self->_raw_scroll_query($config) ) ];
  0         0  
278             },
279 1         9 );
280 0         0 return @{$result};
  0         0  
281              
282             }
283              
284             sub find_releases_providing {
285 0     0 1 0 my ( $self, $module_name ) = @_;
286 0         0 require Gentoo::Util::MetaCPAN::Release;
287              
288 0         0 my $nested_query = {
289             bool => {
290             must => [
291             { term => { 'authorized' => 1 } }, #
292             { term => { 'indexed' => 1 } }, #
293             { term => { 'name' => $module_name } }, #
294             ],
295             },
296             };
297              
298 0         0 my $query = {
299             nested => {
300             path => 'module',
301             query => $nested_query,
302             },
303             };
304              
305 0         0 my $config = {
306             type => 'release',
307             class => 'Gentoo::Util::MetaCPAN::Release',
308             body => {
309             query => { # %{$query},
310             constant_score => { query => $query },
311             },
312             },
313             };
314             my $result = $self->_cache_object(
315             [ 'find_releases_providing', $module_name ] => undef,
316             => sub {
317 0     0   0 return [ $self->_scroll_to_list( $self->_raw_scroll_query($config) ) ];
318             },
319 0         0 );
320 0         0 return @{$result};
  0         0  
321             }
322              
323 2     2 1 1679 sub mcpan { return __PACKAGE__->new() }
324              
325 3     3   23 no Moo;
  3         4  
  3         15  
326              
327             1;
328              
329             __END__
330              
331             =pod
332              
333             =encoding UTF-8
334              
335             =head1 NAME
336              
337             Gentoo::Util::MetaCPAN - Gentoo Specific MetaCPAN Utilities.
338              
339             =head1 VERSION
340              
341             version 0.001000
342              
343             =head1 METHODS
344              
345             =head2 find_files_providing
346              
347             =head2 find_latest_files_providing
348              
349             =head2 find_release
350              
351             =head2 find_releases_providing
352              
353             =head1 FUNCTIONS
354              
355             =head2 C<mcpan>
356              
357             =head1 AUTHOR
358              
359             Kent Fredric <kentnl@cpan.org>
360              
361             =head1 COPYRIGHT AND LICENSE
362              
363             This software is copyright (c) 2014 by Kent Fredric <kentfredric@gmail.com>.
364              
365             This is free software; you can redistribute it and/or modify it under
366             the same terms as the Perl 5 programming language system itself.
367              
368             =cut