File Coverage

blib/lib/OrePAN2/Indexer.pm
Criterion Covered Total %
statement 151 173 87.2
branch 28 44 63.6
condition 4 9 44.4
subroutine 31 33 93.9
pod 0 9 0.0
total 214 268 79.8


line stmt bran cond sub pod time code
1              
2             use strict;
3 6     6   578920 use warnings;
  6         34  
  6         149  
4 6     6   25 use utf8;
  6         10  
  6         113  
5 6     6   24  
  6         18  
  6         30  
6             use Archive::Extract ();
7 6     6   3224 use CPAN::Meta 2.131560 ();
  6         886577  
  6         196  
8 6     6   2695 use Class::Accessor::Lite ( rw => ['_metacpan_lookup'] );
  6         146109  
  6         167  
9 6     6   1555 use File::Basename ();
  6         4232  
  6         41  
10 6     6   398 use File::Find qw( find );
  6         12  
  6         96  
11 6     6   34 use File::Spec ();
  6         9  
  6         266  
12 6     6   34 use File::Temp qw( tempdir );
  6         13  
  6         104  
13 6     6   24 use File::pushd qw( pushd );
  6         12  
  6         261  
14 6     6   1102 use IO::Zlib ();
  6         3032  
  6         257  
15 6     6   2833 use MetaCPAN::Client ();
  6         302867  
  6         161  
16 6     6   2799 use OrePAN2::Index ();
  6         1414679  
  6         166  
17 6     6   2425 use Parse::LocalDistribution ();
  6         15  
  6         126  
18 6     6   2774 use Path::Tiny ();
  6         266452  
  6         175  
19 6     6   4314 use Try::Tiny qw( catch try );
  6         58370  
  6         189  
20 6     6   2656 use Ref::Util qw( is_arrayref );
  6         6483  
  6         320  
21 6     6   39  
  6         10  
  6         8915  
22             my $class = shift;
23             my %args = @_ == 1 ? %{ $_[0] } : @_;
24 13     13 0 13037 unless ( defined $args{directory} ) {
25 13 50       103 Carp::croak('Missing mandatory parameter: directory');
  0         0  
26 13 50       70 }
27 0         0 bless {
28             %args,
29             }, $class;
30 13         152 }
31              
32              
33              
34 23     23 0 1309 my ( $self, %args ) = @_;
35              
36 6 100   6 0 47 my @files = $self->list_archive_files();
37              
38             if ( $self->{metacpan} ) {
39 12     12 0 93 try {
40             $self->do_metacpan_lookup( \@files );
41 12         49 }
42             catch {
43 12 100       54 print STDERR "[WARN] Unable to fetch provides via MetaCPAN\n";
44             print STDERR "[WARN] $_\n";
45 4     4   256 };
46             }
47              
48 0     0   0 my $index = OrePAN2::Index->new();
49 0         0 for my $archive_file (@files) {
50 4         46 $self->add_index( $index, $archive_file );
51             }
52             $self->write_index( $index, $args{no_compress} );
53 12         2454 return $index;
54 12         42 }
55 11         45  
56             my ( $self, $index, $archive_file ) = @_;
57 12         122  
58 12         3854 return if $self->_maybe_index_from_metacpan( $index, $archive_file );
59              
60             my $archive = Archive::Extract->new( archive => $archive_file );
61             my $tmpdir = tempdir( 'orepan2.XXXXXX', TMPDIR => 1, CLEANUP => 1 );
62 11     11 0 41 $archive->extract( to => $tmpdir );
63              
64 11 100       57 my $provides = $self->scan_provides( $tmpdir, $archive_file );
65             my $path = $self->_orepan_archive_path($archive_file);
66 5         41  
67 5         1585 foreach my $package ( sort keys %{$provides} ) {
68 5         1534 $index->add_index(
69             $package,
70 5         696775 $provides->{$package}->{version},
71 5         269 $path,
72             );
73 5         19 }
  5         49  
74             }
75              
76             my $self = shift;
77 5         92 my $archive_file = shift;
78             my $path = File::Spec->abs2rel(
79             $archive_file,
80             File::Spec->catfile( $self->directory, 'authors', 'id' )
81             );
82             $path =~ s!\\!/!g;
83 11     11   35 return $path;
84 11         32 }
85 11         92  
86             my ( $self, $dir, $archive_file ) = @_;
87              
88             my $guard = pushd( glob("$dir/*") );
89 11         89 for my $mfile ( 'META.json', 'META.yml', 'META.yaml' ) {
90 11         45 next unless -f $mfile;
91             my $meta = eval { CPAN::Meta->load_file($mfile) };
92             return $meta->{provides} if $meta && $meta->{provides};
93              
94 5     5 0 64 if ($@) {
95             print STDERR "[WARN] Error using '$mfile' from '$archive_file'\n";
96 5         633 print STDERR "[WARN] $@\n";
97 5         732 print STDERR "[WARN] Attempting to continue...\n";
98 5 50       103 }
99 5         23 }
  5         144  
