File Coverage

blib/lib/DarkPAN/Utils.pm
Criterion Covered Total %
statement 51 166 30.7
branch 0 28 0.0
condition 0 15 0.0
subroutine 17 31 54.8
pod 9 10 90.0
total 77 250 30.8


line stmt bran cond sub pod time code
1             ########################################################################
2             package DarkPAN::Utils;
3             ########################################################################
4              
5 1     1   396304 use strict;
  1         3  
  1         43  
6 1     1   6 use warnings;
  1         2  
  1         67  
7              
8 1     1   1035 use Archive::Tar;
  1         127787  
  1         64  
9 1     1   7 use Data::Dumper;
  1         2  
  1         42  
10 1     1   5 use English qw(no_match_vars);
  1         1  
  1         7  
11 1     1   283 use File::Basename qw(fileparse);
  1         2  
  1         53  
12 1     1   670 use Getopt::Long qw(:config no_ignore_case);
  1         14638  
  1         6  
13 1     1   998 use HTTP::Request;
  1         26241  
  1         46  
14 1     1   752 use IO::Scalar;
  1         4748  
  1         62  
15 1     1   8 use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
  1         2  
  1         165  
16 1     1   1061 use LWP::UserAgent;
  1         46732  
  1         75  
17 1     1   16 use List::Util qw(none);
  1         3  
  1         139  
18 1     1   1447 use Log::Log4perl qw(:easy);
  1         67789  
  1         8  
19 1     1   944 use Log::Log4perl::Level;
  1         3  
  1         6  
20 1     1   973 use Pod::Usage;
  1         67027  
  1         162  
21              
22 1     1   898 use Readonly;
  1         5910  
  1         111  
23             Readonly our $BASE_URL => q{};
24              
25 1     1   9 use parent qw(Class::Accessor::Validated);
  1         1  
  1         25  
