File Coverage

blib/lib/MyCPAN/App/DPAN/Reporter/AsYAML.pm
Criterion Covered Total %
statement 40 136 29.4
branch 0 26 0.0
condition 0 7 0.0
subroutine 14 27 51.8
pod 8 8 100.0
total 62 204 30.3


line stmt bran cond sub pod time code
1             package MyCPAN::App::DPAN::Reporter::AsYAML;
2 1     1   3675 use strict;
  1         3  
  1         84  
3 1     1   26 use warnings;
  1         12  
  1         73  
4              
5 1     1   1630 use subs qw(get_caller_info);
  1         53  
  1         10  
6 1     1   70 use vars qw($VERSION $reporter_logger $collator_logger);
  1         4  
  1         136  
7              
8             # don't change the inheritance order
9             # this should be done with roles, but we don't quite have that yet
10             # it's a problem with who's cleanup() get called
11 1     1   11 use base qw(MyCPAN::Indexer::Reporter::AsYAML);
  1         4  
  1         1289  
12              
13 1     1   15946 use Cwd qw(cwd);
  1         3  
  1         60  
14 1     1   6 use File::Basename qw(dirname);
  1         2  
  1         50  
15 1     1   6 use File::Path qw(mkpath);
  1         1  
  1         54  
16 1     1   6 use File::Spec::Functions qw(catfile rel2abs);
  1         2  
  1         96  
17              
18             $VERSION = '1.28_11';
19              
20             =head1 NAME
21              
22             MyCPAN::App::DPAN::Reporter::AsYAML - Record the indexing results as YAML
23              
24             =head1 SYNOPSIS
25              
26             Use this in the dpan config by specifying it as the reporter class and
27             the collator class:
28              
29             # in dpan.config
30             reporter_class MyCPAN::App::DPAN::Reporter::AsYAML
31             collator_class MyCPAN::App::DPAN::Reporter::AsYAML
32              
33             =head1 DESCRIPTION
34              
35             This module implements the reporter_class components to allow C
36             to create a CPAN-like directory structure with its associated index
37             files. It runs through the indexing, saves the reports as YAML, and
38             prints a report at the end of the run.
39              
40             =cut
41              
42 1     1   6 use Carp qw(croak);
  1         1  
  1         39  
43 1     1   4 use Cwd qw(cwd);
  1         1  
  1         26  
44              
45 1     1   5 use Log::Log4perl;
  1         8  
  1         7  
