File Coverage

lib/Gentoo/Overlay.pm
Criterion Covered Total %
statement 118 121 97.5
branch 13 16 81.2
condition 6 9 66.6
subroutine 27 27 100.0
pod 2 2 100.0
total 166 175 94.8


line stmt bran cond sub pod time code
1 4     4   50897 use 5.006;
  4         10  
  4         122  
2 4     4   12 use strict;
  4         5  
  4         93  
3 4     4   11 use warnings;
  4         5  
  4         203  
4              
5             package Gentoo::Overlay;
6              
7             our $VERSION = '2.001000';
8              
9             # ABSTRACT: Tools for working with Gentoo Overlays
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 4     4   1871 use Moo qw( has );
  4         44875  
  4         20  
14 4     4   6682 use MooX::HandlesVia;
  4         2101  
  4         17  
15 4     4   1902 use MooseX::Has::Sugar qw( ro coerce lazy_build lazy );
  4         1958  
  4         25  
16 4     4   2380 use Types::Standard qw( HashRef CodeRef );
  4         212484  
  4         47  
17 4     4   4620 use Types::Path::Tiny qw( File Dir );
  4         111278  
  4         44  
18 4     4   3487 use MooX::ClassAttribute qw( class_has );
  4         45335  
  4         20  
19 4     4   295 use Carp qw();
  4         11  
  4         60  
20 4     4   1590 use Gentoo::Overlay::Category;
  4         11  
  4         150  
21 4     4   26 use Gentoo::Overlay::Types qw( Gentoo__Overlay_RepositoryName Gentoo__Overlay_Category );
  4         5  
  4         46  
22 4     4   2517 use Gentoo::Overlay::Exceptions qw( exception warning );
  4         8  
  4         29  
23 4     4   418 use namespace::clean -except => 'meta';
  4         5  
  4         39  
