File Coverage

blib/lib/Gentoo/VDB/Portage.pm
Criterion Covered Total %
statement 116 144 80.5
branch 38 74 51.3
condition 6 11 54.5
subroutine 20 27 74.0
pod 0 5 0.0
total 180 261 68.9


line stmt bran cond sub pod time code
1 3     3   82 use 5.006; # our
  3         10  
2 3     3   19 use strict;
  3         5  
  3         90  
3 3     3   15 use warnings;
  3         5  
  3         209  
4              
5             package Gentoo::VDB::Portage;
6              
7             our $VERSION = '0.001001';
8              
9             # ABSTRACT: VDB Query Implementation for Portage/Emerge
10              
11             # AUTHORITY
12              
13 3     3   13 use Path::Tiny qw( path );
  3         11  
  3         6179  
14              
15             sub new {
16 3     3 0 8 my ( $class, @args ) = @_;
17 3 50       16 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  3         17  
18 3         13 return bless $config, $class;
19             }
20              
21             sub _path {
22 148   50 148   809 return ( $_[0]->{path} ||= '/var/db/pkg' );
23             }
24              
25             sub _abspath {
26 67     67   155 my $root = path( $_[0]->_path )->absolute->realpath;
27 67         19302 my $path = path( $_[0]->_path, @_[ 1 .. $#_ ] )->absolute->realpath;
28 67 50       17463 die "Illegal path, outside of VDB" unless $root->subsumes($path);
29 67         5657 return $path->stringify;
30             }
31              
32             sub __dir_iterator {
33 39     39   151 my ($path) = @_;
34 39         44 my $handle;
35 39 50 33 0   2162 ( -d $path and opendir $handle, $path ) or return sub { return undef };
  0         0  
36             return sub {
37 93     93   118 while (1) {
38 139         883 my $dir = readdir $handle;
39 139 100       412 return undef unless defined $dir;
40 116 100 100     417 next if $dir eq '.' or $dir eq '..'; # skip hidden entries
41 70         164 return $dir;
42             }
43 39         192 };
44             }
45              
46             sub _category_iterator {
47 6     6   8 my ($self) = @_;
48 6         14 my $root = $self->_path;
49 0     0   0 return sub { return undef }
50 6 50       195 unless -d $root;
51 6         17 my $_cat_iterator = __dir_iterator($root);
52             return sub {
53 12     12   16 while (1) {
54              
55             # Category possible
56 18         33 my $category = $_cat_iterator->();
57 18 100       62 return undef if not defined $category;
58              
59             # Skip hidden categories
60 12 50       35 next if $category =~ /\A[.]/x;
61              
62             # Validate category to have at least one package with a file
63 12         30 my $_pkg_iterator = __dir_iterator( $self->_abspath($category) );
64 12         59 while ( my $package = $_pkg_iterator->() ) {
65 6 50       26 next if $package =~ /\A[.]/x;
66 6         20 my $_file_iterator =
67             __dir_iterator( $self->_abspath( $category, $package ) );
68 6         21 while ( my $file = $_file_iterator->() ) {
69 6 50       27 next if $file =~ /\A[.]/x;
70             ## Found one package with one file, category is valid
71 6         136 return $category;
72             }
73             }
74             }
75 6         29 };
76             }
77              
78             sub categories {
79 6     6 0 12 my ($self) = @_;
80 6         16 my $it = $self->_category_iterator;
81 6         10 my @cats;
82 6         15 while ( my $entry = $it->() ) {
83 6         21 push @cats, $entry;
84             }
85 6         120 return @cats;
86             }
87              
88             sub _package_iterator {
89 8     8   13 my ( $self, $config ) = @_;
90 8         16 my $root = $self->_path;
91 8 50       27 if ( $config->{in} ) {
92 8         19 my $catdir = $self->_abspath( $config->{in} );
93 2     2   7 return sub { return undef }
94 8 100       204 unless -d $catdir;
95 6         14 my $_pkg_iterator = __dir_iterator($catdir);
96             return sub {
97 10     10   12 while (1) {
98 14         25 my $package = $_pkg_iterator->();
99 14 100       41 return undef if not defined $package;
100 8 50       25 next if $package =~ /\A[.]/x;
101             my $_file_iterator =
102 8         21 __dir_iterator( $self->_abspath( $config->{in}, $package ) );
103 8         22 while ( my $file = $_file_iterator->() ) {
104 4 50       16 next if $file =~ /\A[.]/x;
105             ## Found one package with one file, package is valid
106 4         73 return $config->{in} . '/' . $package;
107             }
108             }
109 6         35 };
110             }
111              
112 0     0   0 return sub { return undef }
113 0 0       0 unless -d $root;
114              
115 0         0 my $_cat_iterator = __dir_iterator($root);
116 0         0 my $category = $_cat_iterator->();
117              
118 0     0   0 return sub { return undef }
119 0 0       0 unless defined $category;
120              
121 0         0 my $_pkg_iterator = __dir_iterator( $self->_abspath($category) );
122              
123             return sub {
124 0     0   0 while (1) {
125 0 0       0 return undef if not defined $category;
126 0         0 my $package = $_pkg_iterator->();
127 0 0       0 if ( not defined $package ) {
128 0         0 $category = $_cat_iterator->();
129 0 0       0 return undef if not defined $category;
130 0 0       0 if ( defined $category ) {
131 0         0 $_pkg_iterator =
132             __dir_iterator( $self->_abspath($category) );
133 0         0 next;
134             }
135 0         0 next;
136             }
137 0 0       0 next if $package =~ /\A[.]/x;
138 0         0 my $_file_iterator =
139             __dir_iterator( $self->_abspath( $category, $package ) );
140 0         0 while ( my $file = $_file_iterator->() ) {
141 0 0       0 next if $file =~ /\A[.]/x;
142             ## Found one package with one file, package is valid
143 0         0 return $category . '/' . $package;
144             }
145             }
146 0         0 };
147             }
148              
149             sub packages {
150 8     8 0 19 my ( $self, @args ) = @_;
151 8 50       22 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  8         33  
152 8         24 my $iterator = $self->_package_iterator($config);
153 8         10 my (@packages);
154 8         16 while ( my $result = $iterator->() ) {
155 4         18 push @packages, $result;
156             }
157 8         121 return @packages;
158             }
159              
160             sub _property_files_iterator {
161 1     1   2 my ( $self, $config ) = @_;
162 0     0   0 return sub { undef }
163 1 50       5 unless $config->{'for'};
164 1         3 my $catdir = $self->_abspath( $config->{'for'} );
165 0     0   0 return sub { undef }
166 1 50       31 unless -d $catdir;
167 1         3 my $iterator = __dir_iterator($catdir);
168             return sub {
169              
170 35     35   24 while (1) {
171 35         41 my $file = $iterator->();
172 35 100       52 return undef if not defined $file;
173 34 50       60 next if $file =~ /\A[.]/x;
174 34         65 return $file;
175             }
176 1         5 };
177             }
178              
179             my $ENATIVE = {
180             BUILD_TIME => 'timestamp',
181             CATEGORY => 'string',
182             CBUILD => 'string',
183             CC => 'string',
184             CFLAGS => 'string',
185             CHOST => 'string',
186             CONTENTS => 'contents',
187             COUNTER => 'number',
188             CTARGET => 'string',
189             CXX => 'string',
190             CXXFLAGS => 'string',
191             DEBUGBUILD => 'flag-file',
192             DEFINED_PHASES => 'space-separated-list',
193             DEPEND => 'dependencies',
194             DESCRIPTION => 'string',
195             EAPI => 'string',
196             FEATURES => 'use-list',
197             'environment.bz2' => {
198             type => 'file',
199             encoding => 'application/x-bzip2',
200             content => 'text/plain'
201             },
202             HOMEPAGE => 'url-list',
203             INHERITED => 'space-separated-list',
204             IUSE => 'use-list',
205             IUSE_EFFECTIVE => 'use-list',
206             KEYWORDS => 'keywords',
207             LDFLAGS => 'string',
208             LICENSE => 'licenses',
209             NEEDED => 'elf-dependency-map',
210             'NEEDED.ELF.2' => 'arch-elf-dependency-map',
211             PDEPEND => 'dependencies',
212             PF => 'string',
213             PKGUSE => 'use-list',
214             PROVIDES => 'arch-so-map',
215             QA_CONFIGURE_OPTIONS => 'string',
216             QA_PREBUILT => 'space-separated-list',
217             RDEPEND => 'dependencies',
218             repository => 'string',
219             REQUIRES => 'arch-so-map',
220             REQUIRES_EXCLUDE => 'space-separated-list',
221             RESTRICT => 'space-seperated-list',
222             SIZE => 'bytecount',
223             SLOT => 'string',
224             USE => 'use-list',
225             };
226              
227             my @ERULES = (
228             [
229             sub { $_[0] =~ /\.ebuild\z/ },
230             {
231             label => 'special:source_ebuild',
232             type => 'file',
233             content => 'text/plain'
234             }
235             ],
236             );
237              
238             sub properties {
239 1     1 0 3 my ( $self, @args ) = @_;
240 1 50       6 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  1         4  
241 1         3 my (@proplist);
242 1         4 my $it = $self->_property_files_iterator($config);
243 1         4 while ( my $entry = $it->() ) {
244 34         24 my $matched = 0;
245 34 100       58 if ( exists $ENATIVE->{$entry} ) {
246 33         27 $matched = 1;
247             push @proplist,
248             {
249             property => $entry,
250             label => $entry,
251             for => $config->{for},
252             (
253             ref $ENATIVE->{$entry}
254 1         8 ? %{ $ENATIVE->{$entry} }
255 33 100       148 : ( type => $ENATIVE->{$entry} )
256             ),
257             };
258             }
259 34         45 for my $rule (@ERULES) {
260 34 100       55 next unless $rule->[0]->($entry);
261 1         2 $matched = 1;
262             push @proplist,
263             {
264             property => $entry,
265             label => $entry,
266             for => $config->{for},
267             (
268             ref $rule->[1]
269 1 50       6 ? %{ $rule->[1] }
  1         8  
270             : ( type => $rule->[1] )
271             ),
272             };
273             }
274 34 50       76 if ( not $matched ) {
275             push @proplist,
276             {
277             property => $entry,
278             label => 'unknown:' . $entry,
279             for => $config->{for},
280 0         0 type => 'file',
281             content => 'application/octet-stream',
282             };
283             }
284             }
285 1         24 return @proplist;
286             }
287              
288             sub get_property {
289 32     32 0 72 my ( $self, @args ) = @_;
290 32 50       87 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  32         184  
291             return undef
292 32 50 33     161 unless exists $config->{for} and exists $config->{property};
293 32         28 my $content;
294             open my $fh, '<', $self->_abspath( $config->{for}, $config->{property} )
295 32 50       174 or return undef;
296             {
297 32         1406 local $/ = undef;
  32         157  
298 32         733 $content = <$fh>;
299             }
300 32         359 close $fh;
301 32         55 chomp $content;
302 32         219 return $content;
303             }
304              
305             1;
306              
307             =head1 NAME
308              
309             Gentoo::VDB::Portage - VDB Query Implementation for Portage/Emerge
310              
311             =head1 AUTHOR
312              
313             Kent Fredric
314              
315             =head1 LICENSE
316              
317             This software is copyright (c) 2016 by Kent Fredric.
318              
319             This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
320              
321             =cut
322              
323             ## Please see file perltidy.ERR