File Coverage

blib/lib/Dist/Data.pm
Criterion Covered Total %
statement 117 129 90.7
branch 31 44 70.4
condition 12 15 80.0
subroutine 25 28 89.2
pod 0 9 0.0
total 185 225 82.2


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