24              
25              
26              
27              
28              
29              
30              
31              
32              
33              
34              
35             has 'path' => (
36             ro, coerce,
37             isa => Dir,
38             default => sub {
39             exception(
40             ident => 'path parameter required',
41             message => '%{package}s requires the \'path\' attribute passed during construction',
42             payload => { package => __PACKAGE__ },
43             );
44             },
45             );
46              
47              
48              
49              
50              
51              
52              
53              
54              
55              
56              
57              
58              
59             has 'name' => ( isa => Gentoo__Overlay_RepositoryName, ro, lazy, builder => 1, );
60              
61              
62              
63              
64              
65              
66              
67              
68              
69              
70              
71              
72             sub _build_name {
73 6     6   3729 my ($self) = shift;
74 6         21 my $f = $self->default_path( repo_name => );
75 6 100 66     454 if ( not $f->exists or $f->is_dir ) {
76 1         22 exception(
77             ident => 'no repo_name',
78             message => <<'EOF',
79             No repo_name file for overlay at: %{overlay_path}s
80             Expects:%{expected_path}s
81             EOF
82             payload => {
83             overlay_path => $self->path->stringify,
84             expected_path => $f->stringify,
85             },
86             );
87             }
88 5         200 return [ $f->lines_raw( { chomp => 1 } ) ]->[0];
89              
90             }
91              
92              
93              
94              
95              
96              
97              
98              
99              
100              
101              
102              
103              
104             has _profile_dir => ( isa => Dir, ro, lazy, builder => 1 );
105              
106              
107              
108              
109              
110              
111              
112              
113              
114              
115              
116             sub _build__profile_dir {
117 12     12   8659 my ($self) = shift;
118 12         40 my $pd = $self->default_path( profiles => );
119 12 100 66     318 if ( not $pd->exists or not $pd->is_dir ) {
120 1         27 exception(
121             ident => 'no profile directory',
122             message => <<'EOF',
123             No profile directory for overlay at: %{overlay_path}s
124             Expects:%{expected_path}s
125             EOF
126             payload => {
127             overlay_path => $self->path->stringify,
128             expected_path => $pd->stringify,
129             },
130             );
131             }
132 11         446 return $pd->absolute;
133             }
134              
135              
136              
137              
138              
139              
140              
141              
142              
143              
144              
145              
146              
147              
148              
149              
150              
151              
152              
153              
154              
155              
156              
157              
158              
159              
160              
161              
162              
163              
164              
165              
166              
167              
168              
169              
170              
171              
172              
173              
174              
175              
176              
177              
178              
179              
180              
181              
182              
183              
184              
185              
186              
187              
188              
189              
190              
191              
192              
193              
194              
195              
196              
197              
198             has _categories => (
199             lazy,
200             builder => 1,
201             ro,
202             isa => HashRef [Gentoo__Overlay_Category],
203             handles_via => 'Hash',
204             handles => {
205             _has_category => exists =>,
206             category_names => keys =>,
207             categories => elements =>,
208             get_category => get =>,
209             },
210             );
211              
212              
213              
214              
215              
216              
217              
218              
219              
220              
221              
222              
223              
224              
225              
226              
227             sub _build__categories {
228 7     7   10672 my ($self) = @_;
229 7         28 my $cf = $self->default_path('catfile');
230 7 100 66     989 if ( not $cf->exists or $cf->is_dir ) {
231 2         75 warning(
232             ident => 'no category file',
233             message => <<'EOF',
234             No category file for overlay %{name}s, expected: %{category_file}s.
235             Falling back to scanning
236             EOF
237             payload => {
238             name => $self->name,
239             category_file => $cf->stringify,
240             },
241             );
242 1         1146 goto $self->can('_build___categories_scan');
243             }
244 5         196 goto $self->can('_build___categories_file');
245             }
246              
247              
248              
249              
250              
251              
252              
253              
254              
255              
256             class_has _default_paths => (
257             ro, lazy,
258             isa => HashRef [CodeRef],
259             default => sub {
260             return {
261             'profiles' => sub { shift->path->child('profiles') },
262             'repo_name' => sub { shift->_profile_dir->child('repo_name') },
263             'catfile' => sub { shift->_profile_dir->child('categories') },
264             'category' => sub { shift->path->child(shift) },
265             'package' => sub { shift->default_path( 'category', shift )->child(shift) },
266             'ebuild' => sub { shift->default_path( 'package', shift, shift )->child(shift) },
267             };
268             },
269             );
270              
271              
272              
273              
274              
275              
276              
277              
278              
279              
280              
281              
282              
283              
284              
285              
286              
287              
288              
289              
290              
291              
292              
293              
294              
295              
296              
297              
298             sub default_path {
299 55     55 1 2432 my ( $self, $name, @args ) = @_;
300 55 50       881 if ( !exists $self->_default_paths->{$name} ) {
301 0         0 exception(
302             ident => 'no default path',
303             message => q[No default path '%{name}s'],
304             payload => { path => $name },
305             );
306             }
307 55         1158 return $self->_default_paths->{$name}->( $self, @args );
308             }
309              
310              
311              
312              
313              
314              
315              
316              
317              
318             sub _build___categories_file {
319 5     5   8 my ($self) = shift;
320 5         7 my %out;
321 5         9 for my $cat ( $self->default_path('catfile')->lines_raw( { chomp => 1 } ) ) {
322 11         964 my $category = Gentoo::Overlay::Category->new(
323             name => $cat,
324             overlay => $self,
325             );
326 11 100       1816 if ( !$category->exists ) {
327 1         84 exception(
328             ident => 'missing category',
329             message => <<'EOF',
330             category %{category_name}s is not an existing directory (%{expected_path}s) for overlay %{overlay_name}s
331             EOF
332             payload => {
333             category_name => $category->name,
334             expected_path => $category->path->stringify,
335             overlay_name => $self->name,
336             },
337             );
338 0         0 next;
339             }
340 10         26 $out{$cat} = $category;
341             }
342 4         78 return \%out;
343             }
344              
345              
346              
347              
348              
349              
350              
351              
352              
353              
354             sub _build___categories_scan {
355 1     1   3 my ($self) = shift;
356 1         1 my %out;
357 1         7 my $it = $self->path->absolute->iterator();
358 1         48 while ( my $entry = $it->() ) {
359 3         266 my $cat = $entry->basename;
360 3 100       62 next if Gentoo::Overlay::Category->is_blacklisted($cat);
361              
362 1         11 my $category = Gentoo::Overlay::Category->new(
363             overlay => $self,
364             name => $cat,
365             );
366 1 50       827 next unless $category->exists();
367 1         6 $out{$cat} = $category;
368             }
369 1         51 return \%out;
370              
371             }
372              
373              
374              
375              
376              
377              
378              
379              
380              
381              
382              
383              
384              
385              
386              
387              
388              
389              
390              
391              
392              
393              
394              
395              
396              
397              
398              
399              
400              
401              
402              
403              
404              
405              
406              
407              
408              
409              
410              
411              
412              
413              
414              
415              
416              
417              
418              
419              
420              
421              
422              
423              
424              
425              
426              
427              
428              
429              
430              
431              
432              
433              
434             sub iterate {
435 3     3 1 7077 my ( $self, $what, $callback ) = @_; ## no critic (Variables::ProhibitUnusedVarsStricter)
436              
437 3         14 my %method_map = (
438             categories => _iterate_categories =>,
439             packages => _iterate_packages =>,
440             ebuilds => _iterate_ebuilds =>,
441             );
442 3 50       8 if ( exists $method_map{$what} ) {
443 3         17 goto $self->can( $method_map{$what} );
444             }
445 0         0 return exception(
446             ident => 'bad iteration method',
447             message => 'The iteration method %{what_method}s is not a known way to iterate.',
448             payload => { what_method => $what, },
449             );
450             }
451              
452              
453              
454              
455              
456              
457              
458              
459              
460              
461              
462             # ebuilds = { /categories/packages/ebuilds }
463             sub _iterate_ebuilds {
464 1     1   1 my ( $self, undef, $callback ) = @_;
465              
466             my $real_callback = sub {
467 1     1   2 my (%cconfig) = %{ $_[1] };
  1         5  
468             my $inner_callback = sub {
469 1         2 my %pconfig = %{ $_[1] };
  1         4  
470 1         12 $self->$callback( { ( %cconfig, %pconfig ) } );
471 1         6 };
472 1         5 $cconfig{package}->_iterate_ebuilds( 'ebuilds' => $inner_callback );
473 1         5 };
474              
475 1         3 $self->_iterate_packages( 'packages' => $real_callback );
476 1         6 return;
477              
478             }
479              
480              
481              
482              
483              
484              
485              
486              
487              
488              
489              
490             # categories = { /categories }
491             sub _iterate_categories {
492 3     3   3 my ( $self, undef, $callback ) = @_;
493 3         31 my %categories = $self->categories();
494 3         153 my $num_categories = scalar keys %categories;
495 3         6 my $last_category = $num_categories - 1;
496 3         4 my $offset = 0;
497 3         10 for my $cname ( sort keys %categories ) {
498 6         10 local $_ = $categories{$cname};
499 6         32 $self->$callback(
500             {
501             category_name => $cname,
502             category => $categories{$cname},
503             num_categories => $num_categories,
504             last_category => $last_category,
505             category_num => $offset,
506             }
507             );
508 6         23 $offset++;
509             }
510 3         10 return;
511             }
512              
513              
514              
515              
516              
517              
518              
519              
520              
521              
522              
523             # packages = { /categories/packages }
524             sub _iterate_packages {
525 2     2   7 my ( $self, undef, $callback ) = @_;
526              
527             my $real_callback = sub {
528 4     4   7 my (%cconfig) = %{ $_[1] };
  4         15  
529             my $inner_callback = sub {
530 1         1 my %pconfig = %{ $_[1] };
  1         3  
531 1         13 $self->$callback( { ( %cconfig, %pconfig ) } );
532 4         22 };
533 4         17 $cconfig{category}->_iterate_packages( 'packages' => $inner_callback );
534 2         9 };
535 2         7 $self->_iterate_categories( 'categories' => $real_callback );
536 2         10 return;
537             }
538 4     4   5112 no Moo;
  4         6  
  4         22  
