File Coverage

blib/lib/MyCPAN/App/DPAN/Reporter/AsYAML.pm
Criterion Covered Total %
statement 42 133 31.5
branch 0 26 0.0
condition 0 7 0.0
subroutine 15 26 57.6
pod 7 7 100.0
total 64 199 32.1


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