File Coverage

blib/lib/Dist/Data.pm
Criterion Covered Total %
statement 116 128 90.6
branch 31 44 70.4
condition 12 15 80.0
subroutine 24 27 88.8
pod 0 9 0.0
total 183 223 82.0


line stmt bran cond sub pod time code
1             package Dist::Data;
2             our $AUTHORITY = 'cpan:GETTY';
3             # ABSTRACT: API to access the data of a Perl distribution file or directory
4             $Dist::Data::VERSION = '0.006';
5 3     3   96218 use Moo;
  3         45536  
  3         19  
6 3     3   5921 use Archive::Any;
  3         80010  
  3         96  
7 3     3   1736 use CPAN::Meta;
  3         72152  
  3         113  
8 3     3   1766 use File::Temp;
  3         22899  
  3         292  
9 3     3   2073 use File::Find::Object;
  3         32131  
  3         111  
10 3     3   2301 use Module::Extract::Namespaces;
  3         375304  
  3         121  
11 3     3   1934 use DateTime::Format::Epoch::Unix;
  3         480749  
  3         120  
12 3     3   1640 use Dist::Metadata ();
  3         4624  
  3         3860  
13              
14             has filename => (
15             is => 'ro',
16             predicate => 'has_filename',
17             );
18              
19             has archive => (
20             is => 'ro',
21             lazy => 1,
22             builder => '_build_archive',
23             );
24              
25             sub _build_archive {
26 2     2   694 my ( $self ) = @_;
27 2 50       11 die __PACKAGE__.": need a filename" unless $self->has_filename;
28 2         23 return Archive::Any->new($self->filename);
29             }
30              
31             has cpan_meta => (
32             is => 'ro',
33             lazy => 1,
34             builder => '_build_cpan_meta',
35             handles => [qw(
36             abstract
37             description
38             dynamic_config
39             generated_by
40             name
41             release_status
42             version
43             authors
44             keywords
45             licenses
46             meta_spec
47             resources
48             provides
49             no_index
50             prereqs
51             optional_features
52             )]
53             );
54 3     3 0 83041 sub cm { shift->cpan_meta(@_) }
55              
56             # LEGACY
57 0     0 0 0 sub distmeta { shift->cpan_meta(@_) }
58              
59             sub _build_cpan_meta {
60 2     2   2087 my ( $self ) = @_;
61 2 50       28 if ($self->files->{'META.json'}) {
    0          
62 2         59 CPAN::Meta->load_file($self->files->{'META.json'});
63             } elsif ($self->files->{'META.yml'}) {
64 0         0 CPAN::Meta->load_file($self->files->{'META.yml'});
65             }
66             }
67              
68             has dist_metadata => (
69             is => 'ro',
70             lazy => 1,
71             builder => '_build_dist_metadata',
72             );
73              
74             sub _build_dist_metadata {
75 2     2   682 my ( $self ) = @_;
76 2         11 $self->extract_distribution;
77 2         54 Dist::Metadata->new(dir => $self->dist_dir);
78             }
79              
80             has dir => (
81             is => 'ro',
82             predicate => 'has_dir',
83             );
84              
85             sub dir_has_dist {
86 3     3 0 4 my ( $self ) = @_;
87 3         27 my $dir = $self->dist_dir;
88 3 50       613 return unless -d $dir;
89 3         90 return -f "$dir/Makefile.PL";
90             }
91              
92             has files => (
93             is => 'ro',
94             lazy => 1,
95             builder => '_build_files',
96             );
97              
98             sub _build_files {
99 2     2   1543 my ( $self ) = @_;
100 2         11 $self->extract_distribution;
101 2         1636 my %files;
102 2         70 for ($self->get_directory_tree($self->dist_dir)) {
103 36 100       258 $files{join('/',@{$_->full_components})} = $_->path if $_->is_file;
  24         46  
104             }
105 2         89 return \%files;
106             }
107              
108             has dirs => (
109             is => 'ro',
110             lazy => 1,
111             builder => '_build_dirs',
112             );
113              
114             sub _build_dirs {
115 0     0   0 my ( $self ) = @_;
116 0         0 $self->extract_distribution;
117 0         0 my %dirs;
118 0         0 for ($self->get_directory_tree($self->dist_dir)) {
119 0 0       0 $dirs{join('/',@{$_->full_components})} = $_->path if $_->is_dir;
  0         0  
120             }
121 0         0 return \%dirs;
122             }
123              
124             has dist_dir => (
125             is => 'ro',
126             lazy => 1,
127             builder => '_build_dist_dir',
128             );
129              
130             sub _build_dist_dir {
131 3     3   688 my ( $self ) = @_;
132 3 100       36 return $self->has_dir ? $self->dir : File::Temp->newdir;
133             }
134              
135             sub extract_distribution {
136 5     5 0 13 my ( $self ) = @_;
137 5 100       27 return unless $self->has_filename;
138 3 100       11 return if $self->dir_has_dist;
139 2         30 my $ext_dir = File::Temp->newdir;
140 2         584 $self->archive->extract($ext_dir);
141 2         352897 for ($self->get_directory_tree($ext_dir)) {
142 38         2481 my @components = @{$_->full_components};
  38         131  
143 38         376 shift @components;
144 38 100       91 if ($_->is_dir) {
145 14         416 mkdir $self->dist_dir.'/'.join('/',@components);
146             } else {
147 24         703 rename $_->path, $self->dist_dir.'/'.join('/',@components);
148             }
149             }
150 2         295 return 1;
151             }
152              
153             has packages => (
154             is => 'ro',
155             lazy => 1,
156             builder => '_build_packages',
157             );
158              
159             sub _build_packages {
160 2     2   7430 my ( $self ) = @_;
161 2         10 return $self->dist_metadata->determine_packages($self->cm);
162             # OLD - probably reused later if we introduce behaviour switches
163             # my %packages;
164             # for (keys %{$self->files}) {
165             # my $key = $_;
166             # my @components = split('/',$key);
167             # if ($key =~ /\.pm$/) {
168             # my @namespaces = Module::Extract::Namespaces->from_file($self->files->{$key});
169             # for (@namespaces) {
170             # $packages{$_} = [] unless defined $packages{$_};
171             # push @{$packages{$_}}, $key;
172             # }
173             # } elsif ($key =~ /^lib\// && $key =~ /\.pod$/) {
174             # my $packagename = $key;
175             # $packagename =~ s/^lib\///g;
176             # $packagename =~ s/\.pod$//g;
177             # $packagename =~ s/\//::/g;
178             # $packages{$packagename} = [] unless defined $packages{$packagename};
179             # push @{$packages{$packagename}}, $key;
180             # }
181             # }
182             # return \%packages;
183             }
184              
185             has namespaces => (
186             is => 'ro',
187             lazy => 1,
188             builder => '_build_namespaces',
189             );
190              
191             sub _build_namespaces {
192 1     1   330 my ( $self ) = @_;
193 1         1 my %namespaces;
194 1         2 for (keys %{$self->files}) {
  1         17  
195 12         18 my $key = $_;
196 12 100 66     44 if ($key =~ /\.pm$/ || $key =~ /\.pl$/) {
197 1         20 my @namespaces = Module::Extract::Namespaces->from_file($self->files->{$key});
198 1         12225 for (@namespaces) {
199 1 50       5 next unless defined $_;
200 1 50       4 $namespaces{$_} = [] unless defined $namespaces{$_};
201 1         1 push @{$namespaces{$_}}, $key;
  1         5  
202             }
203             }
204             }
205 1         12 return \%namespaces;
206             }
207              
208             has documentations => (
209             is => 'ro',
210             lazy => 1,
211             builder => '_build_documentations',
212             );
213              
214             sub _build_documentations {
215 1     1   33484 my ( $self ) = @_;
216 1         2 my %docs;
217 1         2 for (keys %{$self->files}) {
  1         19  
218 12         18 my $key = $_;
219 12 100 100     35 if ($key =~ /^lib\// && $key =~ /\.pod$/) {
220 1         3 my $packagename = $key;
221 1         4 $packagename =~ s/^lib\///g;
222 1         4 $packagename =~ s/\.pod$//g;
223 1         3 $packagename =~ s/\//::/g;
224 1         3 $docs{$packagename} = $key;
225             }
226             }
227 1         8 return \%docs;
228             }
229              
230             has scripts => (
231             is => 'ro',
232             lazy => 1,
233             builder => '_build_scripts',
234             );
235              
236             sub _build_scripts {
237 1     1   450 my ( $self ) = @_;
238 1         5 my %scripts;
239 1         2 for (keys %{$self->files}) {
  1         27  
240 12 100 66     49 next unless $_ =~ /^bin\// || $_ =~ /^script\//;
241 1         3 my $key = $_;
242 1         4 my @components = split('/',$key);
243 1         2 shift @components;
244 1         4 $scripts{join('/',@components)} = $key;
245             }
246 1         7 return \%scripts;
247             }
248              
249             sub get_directory_tree {
250 4     4 0 27 my ( $self, @dirs ) = @_;
251 4         68 my $tree = File::Find::Object->new({}, @dirs);
252 4         1267 my @files;
253 4         26 while (my $r = $tree->next_obj()) {
254 74         16104 push @files, $r;
255             }
256 4         665 return @files;
257             }
258              
259             sub file {
260 4     4 0 91777 my ( $self, $file ) = @_;
261 4         103 return $self->files->{$file};
262             }
263              
264             sub modified {
265 0     0 0 0 my ( $self ) = @_;
266 0 0       0 my $mtime = stat($self->has_filename ? $self->filename : $self->dir )->mtime;
267 0         0 return DateTime::Format::Epoch::Unix->parse_datetime($mtime);
268             }
269              
270             sub BUILD {
271 3     3 0 104 my ( $self ) = @_;
272 3 100 100     70 $self->extract_distribution if $self->has_dir && $self->has_filename;
273             }
274              
275             sub BUILDARGS {
276 3     3 0 11347 my ( $class, @args ) = @_;
277 3 50       17 die __PACKAGE__.": please give filename on new" if !@args;
278 3 100 66     8 my $arg; $arg = shift @args if @args % 2 == 1 && ref $args[0] ne 'HASH';
  3         39  
279 3 100       9 if ($arg) {
280             # should support URL also
281 2 100       70 if (-f $arg) {
    50          
282 1         22 return { filename => $arg, @args };
283             } elsif (-d $arg) {
284 1         34 return { dir => $arg, @args };
285             }
286             }
287 1         8 return $class->SUPER::BUILDARGS(@args);
288             }
289              
290             1;
291              
292             __END__