line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mojolicious::Plugin::MultiConfig; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
24723
|
use v5.10; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
53
|
|
4
|
1
|
|
|
1
|
|
11
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
33
|
|
5
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
12
|
|
|
1
|
|
|
|
|
35
|
|
6
|
1
|
|
|
1
|
|
927
|
use parent 'Mojolicious::Plugin'; |
|
1
|
|
|
|
|
315
|
|
|
1
|
|
|
|
|
5
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
use Config::Any; |
9
|
|
|
|
|
|
|
use File::Spec::Functions; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Mojolicious::Plugin::MultiConfig - Load multiple configs and merge |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 VERSION |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Version 0.2 |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=cut |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our $VERSION = '0.2'; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# In Mojo startup()... |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
my $config = $self->plugin('multi_config', foo => 'bar'); |
28
|
|
|
|
|
|
|
say($config->{this}); |
29
|
|
|
|
|
|
|
say($self->config->{that}); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DESCRIPTION |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
L is a wrapper around L to load multiple configuration files and merge them together. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
The default behaviour is to load 3 config files based on templates containing moniker (%a), mode (%m), username (%u) and file extenstion (%e): |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
* %a.%e |
38
|
|
|
|
|
|
|
* %a.%m.%e |
39
|
|
|
|
|
|
|
* %a.%m.%u.%e |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
The config files are loaded in order, with later files in the chain overwriting option(s) in the previous config file. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
The filenames are configurable, see OPTIONS section below. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Missing config files are ignored without error. (TODO: config option to be added in the near future ensure an error). |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head1 OPTIONS |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
L supports some options. They can be passed as named args. e.g.: |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
$self->plugin('multi_config', option1 => 'value1', foo => 'bar'); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head2 moniker |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
moniker => 'appconfig' |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Will use this value in place of %a (moniker) in filenames. Defaults to C<$app-Emoniker> if not specified. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=head2 mode |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
mode => 'test' |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Will use this value in place of %m (mode) in filenames. Defaults to C<$app-Emode> if not specified. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head2 dir |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
dir => 'my_config_dir' |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
Will load config files from this directory. Defaults to C<$app-Ehome('conf')> if not specified. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head2 files |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
files => ['file1.conf', 'file2.%u.conf'] |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
Will load these config files instead of the default. You can use template codes as per DESCRIPTION section. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Defaults to C<['%a.%e', '%a.%m.%e', '%a.%m.%u.%e']> if not specified. |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 ext |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
ext => 'yml' |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Will use this value in place of %e (file extension) in filenames. Defaults to C if not specified. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head1 METHODS |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head2 register |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Register as a plugin and load config files. Called automatically by C<$app-Eplugin> |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=cut |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub register |
94
|
|
|
|
|
|
|
{ |
95
|
|
|
|
|
|
|
my $self = shift; |
96
|
|
|
|
|
|
|
my $app = shift; |
97
|
|
|
|
|
|
|
my $arg = shift; |
98
|
|
|
|
|
|
|
my $config = {}; |
99
|
|
|
|
|
|
|
my $username = (getpwuid($<))[0]; # TODO: Not on Windows! |
100
|
|
|
|
|
|
|
my @files; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Default args if not set |
103
|
|
|
|
|
|
|
$arg->{moniker} //= $app->moniker; |
104
|
|
|
|
|
|
|
$arg->{mode} //= $app->mode; |
105
|
|
|
|
|
|
|
$arg->{dir} //= catfile($app->home, 'conf'); |
106
|
|
|
|
|
|
|
$arg->{files} //= ['%a.%e', '%a.%m.%e', '%a.%m.%u.%e']; |
107
|
|
|
|
|
|
|
$arg->{ext} //= 'conf'; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
for (my $i = 0; $i < @{$arg->{files}}; $i++) { |
110
|
|
|
|
|
|
|
# Prefix dir |
111
|
|
|
|
|
|
|
$arg->{files}->[$i] = catfile($arg->{dir}, $arg->{files}->[$i]); |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# Search/replace for codes used in files |
114
|
|
|
|
|
|
|
$arg->{files}->[$i] =~ s/\%a/$arg->{moniker}/g; |
115
|
|
|
|
|
|
|
$arg->{files}->[$i] =~ s/\%m/$arg->{mode}/g; |
116
|
|
|
|
|
|
|
$arg->{files}->[$i] =~ s/\%u/$username/g; |
117
|
|
|
|
|
|
|
$arg->{files}->[$i] =~ s/\%e/$arg->{ext}/g; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
if (-e $arg->{files}->[$i]) { |
120
|
|
|
|
|
|
|
$app->log->debug(__PACKAGE__ . ': found ' . $arg->{files}->[$i]); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
else { |
123
|
|
|
|
|
|
|
$app->log->debug(__PACKAGE__ . ': cannot find ' . $arg->{files}->[$i]); |
124
|
|
|
|
|
|
|
splice(@{$arg->{files}}, $i--, 1); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Load the config file(s) |
129
|
|
|
|
|
|
|
my $config_tmp = Config::Any->load_files({ |
130
|
|
|
|
|
|
|
files => $arg->{files}, |
131
|
|
|
|
|
|
|
use_ext => 1, |
132
|
|
|
|
|
|
|
flatten_to_hash => 1, |
133
|
|
|
|
|
|
|
driver_args => { |
134
|
|
|
|
|
|
|
General => {-UTF8 => 1}, |
135
|
|
|
|
|
|
|
}, |
136
|
|
|
|
|
|
|
}); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Merge |
139
|
|
|
|
|
|
|
$config = {%$config, %{$config_tmp->{$_}}} for (@{$arg->{files}}); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
$app->config($config); |
142
|
|
|
|
|
|
|
$app->log->debug($app->dumper($config)); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
return $config; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 AUTHOR |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Ben Vinnerd, C<< >> |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head1 LICENCE AND COPYRIGHT |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Copyright 2013 Ben Vinnerd. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
156
|
|
|
|
|
|
|
under the terms of the the Artistic License (2.0). You may obtain a |
157
|
|
|
|
|
|
|
copy of the full license at: |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
L |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Any use, modification, and distribution of the Standard or Modified |
162
|
|
|
|
|
|
|
Versions is governed by this Artistic License. By using, modifying or |
163
|
|
|
|
|
|
|
distributing the Package, you accept this license. Do not use, modify, |
164
|
|
|
|
|
|
|
or distribute the Package, if you do not accept this license. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
If your Modified Version has been derived from a Modified Version made |
167
|
|
|
|
|
|
|
by someone other than you, you are nevertheless required to ensure that |
168
|
|
|
|
|
|
|
your Modified Version complies with the requirements of this license. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
This license does not grant you the right to use any trademark, service |
171
|
|
|
|
|
|
|
mark, tradename, or logo of the Copyright Holder. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
This license includes the non-exclusive, worldwide, free-of-charge |
174
|
|
|
|
|
|
|
patent license to make, have made, use, offer to sell, sell, import and |
175
|
|
|
|
|
|
|
otherwise transfer the Package with respect to any patent claims |
176
|
|
|
|
|
|
|
licensable by the Copyright Holder that are necessarily infringed by the |
177
|
|
|
|
|
|
|
Package. If you institute patent litigation (including a cross-claim or |
178
|
|
|
|
|
|
|
counterclaim) against any party alleging that the Package constitutes |
179
|
|
|
|
|
|
|
direct or contributory patent infringement, then this Artistic License |
180
|
|
|
|
|
|
|
to you shall terminate on the date that such litigation is filed. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER |
183
|
|
|
|
|
|
|
AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. |
184
|
|
|
|
|
|
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
185
|
|
|
|
|
|
|
PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY |
186
|
|
|
|
|
|
|
YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR |
187
|
|
|
|
|
|
|
CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR |
188
|
|
|
|
|
|
|
CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, |
189
|
|
|
|
|
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=cut |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
1; |