File Coverage

blib/lib/OrePAN2/Index.pm
Criterion Covered Total %
statement 65 70 92.8
branch 16 20 80.0
condition 6 8 75.0
subroutine 14 14 100.0
pod 6 7 85.7
total 107 119 89.9


line stmt bran cond sub pod time code
1             package OrePAN2::Index;
2              
3 7     7   56595 use strict;
  7         27  
  7         215  
4 7     7   40 use warnings;
  7         15  
  7         199  
5 7     7   3475 use autodie;
  7         97056  
  7         40  
6 7     7   47618 use utf8;
  7         18  
  7         69  
7              
8 7     7   868 use IO::Uncompress::Gunzip ('$GunzipError');
  7         37360  
  7         1059  
9 7     7   2857 use OrePAN2;
  7         17  
  7         245  
10 7     7   399 use version 0.9912;
  7         1707  
  7         87  
11              
12             sub new {
13 19     19 1 16291 my $class = shift;
14 19 50       95 my %args = @_ == 1 ? %{ $_[0] } : @_;
  0         0  
15 19         112 bless {
16             index => {},
17             %args,
18             }, $class;
19             }
20              
21             sub load {
22 6     6 1 64 my ( $self, $fname ) = @_;
23              
24 6         27 my $fh = do {
25 6 100       54 if ( $fname =~ /\.gz\z/ ) {
26 3 50       53 IO::Uncompress::Gunzip->new($fname)
27             or die "gzip failed: $GunzipError\n";
28             }
29             else {
30 3         12 open my $fh, '<', $fname;
31 3         2468 $fh;
32             }
33             };
34              
35             # skip headers
36 6         6685 while (<$fh>) {
37 48 100       1769 last unless /\S/;
38             }
39              
40 6         18 while (<$fh>) {
41 22 50       495 if (/^(\S+)\s+(\S+)\s+(.*)$/) {
42 22 100       77 $self->add_index( $1, $2 eq 'undef' ? undef : $2, $3 );
43             }
44             }
45              
46 6         86 close $fh;
47             }
48              
49             sub lookup {
50 9     9 1 8937 my ( $self, $package ) = @_;
51 9 100       34 if ( my $entry = $self->{index}->{$package} ) {
52 8         42 return @$entry;
53             }
54 1         4 return;
55             }
56              
57             sub packages {
58 15     15 0 51 my ($self) = @_;
59 15         39 sort { lc $a cmp lc $b } keys %{ $self->{index} };
  80         147  
  15         163  
60             }
61              
62             sub delete_index {
63 1     1 1 4 my ( $self, $package ) = @_;
64 1         4 delete $self->{index}->{$package};
65 1         2 return;
66             }
67              
68             # Order of preference is last updated. So if some modules maintain the same
69             # version number across multiple uploads, we'll point to the module in the
70             # latest archive.
71              
72             sub add_index {
73 72     72 1 254 my ( $self, $package, $version, $archive_file ) = @_;
74              
75 72 100       224 if ( $self->{index}{$package} ) {
76 9         13 my ($orig_ver) = @{ $self->{index}{$package} };
  9         14  
77              
78 9 50       123 if ( version->parse($orig_ver) > version->parse($version) ) {
79 0   0     0 $version //= 'undef';
80 0         0 print STDERR "[INFO] Not adding $package in $archive_file\n";
81 0         0 print STDERR
82             "[INFO] Existing version $orig_ver is greater than $version\n";
83 0         0 return;
84             }
85             }
86 72         664 $self->{index}->{$package} = [ $version, $archive_file ];
87             }
88              
89             sub as_string {
90 13     13 1 101 my ( $self, $opts ) = @_;
91 13   100     55 $opts ||= +{};
92 13   100     114 my $simple = $opts->{simple} || 0;
93              
94 13         29 my @buf;
95              
96 13 100       116 push @buf,
97             (
98             'File: 02packages.details.txt',
99             'URL: http://www.perl.com/CPAN/modules/02packages.details.txt',
100             'Description: DarkPAN',
101             'Columns: package name, version, path',
102             'Intended-For: Automated fetch routines, namespace documentation.',
103             $simple
104             ? ()
105             : (
106             "Written-By: OrePAN2 $OrePAN2::VERSION",
107 9         23 "Line-Count: @{[ scalar(keys %{$self->{index}}) ]}",
  9         77  
108 9         484 "Last-Updated: @{[ scalar localtime ]}",
109             ),
110             '',
111             );
112              
113 13         114 for my $pkg ( $self->packages ) {
114 45         111 my $entry = $self->{index}{$pkg};
115              
116             # package name, version, path
117 45   100     240 push @buf, sprintf '%-22s %-22s %s', $pkg, $entry->[0] || 'undef',
118             $entry->[1];
119             }
120 13         368 return join( "\n", @buf ) . "\n";
121             }
122              
123             1;
124             __END__
125              
126             =head1 NAME
127              
128             OrePAN2::Index - Index
129              
130             =head1 DESCRIPTION
131              
132             This is a module to manipulate 02packages.details.txt.
133              
134             =head1 METHODS
135              
136             =over 4
137              
138             =item C<< my $index = OrePAN2::Index->new(%attr) >>
139              
140             =item C<< $index->load($filename) >>
141              
142             Load an existing 02.packages.details.txt
143              
144             =item C<< my ($version, $path) = $index->lookup($package) >>
145              
146             Perform a package lookup on the index.
147              
148             =item C<< $index->delete_index($package) >>
149              
150             Delete a package from the index.
151              
152             =item C<< $index->add_index($package, $version, $path) >>
153              
154             Add a new entry to the index.
155              
156             =item C<< $index->as_string() >>
157              
158             Returns the content of the index as a string. Some of the index metadata can
159             cause merge conflicts when multiple developers are working on the same project.
160             You can avoid this problem by using a paring down the metadata. "simple"
161             defaults to 0.
162              
163             $index->as_string( simple => 1 );
164              
165             Make index as string.
166              
167             =back