100 5 50 33     74343  
101             print STDERR
102 0 0       0 "[INFO] Found META file in '$archive_file' but it does not contain 'provides'\n";
103 0         0 print STDERR "[INFO] Scanning for provided modules...\n";
104 0         0  
105 0         0 my $provides = eval { $self->_scan_provides('.') };
106             return $provides if $provides;
107              
108             print STDERR "[WARN] Error scanning: $@\n";
109 0         0  
110             # Return empty provides.
111 0         0 return {};
112             }
113 0         0  
  0         0  
114 0 0       0 my ( $self, $index, $file ) = @_;
115              
116 0         0 return unless $self->{metacpan};
117              
118             my $archive = Path::Tiny->new($file)->basename;
119 0         0 my $lookup = $self->_metacpan_lookup;
120              
121             unless ( exists $lookup->{archive}->{$archive} ) {
122             print STDERR "[INFO] $archive not found on MetaCPAN\n";
123 11     11   61 return;
124             }
125 11 100       70 my $release_name = $lookup->{archive}->{$archive};
126              
127 6         53 my $provides = $lookup->{release}->{$release_name};
128 6         671 unless ( $provides && keys %{$provides} ) {
129             print STDERR "[INFO] provides for $archive not found on MetaCPAN\n";
130 6 50       62 return;
131 0         0 }
132 0         0  
133             my $path = $self->_orepan_archive_path($file);
134 6         22  
135             foreach my $package ( keys %{$provides} ) {
136 6         22 $index->add_index( $package, $provides->{$package}, $path, );
137 6 50 33     28 }
  6         50  
138 0         0 return 1;
139 0         0 }
140              
141             my ( $self, $files ) = @_;
142 6         27  
143             return unless @{$files};
144 6         22  
  6         55  
145 43         159 my $provides = $self->_metacpan_lookup;
146              
147 6         53 my $mc = MetaCPAN::Client->new( version => 'v1' );
148             my @archives = map { Path::Tiny->new($_)->basename } @{$files};
149             my @search_by_archives = map { +{ archive => $_ } } @archives;
150              
151 5     5 0 44 while (@search_by_archives) {
152             my @search_by_archives_chunk = splice @search_by_archives, 0,
153 5 50       12 $self->metacpan_lookup_size;
  5         20  
154              
155 5         38 my $releases
156             = $mc->release( { either => \@search_by_archives_chunk } );
157 5         199  
158 5         1561 my @file_search;
  8         314  
  5         14  
159 5         271  
  8         25  
160             while ( my $release = $releases->next ) {
161 5         17 $provides->{archive}->{ $release->archive } = $release->name;
162 6         197255  
163             push @file_search,
164             {
165 6         41 all => [
166             { release => $release->name },
167             { indexed => 'true' },
168 6         1161968 { authorized => 'true' },
169             { 'module.indexed' => 'true' },
170 6         36 ]
171 8         599147 };
172             }
173 8         605  
174             next unless @file_search;
175              
176             my $modules = $mc->module( { either => \@file_search } );
177              
178             while ( my $file = $modules->next ) {
179             my $module = $file->module or next;
180             for my $inner ( is_arrayref $module ? @{$module} : $module ) {
181             next unless $inner->{indexed};
182             $provides->{release}->{ $file->release }->{ $inner->{name} }
183             //= $inner->{version};
184 6 50       368 }
185             }
186 6         55 }
187              
188 6         1032434 $self->_metacpan_lookup($provides);
189 61 50       572296 }
190 61 50       1001  
  61         155  
191 61 50       260 my ( $self, $dir, $meta ) = @_;
192              
193 61   66     1536 my $provides = Parse::LocalDistribution->new( { ALLOW_DEV_VERSION => 1 } )
194             ->parse($dir);
195             return $provides;
196             }
197              
198 5         914994 my ( $self, $index, $no_compress ) = @_;
199              
200             my $pkgfname = File::Spec->catfile(
201             $self->directory,
202 0     0   0 'modules',
203             $no_compress ? '02packages.details.txt' : '02packages.details.txt.gz'
204 0         0 );
205             mkdir( File::Basename::dirname($pkgfname) );
206 0         0 my $fh = do {
207             if ($no_compress) {
208             open my $fh, '>:raw', $pkgfname;
209             $fh;
210 12     12 0 53 }
211             else {
212 12 100       60 IO::Zlib->new( $pkgfname, 'w' )
213             or die "Cannot open $pkgfname for writing: $!\n";
214             }
215             };
216             print $fh $index->as_string( { simple => $self->{simple} } );
217 12         1670 close $fh;
218 12         68 }
219 12 100       63  
220 5         2290 my $self = shift;
221 5         31  
222             my $authors_dir = File::Spec->catfile( $self->{directory}, 'authors' );
223             return () unless -d $authors_dir;
224 7 50       152  
225             my @files;
226             find(
227             {
228 12         21582 wanted => sub {
229 12         2284 return unless /
230             (?:
231             \.tar\.gz
232             | \.tgz
233 12     12 0 62 | \.zip
234             )
235 12         138 \z/x;
236 12 100       262 push @files, $_;
237             },
238 9         28 no_chdir => 1,
239             },
240             $authors_dir
241             );
242 62 100   62   3785  
243             # Sort files by modication time so that we can index distributions from
244             # earliest to latest version.
245              
246             return sort { -M $b <=> -M $a } @files;
247             }
248              
249 11         145 1;