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   61 use 5.006; # our
  3         8  
2 3     3   12 use strict;
  3         4  
  3         58  
3 3     3   10 use warnings;
  3         4  
  3         152  
4              
5             package Gentoo::VDB::Portage;
6              
7             our $VERSION = '0.001002';
8              
9             # ABSTRACT: VDB Query Implementation for Portage/Emerge
10              
11             # AUTHORITY
12              
13 3     3   14 use Path::Tiny 0.048 qw( path ); # subsumes
  3         50  
  3         4214  
14              
15             sub new {
16 3     3 0 6 my ( $class, @args ) = @_;
17 3 50       10 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  3         9  
18 3         8 return bless $config, $class;
19             }
20              
21             sub _path {
22 148   50 148   601 return ( $_[0]->{path} ||= '/var/db/pkg' );
23             }
24              
25             sub _abspath {
26 67     67   121 my $root = path( $_[0]->_path )->absolute->realpath;
27 67         13289 my $path = path( $_[0]->_path, @_[ 1 .. $#_ ] )->absolute->realpath;
28 67 50       13146 die "Illegal path, outside of VDB" unless $root->subsumes($path);
29 67         4559 return $path->stringify;
30             }
31              
32             sub __dir_iterator {
33 39     39   101 my ($path) = @_;
34 39         28 my $handle;
35 39 50 33 0   1386 ( -d $path and opendir $handle, $path ) or return sub { return undef };
  0         0  
36             return sub {
37 93     93   89 while (1) {
38 139         590 my $dir = readdir $handle;
39 139 100       295 return undef unless defined $dir;
40 116 100 100     320 next if $dir eq '.' or $dir eq '..'; # skip hidden entries
41 70         109 return $dir;
42             }
43 39         131 };
44             }
45              
46             sub _category_iterator {
47 6     6   7 my ($self) = @_;
48 6         10 my $root = $self->_path;
49 0     0   0 return sub { return undef }
50 6 50       104 unless -d $root;
51 6         10 my $_cat_iterator = __dir_iterator($root);
52             return sub {
53 12     12   12 while (1) {
54              
55             # Category possible
56 18         21 my $category = $_cat_iterator->();
57 18 100       40 return undef if not defined $category;
58              
59             # Skip hidden categories
60 12 50       26 next if $category =~ /\A[.]/x;
61              
62             # Validate category to have at least one package with a file
63 12         18 my $_pkg_iterator = __dir_iterator( $self->_abspath($category) );
64 12         32 while ( my $package = $_pkg_iterator->() ) {
65 6 50       16 next if $package =~ /\A[.]/x;
66 6         11 my $_file_iterator =
67             __dir_iterator( $self->_abspath( $category, $package ) );
68 6         10 while ( my $file = $_file_iterator->() ) {
69 6 50       13 next if $file =~ /\A[.]/x;
70             ## Found one package with one file, category is valid
71 6         115 return $category;
72             }
73             }
74             }
75 6         19 };
76             }
77              
78             sub categories {
79 6     6 0 8 my ($self) = @_;
80 6         8 my $it = $self->_category_iterator;
81 6         6 my @cats;
82 6         9 while ( my $entry = $it->() ) {
83 6         15 push @cats, $entry;
84             }
85 6         77 return @cats;
86             }
87              
88             sub _package_iterator {
89 8     8   6 my ( $self, $config ) = @_;
90 8         13 my $root = $self->_path;
91 8 50       19 if ( $config->{in} ) {
92 8         13 my $catdir = $self->_abspath( $config->{in} );
93 2     2   6 return sub { return undef }
94 8 100       132 unless -d $catdir;
95 6         12 my $_pkg_iterator = __dir_iterator($catdir);
96             return sub {
97 10     10   11 while (1) {
98 14         17 my $package = $_pkg_iterator->();
99 14 100       30 return undef if not defined $package;
100 8 50       16 next if $package =~ /\A[.]/x;
101             my $_file_iterator =
102 8         17 __dir_iterator( $self->_abspath( $config->{in}, $package ) );
103 8         17 while ( my $file = $_file_iterator->() ) {
104 4 50       10 next if $file =~ /\A[.]/x;
105             ## Found one package with one file, package is valid
106 4         48 return $config->{in} . '/' . $package;
107             }
108             }
109 6         22 };
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 10 my ( $self, @args ) = @_;
151 8 50       20 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  8         24  
152 8         16 my $iterator = $self->_package_iterator($config);
153 8         10 my (@packages);
154 8         11 while ( my $result = $iterator->() ) {
155 4         10 push @packages, $result;
156             }
157 8         80 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       3 unless $config->{'for'};
164 1         3 my $catdir = $self->_abspath( $config->{'for'} );
165 0     0   0 return sub { undef }
166 1 50       16 unless -d $catdir;
167 1         3 my $iterator = __dir_iterator($catdir);
168             return sub {
169              
170 35     35   21 while (1) {
171 35         35 my $file = $iterator->();
172 35 100       44 return undef if not defined $file;
173 34 50       48 next if $file =~ /\A[.]/x;
174 34         48 return $file;
175             }
176 1         4 };
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       4 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  1         3  
241 1         2 my (@proplist);
242 1         3 my $it = $self->_property_files_iterator($config);
243 1         3 while ( my $entry = $it->() ) {
244 34         26 my $matched = 0;
245 34 100       51 if ( exists $ENATIVE->{$entry} ) {
246 33         20 $matched = 1;
247             push @proplist,
248             {
249             property => $entry,
250             label => $entry,
251             for => $config->{for},
252             (
253             ref $ENATIVE->{$entry}
254 1         6 ? %{ $ENATIVE->{$entry} }
255 33 100       118 : ( type => $ENATIVE->{$entry} )
256             ),
257             };
258             }
259 34         33 for my $rule (@ERULES) {
260 34 100       39 next unless $rule->[0]->($entry);
261 1         1 $matched = 1;
262             push @proplist,
263             {
264             property => $entry,
265             label => $entry,
266             for => $config->{for},
267             (
268             ref $rule->[1]
269 1 50       5 ? %{ $rule->[1] }
  1         5  
270             : ( type => $rule->[1] )
271             ),
272             };
273             }
274 34 50       65 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         15 return @proplist;
286             }
287              
288             sub get_property {
289 32     32 0 66 my ( $self, @args ) = @_;
290 32 50       72 my $config = { ref $args[0] ? %{ $args[0] } : @args };
  32         171  
291             return undef
292 32 50 33     147 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       147 or return undef;
296             {
297 32         1365 local $/ = undef;
  32         131  
298 32         638 $content = <$fh>;
299             }
300 32         199 close $fh;
301 32         43 chomp $content;
302 32         200 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