26              
27             our $VERSION = '0.02';
28              
29             our @EXPORT_OK = qw(parse_distribution_path);
30              
31             our %ATTRIBUTES = (
32             logger => 0,
33             log_level => 0,
34             package => 0, # Archive::Tar of unzip packag
35             module_index => 0, # distribution tarball indexed list of contents
36             darkpan_index => 0, # distribution list (raw)
37             help => 0,
38             base_url => 1,
39             module => 0,
40             );
41              
42             __PACKAGE__->setup_accessors( keys %ATTRIBUTES );
43              
44             caller or __PACKAGE__->main();
45              
46             ########################################################################
47             sub new {
48             ########################################################################
49 0     0 1   my ( $class, @args ) = @_;
50              
51 0 0         my $options = ref $args[0] ? $args[0] : {@args};
52              
53 0   0       $options->{log_level} //= 'info';
54              
55 0           my $self = $class->SUPER::new($options);
56              
57 0           return $self;
58             }
59              
60             ########################################################################
61             sub parse_distribution_path {
62             ########################################################################
63 0     0 1   my ($path) = @_;
64              
65 0           my @distribution = ( $path =~ m{D/DU/DUMMY/(.*)-([v\d.]+)[.]tar[.]gz$}xsm );
66              
67 0           return @distribution;
68             }
69              
70             ########################################################################
71             sub find_module {
72             ########################################################################
73 0     0 1   my ( $self, $module ) = @_;
74              
75 0           my $module_index = $self->get_module_index;
76              
77 0           my @found;
78              
79 0           foreach my $p ( keys %{$module_index} ) {
  0            
80              
81 0           my ($distribution) = parse_distribution_path($p);
82              
83 0 0         if ( $distribution eq $module ) {
84 0           push @found, $p;
85 0           next;
86             }
87              
88 0 0   0     next if none { $_ eq $module } @{ $module_index->{$p} };
  0            
  0            
89              
90 0           push @found, $p;
91             }
92              
93             return
94 0 0         if !@found;
95              
96 0           return \@found;
97             }
98              
99             ########################################################################
100             sub extract_file {
101             ########################################################################
102 0     0 1   my ( $self, $file ) = @_;
103              
104 0           my $package = $self->get_package;
105              
106 0           my @list = $package->list_files;
107              
108             return
109 0 0   0     if none { $file eq $_ } @list;
  0            
110              
111 0           return $package->get_content($file);
112             }
113              
114             ########################################################################
115             sub extract_module {
116             ########################################################################
117 0     0 1   my ( $self, $package, $module ) = @_;
118              
119 0           $package =~ s{D/DU/DUMMY/(.*)[.]tar[.]gz$}{$1}xsm;
120              
121 0           my $file = $module;
122              
123 0           $file =~ s/::/\//xsmg;
124              
125 0           return $self->extract_file( sprintf '%s/lib/%s.pm', $package, $file );
126             }
127              
128             ########################################################################
129             sub fetch_darkpan_index {
130             ########################################################################
131 0     0 1   my ($self) = @_;
132              
133 0 0         return $self
134             if $self->get_darkpan_index;
135              
136 0           my $file = '02packages.details.txt.gz';
137              
138 0           my $index_url = sprintf '%s/modules/%s', $self->get_base_url, $file;
139              
140 0           my $ua = LWP::UserAgent->new;
141 0           my $req = HTTP::Request->new( GET => $index_url );
142 0           my $rsp = $ua->request($req);
143              
144 0           my $index = q{};
145              
146 0 0         die Dumper( [ rsp => $rsp ] )
147             if !$rsp->is_success;
148              
149 0           my $index_zipped = $rsp->content;
150              
151 0 0         gunzip( \$index_zipped, \$index )
152             or die "unzip failed: $GunzipError\n";
153              
154 0           $self->set_darkpan_index($index);
155              
156 0           $self->_create_module_index;
157              
158 0           return $self;
159             }
160              
161             ########################################################################
162             sub fetch_package {
163             ########################################################################
164 0     0 1   my ( $self, $package_name ) = @_;
165              
166 0           my $logger = $self->get_logger;
167              
168 0           my $package_url = sprintf '%s/authors/id/%s', $self->get_base_url, $package_name;
169              
170 0           my $ua = LWP::UserAgent->new;
171 0           my $req = HTTP::Request->new( GET => $package_url );
172 0           my $rsp = $ua->request($req);
173              
174 0 0         die Dumper( [ rsp => $rsp ] )
175             if !$rsp->is_success;
176              
177 0           my $package_zipped = $rsp->content;
178 0           my $package = q{};
179              
180 0           gunzip( \$package_zipped, \$package );
181              
182 0           my $tar = Archive::Tar->new;
183              
184 0           my $fh = IO::Scalar->new( \$package );
185              
186 0           $tar->read($fh);
187              
188 0           $self->set_package($tar);
189              
190 0           my ($package_basename) = $package_name =~ /^D\/DU\/DUMMY\/(.*?)[.]tar[.]gz$/xsm;
191              
192             $logger->debug(
193             sub {
194 0     0     return Dumper(
195             [ package_basename => $package_basename,
196             files => $tar->list_files
197             ]
198             );
199             }
200 0           );
201              
202 0           return $self;
203             }
204              
205             ########################################################################
206             sub _create_module_index {
207             ########################################################################
208 0     0     my ($self) = @_;
209              
210 0           my $index = $self->get_darkpan_index;
211              
212 0           $index =~ s/^(?:.*)?\n\n//xsm;
213              
214 0           my @modules = split /\n/xsm, $index;
215 0           my %module_index;
216             my %module_versions;
217              
218 0           foreach (@modules) {
219 0           my ( $module, $version, $zip ) = split /\s+/xsm;
220              
221 0 0 0       if ( $module_versions{$module} && $version gt $module_versions{$module} ) {
222 0           delete $module_index{$zip};
223             }
224              
225 0   0       $module_index{$zip} //= [];
226 0           push @{ $module_index{$zip} }, $module;
  0            
227             }
228              
229 0           $self->set_module_index( \%module_index );
230              
231 0           return $self;
232             }
233              
234             ########################################################################
235             sub init_logger {
236             ########################################################################
237 0     0 1   my ($self) = @_;
238              
239 0   0       my $level = $self->get_log_level // 'info';
240              
241             $level = {
242             'trace' => $TRACE,
243             'debug' => $DEBUG,
244             'info' => $INFO,
245             'warn' => $WARN,
246             'error' => $ERROR,
247             'trace' => $TRACE,
248 0   0       }->{$level} // $INFO;
249              
250 0           Log::Log4perl->easy_init($level);
251              
252 0           $self->set_logger( Log::Log4perl->get_logger );
253              
254 0           return $self;
255             }
256              
257             ########################################################################
258             sub fetch_options {
259             ########################################################################
260              
261 0     0 1   my %options = (
262             'log-level' => 'info',
263             'base-url' => $BASE_URL,
264             );
265              
266 0           my @option_specs = qw(
267             help|h
268             package|p=s
269             module|m=s
270             log-level|l=s
271             base-url|u=s
272             );
273              
274 0           my $retval = GetOptions( \%options, @option_specs );
275              
276 0 0 0       if ( !$retval || $options{help} ) {
277 0           pod2usage( -exitval => 1, -verbose => 1 );
278             }
279              
280 0           foreach my $o ( keys %options ) {
281 0 0         next if $o !~ /[-]/xsm;
282              
283 0           my $value = delete $options{$o};
284 0           $o =~ s/[-]/_/xsm;
285 0           $options{$o} = $value;
286             }
287              
288 0           return \%options;
289             }
290              
291             ########################################################################
292             sub main {
293             ########################################################################
294              
295 0     0 0   my $options = fetch_options();
296              
297 0           my $self = DarkPAN::Utils->new($options);
298              
299 0           $self->init_logger;
300              
301 0           my $logger = $self->get_logger;
302              
303 0           $self->fetch_darkpan_index;
304              
305             $logger->trace(
306             Dumper(
307 0           [ packages => [ sort keys %{ $self->get_module_index } ],
  0            
308             module_index => $self->get_module_index,
309             ]
310             )
311             );
312              
313 0           my $module = $self->get_module;
314              
315 0 0         if ($module) {
316 0           my $package = $self->find_module($module);
317              
318 0 0         die sprintf "could not find %s\n", $module
319             if !$package;
320              
321 0           $logger->info( sprintf 'fetching package: %s', $package );
322              
323 0           $self->fetch_package($package);
324              
325 0           my $file = $self->extract_module( $package, $module );
326              
327 0           my $docs = DarkPAN::Module::Docs->new($file);
328              
329 0           print {*STDOUT} $docs->{html};
  0            
330             }
331              
332 0           return 0;
333             }
334              
335             1;
336              
337             __END__
338              
339             =pod
340              
341             =head1 NAME
342              
343             DarkPAN::Utils - set of utilities for working with a DarkPAN
344              
345             =head1 SYNOPSIS
346              
347             use DarkPAN::Utils qw(parse_distribution_path);
348              
349             use DarkPAN::Utils::Docs;
350              
351             my $dpu = DarkPAN::Utils->new(
352             log_level => 'debug',
353             base_url => 'https://cpan.openbedrock.net/orepan2',
354             );
355              
356             $dpu->fetch_darkpan_index;
357              
358             my $package = $dpu->find_module('SomeApp::Module');
359              
360              
361             if ($package) {
362             $dpu->fetch_package( $package->[0] );
363             }
364              
365              
366             my $file = $dpu->extract_module( $package->[0], 'SomeApp::Module');
367             my $docs = DarkPAN::Utils::Docs->new( text => $file );
368              
369             $docs->parse_pod;
370              
371             print $docs->get_html();
372              
373             =head1 DESCRIPTION
374              
375             =head1 METHODS AND SUBROUTINES
376              
377             =head2 new
378              
379             =head2 parse_distribution_path
380              
381             =head2 find_module
382              
383             =head2 extract_file
384              
385             =head2 extract_module
386              
387             =head2 fetch_darkpan_index
388              
389             =head2 fetch_package
390              
391             =head2 init_logger
392              
393             =head2 fetch_options
394              
395             =head1 AUTHOR
396              
397             Rob Lauer - <rlauer6@comcast.net>
398              
399             =head1 SEE ALSO
400              
401             L<OrePAN2>, L<OrePAN2::S3>
402              
403             =cut