File Coverage

lib/Morpheus/Plugin/File.pm
Criterion Covered Total %
statement 68 68 100.0
branch 15 22 68.1
condition 7 8 87.5
subroutine 12 12 100.0
pod 0 3 0.0
total 102 113 90.2


line stmt bran cond sub pod time code
1             package Morpheus::Plugin::File;
2             {
3             $Morpheus::Plugin::File::VERSION = '0.46';
4             }
5 4     4   21 use strict;
  4         7  
  4         162  
6              
7             # ABSTRACT: plugin reading perl-based configs
8              
9 4     4   22 use base qw(Morpheus::Plugin::Content);
  4         6  
  4         319  
10              
11 4     4   24 use Morpheus;
  4         6  
  4         56  
12 4     4   26 use File::Find;
  4         9  
  4         290  
13 4     4   4810 use Params::Validate;
  4         79440  
  4         4302  
14              
15             sub new {
16 4     4 0 11 my $class = shift;
17             my $self = validate(@_, {
18 96     96   389 path => { default => sub { morph('/morpheus/plugin/file/options/path') } },
19 4         369 suffix => { default => qr/(?:\.(-?\d+))?\.(?:cfg|conf)$/ },
20             });
21              
22 4 50       38 if (ref $self->{suffix} eq "Regexp") {
23 4         9 my $re = $self->{suffix};
24             $self->{suffix} = sub {
25 97     97   140 my $fname = shift;
26 97 100       867 $fname =~ s/$re// or return;
27 96         296 return ($fname, $1);
28 4         18 };
29             }
30              
31 4         76 bless $self => $class;
32             }
33              
34             sub content ($$) {
35 24     24 0 38 my ($self, $file) = @_;
36 24 50       1365 open my $fh, "<", "$file" or die "open '$file' failed: $!";
37 24         39 my $content = do { local $/; <$fh> };
  24         103  
  24         621  
38 24 50       356 close $fh or die "close '$file' failed: $!";
39 24         129 return $content;
40             }
41              
42             sub list ($$) {
43 96     96 0 198 my ($self, $main_ns) = @_;
44 96         209 $main_ns =~ s{^/+}{};
45              
46 96         283 my $paths = $self->{path};
47 96 50       514 $paths = $paths->() if ref $paths eq "CODE";
48 96 50       300 return () unless $paths;
49 96 50       274 die unless ref $paths eq "ARRAY";
50             #FIXME: cache those paths?
51            
52 96         487 my $suffix = $self->{suffix};
53              
54 96         155 my @list;
55 96         224 for my $path (@{$paths}) {
  96         202  
56 192         522 $path =~ s{/+$}{};
57 192         232 my %list;
58              
59             my $process_file = sub ($;$) {
60 259     259   382 my ($full_file, $desired_ns) = @_;
61 259 100       5628 -f $full_file or return;
62 97 50       895 die 'mystery' unless $full_file =~ m{^\Q$path\E/(.*)};
63 97         263 my $file = $1;
64 97         197 my ($ns, $priority) = $suffix->($file);
65 97 100 100     499 return if not $ns or $desired_ns and $ns ne $desired_ns;
      66        
66 95   100     104 push @{$list{$ns}}, {
  95         1883  
67             file => $full_file,
68             priority => $priority || 0,
69             };
70 192         1333 };
71              
72 192 100       3470 if (-d "$path/$main_ns") {
73             find({
74             no_chdir => 1,
75             follow_skip => 2,
76 64     64   121 wanted => sub { $process_file->($File::Find::name) },
77 4         304 }, "$path/$main_ns");
78             }
79              
80 192         327 my $ns = $main_ns;
81 192         365 while ($ns) {
82 844         27423 for my $file (glob ("$path/$ns*")) { # $ns.cfg or $ns.10.cfg but not $ns-blah.cfg
83 195         435 $process_file->($file, $ns);
84             }
85 844         7624 $ns =~ s{/?[^/]+$}{};
86             }
87              
88 192         1493 for my $ns (sort { length $b <=> length $a } keys %list) {
  66         101  
89 71         92 for (sort { $b->{priority} <=> $a->{priority} } @{$list{$ns}}) {
  28         99  
  71         172  
90 95         629 push @list, $ns => $_->{file};
91             }
92             }
93             }
94              
95 96         600 return @list;
96             # priority rules: config path, then file depth, then file suffix.
97             # for example if config path is /etc/:/etc2/ and there exist files
98             # /etc/x/y.10.cfg /etc/x/y.cfg /etc/x/y.-10.cfg
99             # /etc/x.10.cfg /etc/x.cfg /etc/x.-10.cfg
100             # /etc2/x/y.10.cfg /etc2/x/y.cfg /etc2/x/y.-10.cfg
101             # /etc2/x.10.cfg /etc2/x.cfg /etc2/x.-10.cfg
102             # then the order of their priority from higher to lower is from left to right
103             }
104              
105             1;
106              
107             __END__