539             1;
540              
541             __END__
542              
543             =pod
544              
545             =encoding UTF-8
546              
547             =head1 NAME
548              
549             Gentoo::Overlay - Tools for working with Gentoo Overlays
550              
551             =head1 VERSION
552              
553             version 2.001000
554              
555             =head1 SYNOPSIS
556              
557             my $overlay = Gentoo::Overlay->new( path => '/usr/portage' );
558              
559             my $name = $overlay->name();
560             my %categories = $overlay->categories();
561              
562             print "Overlay $name 's categories:\n";
563             for( sort keys %categories ){
564             printf "%30s : %s", $_, $categories{$_};
565             }
566              
567             # Overlay gentoo 's categories:
568             # .....
569             # dev-lang : /usr/portage/dev-lang
570             # .....
571              
572             There will be more features eventually, this is just a first release.
573              
574             =head1 METHODS
575              
576             =head2 default_path
577              
578             Useful function to easily wrap the class-wide method with a per-object sugar.
579              
580             $overlay->default_path('profiles');
581             ->
582             ::Overlay->_default_paths->{'profiles'}->($overlay);
583             ->
584             $overlay->path->subdir('profiles')
585              
586              
587             $overlay->default_path('category','foo');
588             ->
589             ::Overlay->_default_path('category')->( $overlay, 'foo' );
590             ->
591             $overlay->path->subdir('foo')
592              
593             $overlay->default_path('repo_name');
594             ->
595             ::Overlay->_default_path('repo_name')->( $overlay );
596             ->
597             $overlay->_profile_dir->file('repo_name')
598              
599             They're class wide functions, but they need individual instances to work.
600              
601             =head2 iterate
602              
603             $overlay->iterate( $what, sub {
604             my ( $context_information ) = shift;
605              
606             } );
607              
608             The iterate method provides a handy way to do walking across the whole tree stopping at each of a given type.
609              
610             =over 4
611              
612             =item * C<$what = 'categories'>
613              
614             $overlay->iterate( categories => sub {
615             my ( $self, $c ) = shift;
616             # $c->{category_name} # String
617             # $c->{category} # Category Object
618             # $c->{num_categories} # How many categories are there to iterate
619             # $c->{last_category} # Index ID of the last category.
620             # $c->{category_num} # Index ID of the current category.
621             } );
622              
623             =item * C<$what = 'packages'>
624              
625             $overlay->iterate( packages => sub {
626             my ( $self, $c ) = shift;
627             # $c->{category_name} # String
628             # $c->{category} # Category Object
629             # $c->{num_categories} # How many categories are there to iterate
630             # $c->{last_category} # Index ID of the last category.
631             # $c->{category_num} # Index ID of the current category.
632             #
633             # $c->{package_name} # String
634             # See ::Category for the rest of the fields provided by the package Iterator.
635             # Very similar though.
636             } );
637              
638             =item * C<$what = 'ebuilds'>
639              
640             $overlay->iterate( ebuilds => sub {
641             my ( $self, $c ) = shift;
642             # $c->{category_name} # String
643             # $c->{category} # Category Object
644             # $c->{num_categories} # How many categories are there to iterate
645             # $c->{last_category} # Index ID of the last category.
646             # $c->{category_num} # Index ID of the current category.
647             #
648             # $c->{package_name} # String
649             # See ::Category for the rest of the fields provided by the package Iterator.
650             # Very similar though.
651             #
652             # $c->{ebuild_name} # String
653             # See ::Package for the rest of the fields provided by the ebuild Iterator.
654             # Very similar though.
655             } );
656              
657             =back
658              
659             =head1 ATTRIBUTES
660              
661             =head2 path
662              
663             Path to repository.
664              
665             isa => File, ro, required, coerce
666              
667             L<Types::Path::Tiny/File>
668              
669             =head2 name
670              
671             Repository name.
672              
673             isa => Gentoo__Overlay_RepositoryName, ro, lazy_build
674              
675             L<< C<RepositoryName>|Gentoo::Overlay::Types/Gentoo__Overlay_RepositoryName >>
676              
677             L</_build_name>
678              
679             =head1 ATTRIBUTE ACCESSORS
680              
681             =head2 category_names
682              
683             Returns a list of the names of all the categories.
684              
685             my @list = sort $overlay->category_names();
686              
687             L</_categories>
688              
689             =head2 categories
690              
691             Returns a hash of L<< C<Category>|Gentoo::Overlay::Category >> objects.
692              
693             my %hash = $overlay->categories;
694             print $hash{dev-perl}->pretty_name; # dev-perl/::gentoo
695              
696             L</_categories>
697              
698             =head2 get_category
699              
700             Returns a Category Object for a given category name
701              
702             my $cat = $overlay->get_category('dev-perl');
703              
704             L</_categories>
705              
706             =head1 PRIVATE ATTRIBUTES
707              
708             =head2 _profile_dir
709              
710             Path to the profile sub-directory.
711              
712             isa => Dir, ro, lazy_build
713              
714             L<MooseX::Types::Path::Tiny/Dir>
715              
716             L</_build__profile_dir>
717              
718             =head2 _categories
719              
720             The auto-generating category hash backing
721              
722             isa => HashRef[ Gentoo__Overlay_Category ], ro, lazy_build
723              
724             L</_build__categories>
725              
726             L</_has_category>
727              
728             L</category_names>
729              
730             L</categories>
731              
732             L</get_category>
733              
734             L<Gentoo::Overlay::Types/Gentoo__Overlay_Category>
735              
736             L<< C<MooseX::Types::Moose>|MooseX::Types::Moose >>
737              
738             =head1 PRIVATE ATTRIBUTE ACCESSORS
739              
740             =head2 _has_category
741              
742             Returns if a named category exists
743              
744             $overlay->_has_category("dev-perl");
745              
746             L</_categories>
747              
748             =head1 PRIVATE CLASS ATTRIBUTES
749              
750             =head2 _default_paths
751              
752             Class-wide list of path generators.
753              
754             isa => HashRef[ CodeRef ], ro, lazy_build
755              
756             L</_build__default_paths>
757              
758             =head1 PRIVATE METHODS
759              
760             =head2 _build_name
761              
762             Extracts the repository name out of the file 'C<repo_name>'
763             in C<$OVERLAY/profiles/repo_name>
764              
765             $overlay->_build_name
766              
767             L</name>
768              
769             =head2 _build__profile_dir
770              
771             Verifies the existence of the profile directory, and returns the path to it.
772              
773             $overlay->_build__profile_dir
774              
775             L</_profile_dir>
776              
777             =head2 _build__categories
778              
779             Generates the Category Hash-Table, either by reading the categories index ( new, preferred )
780             or by traversing the directory ( old, discouraged )
781              
782             $category->_build_categories;
783              
784             L</_categories>
785              
786             L</_build___categories_scan>
787              
788             L</_build___categories_file>
789              
790             =head2 _build___categories_file
791              
792             Builds the category map using the 'categories' file found in the overlays profile directory.
793              
794             $overlay->_build___categories_file
795              
796             =head2 _build___categories_scan
797              
798             Builds the category map the hard way by scanning the directory and then skipping things
799             that are files and/or blacklisted.
800              
801             $overlay->_build___categories_scan
802              
803             =head2 _iterate_ebuilds
804              
805             $object->_iterate_ebuilds( ignored_value => sub { } );
806              
807             Handles dispatch call for
808              
809             $object->iterate( ebuilds => sub { } );
810              
811             =head2 _iterate_categories
812              
813             $object->_iterate_categories( ignored_value => sub { } );
814              
815             Handles dispatch call for
816              
817             $object->iterate( categories => sub { } );
818              
819             =head2 _iterate_packages
820              
821             $object->_iterate_packages( ignored_value => sub { } );
822              
823             Handles dispatch call for
824              
825             $object->iterate( packages => sub { } );
826              
827             =head1 AUTHOR
828              
829             Kent Fredric <kentnl@cpan.org>
830              
831             =head1 COPYRIGHT AND LICENSE
832              
833             This software is copyright (c) 2014 by Kent Fredric <kentnl@cpan.org>.
834              
835             This is free software; you can redistribute it and/or modify it under
836             the same terms as the Perl 5 programming language system itself.
837              
838             =cut