46              
47             BEGIN {
48 1     1   85 $reporter_logger = Log::Log4perl->get_logger( 'Reporter' );
49 1         25 $collator_logger = Log::Log4perl->get_logger( 'Collator' );
50             }
51              
52             # Override the exit from the parent class so we can embed a run
53             # inside a bigger application. Applications should override this
54             # on their own to do any final processing they want.
55 0     0     sub _exit { 1 }
56              
57             =head2 Methods
58              
59             =over 4
60              
61             =item get_reporter
62              
63             Inherited from MyCPAN::App::BackPAN::Indexer
64              
65             =item get_collator
66              
67             This Reporter class also implements its Collator since the two are
68             coupled by the report format. It's a wrapper around C,
69             which previously did the same thing.
70              
71             =cut
72              
73             sub get_collator
74             {
75             #TRACE( sub { get_caller_info } );
76              
77 0     0 1   my( $self ) = @_;
78              
79 0     0     my $collator = sub { $_[0]->final_words( $_[1] ) };
  0            
80              
81 0           $self->set_note( $_[0]->collator_type, $collator );
82              
83 0           1;
84             }
85              
86             =item final_words
87              
88             Creates the F<02packages.details.txt.gz> and F files once
89             C has analysed every distribution.
90              
91             =cut
92              
93             sub final_words
94             {
95             # This is where I want to write 02packages and CHECKSUMS
96 0     0 1   my( $self ) = @_;
97              
98 0           $collator_logger->trace( "Final words from the DPAN Reporter" );
99              
100 0           my $report_dir = $self->get_config->success_report_subdir;
101 0           $collator_logger->debug( "Report dir is $report_dir" );
102              
103 0 0         opendir my($dh), $report_dir or
104             $collator_logger->fatal( "Could not open directory [$report_dir]: $!");
105              
106 0           my %dirs_needing_checksums;
107              
108 0           require CPAN::PackageDetails;
109 0           my $package_details = CPAN::PackageDetails->new;
110              
111 0           $collator_logger->info( "Creating index files" );
112              
113 0           $self->_init_skip_package_from_config;
114              
115 0           require version;
116 0           foreach my $file ( readdir( $dh ) )
117             {
118 0 0         next unless $file =~ /\.yml\z/;
119 0           $collator_logger->debug( "Processing output file $file" );
120 0 0         my $yaml = eval { YAML::LoadFile( catfile( $report_dir, $file ) ) } or do {
  0            
121 0           $collator_logger->error( "$file: $@" );
122 0           next;
123             };
124              
125 0           my $dist_file = $yaml->{dist_info}{dist_file};
126              
127             #print STDERR "Dist file is $dist_file\n";
128              
129             # some files may be left over from earlier runs, even though the
130             # original distribution has disappeared. Only index distributions
131             # that are still there
132             # check that dist file is in one of these directories
133 0 0         next unless -e $dist_file;
134              
135 0           my $dist_dir = dirname( $dist_file );
136              
137 0           $dirs_needing_checksums{ $dist_dir }++;
138              
139             =pod
140              
141             This is the big problem. Since we didn't really parse the source code, we
142             don't really know how to match up packages and VERSIONs. The best we can
143             do right now is assume that a $VERSION we found goes with the packages
144             we found.
145              
146             Additionally, that package variable my have been in one package, but
147             been the version for another package. For example:
148              
149             package DBI;
150              
151             $DBI::PurePerl::VERSION = 1.23;
152              
153             =cut
154              
155 0           foreach my $module ( @{ $yaml->{dist_info}{module_info} } )
  0            
156             {
157 0           my $packages = $module->{packages};
158 0           my $version = $module->{version_info}{value};
159 0 0         $version = $version->numify if eval { $version->can('numify') };
  0            
160              
161 0   0       ( my $version_variable = $module->{version_info}{identifier} || '' )
162             =~ s/(?:\:\:)?VERSION$//;
163 0           $collator_logger->debug( "Package from version variable is $version_variable" );
164              
165 0           PACKAGE: foreach my $package ( @$packages )
166             {
167 0 0 0       if( $version_variable && $version_variable ne $package )
168             {
169 0           $collator_logger->debug( "Skipping package [$package] since version variable [$version_variable] is in a different package" );
170 0           next;
171             }
172              
173             # broken crap that works on Unix and Windows to make cpanp
174             # happy. It assumes that authors/id/ is in front of the path
175             # in 02paackages
176 0           ( my $path = $dist_file ) =~ s/.*authors.id.//g;
177              
178 0           $path =~ s|\\+|/|g; # no windows paths.
179              
180 0 0         if( $self->skip_package( $package ) )
181             {
182 0           $collator_logger->debug( "Skipping $package: excluded by config" );
183 0           next PACKAGE;
184             }
185              
186             $package_details->add_entry(
187 0           'package name' => $package,
188             version => $version,
189             path => $path,
190             );
191             }
192             }
193             }
194              
195 0           $self->_create_index_files( $package_details, [ keys %dirs_needing_checksums ] );
196              
197 0           1;
198             }
199              
200             sub _create_index_files
201             {
202 0     0     my( $self, $package_details, $dirs_needing_checksums ) = @_;
203              
204 0           my $index_dir = do {
205 0           my $d = $self->get_config->dpan_dir;
206              
207             # there might be more than one if we pull from multiple sources
208             # so make the index in the first one.
209 0 0         my $abs = rel2abs( ref $d ? $d->[0] : $d );
210 0           $abs =~ s/authors.id.*//;
211 0           catfile( $abs, 'modules' );
212             };
213              
214 0 0         mkpath( $index_dir ) unless -d $index_dir;
215              
216 0           my $packages_file = catfile( $index_dir, '02packages.details.txt.gz' );
217              
218 0           $reporter_logger->info( "Writing 02packages.details.txt.gz" );
219 0           $package_details->write_file( $packages_file );
220              
221 0           $reporter_logger->info( "Writing 03modlist.txt.gz" );
222 0           $self->create_modlist( $index_dir );
223              
224 0           $reporter_logger->info( "Creating CHECKSUMS files" );
225 0           $self->create_checksums( $dirs_needing_checksums );
226              
227 0           1;
228             }
229              
230             =item guess_package_name
231              
232             Given information about the module, make a guess about which package
233             is the primary one. This is
234              
235             NOT YET IMPLEMENTED
236              
237             =cut
238              
239             sub guess_package_name
240             {
241 0     0 1   my( $self, $module_info ) = @_;
242              
243              
244             }
245              
246             =item get_package_version( MODULE_INFO, PACKAGE )
247              
248             Get the $VERSION associated with PACKAGE. You probably want to use
249             C first to figure out which package is the
250             primary one that you should index.
251              
252             NOT YET IMPLEMENTED
253              
254             =cut
255              
256             sub get_package_version
257 0     0 1   {
258              
259              
260             }
261              
262             =item skip_package( PACKAGE )
263              
264             Returns true if the indexer should ignore PACKAGE.
265              
266             By default, this skips the Perl special packages specified by the
267             ignore_packages configuration. By default, ignore packages is:
268              
269             main
270             MY
271             MM
272             DB
273             bytes
274             DynaLoader
275              
276             To set a different list, configure ignore_packages with a space
277             separated list of packages to ignore:
278              
279             ignore_packages main Foo Bar::Baz Test
280              
281             Note that this only ignores those exact packages. You can't configure
282             this with regex or wildcards (yet).
283              
284             =cut
285              
286             BEGIN {
287 1     1   1891 my $initialized = 0;
288 1         441 my %skip_packages;
289              
290 0     0     sub _skip_package_initialized { $initialized }
291              
292             sub _init_skip_package_from_config
293             {
294 0     0     my( $self ) = @_;
295              
296 0           %skip_packages =
297 0           map { $_, 1 }
298 0   0       grep { defined }
299             split /\s+/,
300             $self->get_notes( 'config' )->ignore_packages || '';
301              
302 0           $initialized = 1;
303             }
304              
305             sub skip_package
306             {
307 0     0 1   my( $self, $package ) = @_;
308              
309 0           exists $skip_packages{ $package }
310             }
311             }
312              
313             =item create_package_details
314              
315             Not yet implemented. Otehr code needs to be refactored and show up
316             here.
317              
318             =cut
319              
320             sub create_package_details
321             {
322 0     0 1   my( $self, $index_dir ) = @_;
323              
324              
325 0           1;
326             }
327              
328             =item create_modlist
329              
330             If a modules/03modlist.data.gz does not already exist, this creates a
331             placeholder which defines the CPAN::Modulelist package and the method
332             C in that package. The C method returns an empty hash
333             reference.
334              
335             =cut
336              
337             sub create_modlist
338             {
339 0     0 1   my( $self, $index_dir ) = @_;
340              
341 0           my $module_list_file = catfile( $index_dir, '03modlist.data.gz' );
342 0           $reporter_logger->debug( "modules list file is [$module_list_file]");
343              
344 0 0         if( -e $module_list_file )
345             {
346 0           $reporter_logger->debug( "File [$module_list_file] already exists!" );
347 0           return 1;
348             }
349              
350 0           my $fh = IO::Compress::Gzip->new( $module_list_file );
351 0           print $fh <<"HERE";
352             File: 03modlist.data
353             Description: This a placeholder for CPAN.pm
354             Modcount: 0
355 0           Written-By: Id: $0
356             Date: @{ [ scalar localtime ] }
357              
358             package CPAN::Modulelist;
359              
360             sub data { {} }
361              
362             1;
363             HERE
364              
365 0           close $fh;
366             }
367              
368             =item create_checksums
369              
370             Creates the CHECKSUMS file that goes in each author directory in CPAN.
371             This is mostly a wrapper around CPAN::Checksums since that already handles
372             updating an entire tree. We just do a little logging.
373              
374             =cut
375              
376             sub create_checksums
377             {
378 0     0 1   my( $self, $dirs ) = @_;
379              
380 0           require CPAN::Checksums;
381 0           foreach my $dir ( @$dirs )
382             {
383 0           my $rc = eval{ CPAN::Checksums::updatedir( $dir ) };
  0            
384 0 0         $reporter_logger->error( "Couldn't create CHECKSUMS for $dir: $@" ) if $@;
385             $reporter_logger->info(
386 0           do {
387 0 0         if( $rc == 1 ) { "Valid CHECKSUMS file is already present" }
  0 0          
388 0           elsif( $rc == 2 ) { "Wrote new CHECKSUMS file in $dir" }
389 0           else { "updatedir unexpectedly returned an error" }
390             } );
391             }
392             }
393              
394             =back
395              
396             =head1 SOURCE AVAILABILITY
397              
398             This code is in Github:
399              
400             git://github.com/briandfoy/mycpan-indexer.git
401             git://github.com/briandfoy/mycpan--app--dpan.git
402              
403             =head1 AUTHOR
404              
405             brian d foy, C<< >>
406              
407             =head1 COPYRIGHT AND LICENSE
408              
409             Copyright (c) 2008-2010, brian d foy, All Rights Reserved.
410              
411             You may redistribute this under the same terms as Perl itself.
412              
413             =cut