line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ************************************************************************* |
2
|
|
|
|
|
|
|
# Copyright (c) 2014-2020, SUSE LLC |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# All rights reserved. |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# Redistribution and use in source and binary forms, with or without |
7
|
|
|
|
|
|
|
# modification, are permitted provided that the following conditions are met: |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# 1. Redistributions of source code must retain the above copyright notice, |
10
|
|
|
|
|
|
|
# this list of conditions and the following disclaimer. |
11
|
|
|
|
|
|
|
# |
12
|
|
|
|
|
|
|
# 2. Redistributions in binary form must reproduce the above copyright |
13
|
|
|
|
|
|
|
# notice, this list of conditions and the following disclaimer in the |
14
|
|
|
|
|
|
|
# documentation and/or other materials provided with the distribution. |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# 3. Neither the name of SUSE LLC nor the names of its contributors may be |
17
|
|
|
|
|
|
|
# used to endorse or promote products derived from this software without |
18
|
|
|
|
|
|
|
# specific prior written permission. |
19
|
|
|
|
|
|
|
# |
20
|
|
|
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
21
|
|
|
|
|
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22
|
|
|
|
|
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23
|
|
|
|
|
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
24
|
|
|
|
|
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25
|
|
|
|
|
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26
|
|
|
|
|
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27
|
|
|
|
|
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28
|
|
|
|
|
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29
|
|
|
|
|
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30
|
|
|
|
|
|
|
# POSSIBILITY OF SUCH DAMAGE. |
31
|
|
|
|
|
|
|
# ************************************************************************* |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
package App::CELL::Load; |
34
|
|
|
|
|
|
|
|
35
|
14
|
|
|
14
|
|
27548
|
use strict; |
|
14
|
|
|
|
|
38
|
|
|
14
|
|
|
|
|
380
|
|
36
|
14
|
|
|
14
|
|
61
|
use warnings; |
|
14
|
|
|
|
|
20
|
|
|
14
|
|
|
|
|
279
|
|
37
|
14
|
|
|
14
|
|
199
|
use 5.012; |
|
14
|
|
|
|
|
43
|
|
38
|
|
|
|
|
|
|
|
39
|
14
|
|
|
14
|
|
1131
|
use App::CELL::Config qw( $meta $core $site ); |
|
14
|
|
|
|
|
23
|
|
|
14
|
|
|
|
|
1112
|
|
40
|
14
|
|
|
14
|
|
88
|
use App::CELL::Log qw( $log ); |
|
14
|
|
|
|
|
25
|
|
|
14
|
|
|
|
|
929
|
|
41
|
14
|
|
|
14
|
|
108
|
use App::CELL::Message; |
|
14
|
|
|
|
|
29
|
|
|
14
|
|
|
|
|
347
|
|
42
|
14
|
|
|
14
|
|
73
|
use App::CELL::Status; |
|
14
|
|
|
|
|
27
|
|
|
14
|
|
|
|
|
376
|
|
43
|
14
|
|
|
14
|
|
4878
|
use App::CELL::Test qw( cmp_arrays ); |
|
14
|
|
|
|
|
31
|
|
|
14
|
|
|
|
|
743
|
|
44
|
14
|
|
|
14
|
|
82
|
use App::CELL::Util qw( stringify_args is_directory_viable ); |
|
14
|
|
|
|
|
22
|
|
|
14
|
|
|
|
|
492
|
|
45
|
14
|
|
|
14
|
|
65
|
use Data::Dumper; |
|
14
|
|
|
|
|
22
|
|
|
14
|
|
|
|
|
456
|
|
46
|
14
|
|
|
14
|
|
5269
|
use File::Next; |
|
14
|
|
|
|
|
21974
|
|
|
14
|
|
|
|
|
362
|
|
47
|
14
|
|
|
14
|
|
4985
|
use File::ShareDir; |
|
14
|
|
|
|
|
251879
|
|
|
14
|
|
|
|
|
573
|
|
48
|
14
|
|
|
14
|
|
81
|
use Params::Validate qw( :all ); |
|
14
|
|
|
|
|
26
|
|
|
14
|
|
|
|
|
15416
|
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 NAME |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
App::CELL::Load -- find and load message files and config files |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 SYNOPSIS |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
use App::CELL::Load; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Load App::CELL's internal messages and config params and then |
61
|
|
|
|
|
|
|
# attempt to load the application's messages and config params |
62
|
|
|
|
|
|
|
$status = App::CELL::Load::init(); |
63
|
|
|
|
|
|
|
return $status if $status->not_ok; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# attempt to determine the site configuration directory |
66
|
|
|
|
|
|
|
my $resulthash = App::CELL::Load::get_sitedir(); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# get a reference to a list of configuration files (full paths) of a |
69
|
|
|
|
|
|
|
# given type under a given directory |
70
|
|
|
|
|
|
|
my $metafiles = App::CELL::Load::find_files( '/etc/CELL', 'meta' ); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# load messages from all message file in a given directory and all its |
73
|
|
|
|
|
|
|
# subdirectories |
74
|
|
|
|
|
|
|
$status = message_files( '/etc/CELL' ); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# load meta, core, and site params from all meta, core, and site |
77
|
|
|
|
|
|
|
# configuration files in a given directory and all its subdirectories |
78
|
|
|
|
|
|
|
$status = meta_core_site_files( '/etc/CELL' ); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=head1 DESCRIPTION |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
The purpose of the App::CELL::Load module is to provide message and config |
85
|
|
|
|
|
|
|
file finding and loading functionality to the App::CELL::Message and |
86
|
|
|
|
|
|
|
App::CELL::Config modules. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head1 PACKAGE VARIABLES |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
This module provides the following package variables |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=over |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=item C<$sharedir> - the full path of the sharedir |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=item C<$sharedir_loaded> - whether it has been loaded or not |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=item C<@sitedir> - the full path of the site configuration directory |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=back |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=cut |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
our $sharedir = ''; |
107
|
|
|
|
|
|
|
our $sharedir_loaded = 0; |
108
|
|
|
|
|
|
|
our @sitedir = (); |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head1 MODULES |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=head2 init |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
Idempotent initialization function. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
Optionally takes a PARAMHASH. The following arguments are recognized: |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=over |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item C -- full path to the/a site dir |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item C -- name of environment variable containing sitedir path |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item C -- increase logging verbosity of the load routine |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=back |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
E.g.: |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
my $status = App::CELL::Load::init( |
132
|
|
|
|
|
|
|
sitedir => '/etc/foo', |
133
|
|
|
|
|
|
|
verbose => 1 |
134
|
|
|
|
|
|
|
); |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
See L for details. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=cut |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub init { |
141
|
13
|
|
|
13
|
1
|
1189
|
my %ARGS = validate( @_, { |
142
|
|
|
|
|
|
|
enviro => { type => SCALAR, optional => 1 }, |
143
|
|
|
|
|
|
|
sitedir => { type => SCALAR, optional => 1 }, |
144
|
|
|
|
|
|
|
verbose => { type => SCALAR, default => 0 }, |
145
|
|
|
|
|
|
|
} ); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# determine verbosity level |
148
|
13
|
|
|
|
|
69
|
my $args_string; |
149
|
13
|
50
|
|
|
|
39
|
if ( %ARGS ) { |
150
|
13
|
|
|
|
|
57
|
$args_string = "with arguments: " . stringify_args( \%ARGS ); |
151
|
|
|
|
|
|
|
} else { |
152
|
0
|
|
|
|
|
0
|
$args_string = "without arguments"; |
153
|
|
|
|
|
|
|
} |
154
|
13
|
|
100
|
|
|
107
|
$meta->set('CELL_META_LOAD_VERBOSE', $ARGS{'verbose'} || 0); |
155
|
|
|
|
|
|
|
|
156
|
13
|
100
|
|
|
|
91
|
$log->info( |
157
|
|
|
|
|
|
|
"Entering App::CELL::Load::init from " . (caller)[0] . " $args_string", |
158
|
|
|
|
|
|
|
cell => 1 |
159
|
|
|
|
|
|
|
) if $meta->CELL_META_LOAD_VERBOSE; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# check for taint mode |
162
|
13
|
50
|
|
|
|
99
|
if ( ${^TAINT} != 0 ) { |
163
|
0
|
|
|
|
|
0
|
return App::CELL::Status->new( level => "FATAL", |
164
|
|
|
|
|
|
|
code => "Attempt to load while in taint mode (-T)" ); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# look up sharedir |
168
|
13
|
100
|
|
|
|
49
|
if ( not $sharedir ) { |
169
|
9
|
|
|
|
|
60
|
my $tmp_sharedir = File::ShareDir::dist_dir('App-CELL'); |
170
|
9
|
50
|
|
|
|
1022
|
if ( ! is_directory_viable( $tmp_sharedir ) ) { |
171
|
0
|
|
|
|
|
0
|
return App::CELL::Status->new( |
172
|
|
|
|
|
|
|
level => 'ERR', |
173
|
|
|
|
|
|
|
code => 'CELL_SHAREDIR_NOT_VIABLE', |
174
|
|
|
|
|
|
|
args => [ $tmp_sharedir, $App::CELL::Util::not_viable_reason ], |
175
|
|
|
|
|
|
|
); |
176
|
|
|
|
|
|
|
} |
177
|
9
|
100
|
|
|
|
60
|
$log->info( "Found viable CELL configuration directory " . |
178
|
|
|
|
|
|
|
$tmp_sharedir . " in App::CELL distro", cell => 1 ) if $meta->CELL_META_LOAD_VERBOSE; |
179
|
9
|
|
|
|
|
37
|
$site->set( 'CELL_SHAREDIR_FULLPATH', $tmp_sharedir ); |
180
|
9
|
|
|
|
|
26
|
$sharedir = $tmp_sharedir; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# walk sharedir |
184
|
13
|
100
|
66
|
|
|
75
|
if ( $sharedir and not $sharedir_loaded ) { |
185
|
9
|
|
|
|
|
48
|
my $status = message_files( $sharedir ); |
186
|
9
|
|
|
|
|
108
|
my $load_status = _report_load_status( $sharedir, 'sharedir', 'message', $status ); |
187
|
9
|
50
|
|
|
|
41
|
return $load_status if $load_status->not_ok; |
188
|
9
|
|
|
|
|
31
|
$status = meta_core_site_files( $sharedir ); |
189
|
9
|
|
|
|
|
35
|
$load_status = _report_load_status( $sharedir, 'sharedir', 'config params', $status ); |
190
|
9
|
50
|
|
|
|
45
|
return $load_status if $load_status->not_ok; |
191
|
9
|
|
|
|
|
42
|
$site->set( 'CELL_SHAREDIR_LOADED', 1 ); |
192
|
9
|
|
|
|
|
35
|
$sharedir_loaded = 1; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
13
|
100
|
|
|
|
58
|
if ( $meta->CELL_META_LOAD_VERBOSE ) { |
196
|
6
|
50
|
|
|
|
24
|
if ( @sitedir ) { |
197
|
0
|
|
|
|
|
0
|
$log->debug( "sitedir package variable contains ->" . |
198
|
|
|
|
|
|
|
join( ':', @sitedir ) . "<-", cell => 1 ); |
199
|
|
|
|
|
|
|
} else { |
200
|
6
|
|
|
|
|
26
|
$log->debug( "sitedir package variable is empty", cell => 1 ); |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# get sitedir from args or environment |
205
|
13
|
|
|
|
|
55
|
my $status = get_sitedir( %ARGS ); |
206
|
13
|
100
|
|
|
|
44
|
return $status unless $status->ok; |
207
|
2
|
|
|
|
|
6
|
my $sitedir_candidate = $status->payload; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# walk sitedir |
210
|
2
|
50
|
|
|
|
4
|
if ( $sitedir_candidate ) { |
211
|
2
|
|
|
|
|
5
|
my $status = message_files( $sitedir_candidate ); |
212
|
2
|
|
|
|
|
7
|
my $messages_loaded = _report_load_status( $sitedir_candidate, 'sitedir', 'message', $status ); |
213
|
2
|
|
|
|
|
18
|
$status = meta_core_site_files( $sitedir_candidate ); |
214
|
2
|
|
|
|
|
13
|
my $params_loaded = _report_load_status( $sitedir_candidate, 'sitedir', 'config params', $status ); |
215
|
|
|
|
|
|
|
# |
216
|
|
|
|
|
|
|
# sitedir candidate is accepted only if something is actually |
217
|
|
|
|
|
|
|
# loaded |
218
|
|
|
|
|
|
|
# |
219
|
2
|
50
|
33
|
|
|
8
|
if ( $messages_loaded->ok or $params_loaded->ok ) { |
220
|
2
|
|
|
|
|
9
|
$meta->set( 'CELL_META_SITEDIR_LOADED', |
221
|
|
|
|
|
|
|
( $meta->CELL_META_SITEDIR_LOADED + 1 ) ); |
222
|
2
|
|
|
|
|
5
|
push @sitedir, $sitedir_candidate; |
223
|
2
|
|
|
|
|
7
|
$meta->set( 'CELL_META_SITEDIR_LIST', \@sitedir ); |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# check that at least sharedir has really been loaded |
228
|
|
|
|
|
|
|
SANITY: { |
229
|
2
|
|
|
|
|
6
|
my $results = []; |
|
2
|
|
|
|
|
5
|
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# remember, message constructor returns a status object |
232
|
2
|
|
|
|
|
6
|
my $status = App::CELL::Message->new( code => 'CELL_LOAD_SANITY_MESSAGE' ); |
233
|
|
|
|
|
|
|
|
234
|
2
|
50
|
|
|
|
10
|
if ( $status->ok ) { |
235
|
2
|
|
|
|
|
8
|
my $msgobj = $status->payload; |
236
|
2
|
|
|
|
|
12
|
push @$results, ( |
237
|
|
|
|
|
|
|
$meta->CELL_LOAD_SANITY_META, |
238
|
|
|
|
|
|
|
$core->CELL_LOAD_SANITY_CORE, |
239
|
|
|
|
|
|
|
$site->CELL_LOAD_SANITY_SITE, |
240
|
|
|
|
|
|
|
$msgobj->text(), |
241
|
|
|
|
|
|
|
); |
242
|
2
|
|
|
|
|
13
|
my $cmp_arrays_result = cmp_arrays( |
243
|
|
|
|
|
|
|
$results, |
244
|
|
|
|
|
|
|
[ 'Baz', 'Bar', 'Foo', 'This is a sanity testing message' ], |
245
|
|
|
|
|
|
|
); |
246
|
2
|
50
|
|
|
|
14
|
last SANITY if $cmp_arrays_result; |
247
|
|
|
|
|
|
|
} |
248
|
0
|
|
|
|
|
0
|
return App::CELL::Status->new( |
249
|
|
|
|
|
|
|
level => 'ERR', |
250
|
|
|
|
|
|
|
code => 'CELL_LOAD_FAILED_SANITY', |
251
|
|
|
|
|
|
|
); |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
2
|
50
|
|
|
|
10
|
$log->debug( "Leaving App::CELL::Load::init", cell => 1 ) |
255
|
|
|
|
|
|
|
if $meta->CELL_META_LOAD_VERBOSE; |
256
|
|
|
|
|
|
|
|
257
|
2
|
|
|
|
|
7
|
return App::CELL::Status->ok; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub _report_load_status { |
262
|
22
|
|
|
22
|
|
66
|
my ( $dir_path, $dir_desc, $what, $status ) = @_; |
263
|
22
|
|
|
|
|
68
|
my $return_status = App::CELL::Status->ok; |
264
|
22
|
|
50
|
|
|
35
|
my $quantitems = ${ $status->payload }{quantitems} || 0; |
265
|
22
|
|
50
|
|
|
37
|
my $quantfiles = ${ $status->payload }{quantfiles} || 0; |
266
|
22
|
50
|
|
|
|
82
|
if ( $quantitems == 0 ) { |
267
|
0
|
|
|
|
|
0
|
$return_status = App::CELL::Status->new( |
268
|
|
|
|
|
|
|
level => 'WARN', |
269
|
|
|
|
|
|
|
code => 'CELL_DIR_WALKED_NOTHING_FOUND', |
270
|
|
|
|
|
|
|
args => [ $what, $dir_desc, $dir_path, $quantfiles ], |
271
|
|
|
|
|
|
|
caller => [ CORE::caller() ], |
272
|
|
|
|
|
|
|
cell => 1, |
273
|
|
|
|
|
|
|
); |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
# trigger a log message: note that we can't use an OK status here |
276
|
|
|
|
|
|
|
# because log messages for those are suppressed |
277
|
|
|
|
|
|
|
App::CELL::Status->new ( |
278
|
22
|
100
|
66
|
|
|
171
|
level => 'INFO', |
|
|
|
100
|
|
|
|
|
279
|
|
|
|
|
|
|
code => 'CELL_DIR_WALKED_ITEMS_LOADED', |
280
|
|
|
|
|
|
|
args => [ $quantitems, $what, $quantfiles, $dir_desc, $dir_path ], |
281
|
|
|
|
|
|
|
caller => [ CORE::caller() ], |
282
|
|
|
|
|
|
|
cell => 1, |
283
|
|
|
|
|
|
|
) if ( $dir_desc eq 'sitedir' ) or ( $dir_desc eq 'sharedir' and $meta->CELL_META_LOAD_VERBOSE ); |
284
|
22
|
|
|
|
|
72
|
return $return_status; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=head2 message_files |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
Loads message files from the given directory. Takes: full path to |
290
|
|
|
|
|
|
|
configuration directory. Returns: result hash containing 'quantfiles' |
291
|
|
|
|
|
|
|
(total number of files processed) and 'count' (total number of |
292
|
|
|
|
|
|
|
messages loaded). |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=cut |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
sub message_files { |
297
|
|
|
|
|
|
|
|
298
|
11
|
|
|
11
|
1
|
62
|
my $confdir = shift; |
299
|
11
|
|
|
|
|
19
|
my %reshash; |
300
|
11
|
|
|
|
|
29
|
$reshash{quantfiles} = 0; |
301
|
11
|
|
|
|
|
28
|
$reshash{quantitems} = 0; |
302
|
|
|
|
|
|
|
|
303
|
11
|
|
|
|
|
43
|
my $file_list = find_files( 'message', $confdir ); |
304
|
|
|
|
|
|
|
|
305
|
11
|
50
|
|
|
|
90
|
if ( @$file_list ) { |
306
|
11
|
100
|
|
|
|
55
|
$log->info( "Found message files: " . join( ',', @$file_list ), |
307
|
|
|
|
|
|
|
cell => 1 ) if $meta->CELL_META_LOAD_VERBOSE; |
308
|
|
|
|
|
|
|
} else { |
309
|
0
|
0
|
|
|
|
0
|
$log->warn( "No message files found in $confdir", cell => 1 ) |
310
|
|
|
|
|
|
|
if $meta->CELL_META_LOAD_VERBOSE; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
11
|
|
|
|
|
34
|
foreach my $file ( @$file_list ) { |
314
|
12
|
|
|
|
|
28
|
$reshash{quantfiles} += 1; |
315
|
12
|
50
|
|
|
|
43
|
die "INTERNAL ERROR (App::CELL::Message::mesg is not a reference)" if not ref( $App::CELL::Message::mesg ); |
316
|
12
|
|
|
|
|
143
|
$reshash{quantitems} += parse_message_file( |
317
|
|
|
|
|
|
|
File => $file, |
318
|
|
|
|
|
|
|
Dest => $App::CELL::Message::mesg, |
319
|
|
|
|
|
|
|
); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
11
|
|
|
|
|
92
|
return App::CELL::Status->new( |
323
|
|
|
|
|
|
|
level => 'OK', |
324
|
|
|
|
|
|
|
payload => \%reshash, |
325
|
|
|
|
|
|
|
); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head2 meta_core_site_files |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Loads meta, core, and site config files from the given directory. Takes: |
332
|
|
|
|
|
|
|
full path to configuration directory. Returns: result hash containing |
333
|
|
|
|
|
|
|
'quantfiles' (total number of files processed) and 'count' (total number of |
334
|
|
|
|
|
|
|
configuration parameters loaded). |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=cut |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub meta_core_site_files { |
339
|
|
|
|
|
|
|
|
340
|
11
|
|
|
11
|
1
|
22
|
my $confdir = shift; |
341
|
11
|
|
|
|
|
18
|
my %reshash; |
342
|
11
|
|
|
|
|
30
|
$reshash{quantfiles} = 0; |
343
|
11
|
|
|
|
|
20
|
$reshash{quantitems} = 0; |
344
|
|
|
|
|
|
|
|
345
|
11
|
|
|
|
|
28
|
foreach my $type ( 'meta', 'core', 'site' ) { |
346
|
33
|
|
|
|
|
80
|
my $fulltype = 'App::CELL::Config::' . $type; |
347
|
|
|
|
|
|
|
#$log->debug( "\$fulltype is $fulltype", cell => 1 ); |
348
|
33
|
|
|
|
|
111
|
my $file_list = find_files( $type, $confdir ); |
349
|
33
|
|
|
|
|
59
|
foreach my $file ( @$file_list ) { |
350
|
14
|
|
|
14
|
|
97
|
no strict 'refs'; |
|
14
|
|
|
|
|
30
|
|
|
14
|
|
|
|
|
8492
|
|
351
|
29
|
|
|
|
|
61
|
$reshash{quantfiles} += 1; |
352
|
29
|
|
|
|
|
113
|
$reshash{quantitems} += parse_config_file( |
353
|
|
|
|
|
|
|
File => $file, |
354
|
|
|
|
|
|
|
Dest => $$fulltype, |
355
|
|
|
|
|
|
|
); |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
11
|
|
|
|
|
76
|
return App::CELL::Status->new( |
360
|
|
|
|
|
|
|
level => 'OK', |
361
|
|
|
|
|
|
|
payload => \%reshash, |
362
|
|
|
|
|
|
|
); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=head2 get_sitedir |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
This function implements the algorithm described in |
369
|
|
|
|
|
|
|
L to find a sitedir candidate. |
370
|
|
|
|
|
|
|
configuration directory. |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
On success -- i.e., as soon as the algorithm finds a viable sitedir |
373
|
|
|
|
|
|
|
candidate -- the sitedir (full path) is added to CELL_META_SITEDIR_LIST and |
374
|
|
|
|
|
|
|
an OK status object is returned, with the sitedir in the payload. |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
On failure, the function returns an ERR or WARN status object containing |
377
|
|
|
|
|
|
|
a description of what went wrong. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=cut |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
sub get_sitedir { |
382
|
|
|
|
|
|
|
|
383
|
13
|
|
|
13
|
1
|
34
|
my %paramhash = @_; |
384
|
13
|
|
|
|
|
20
|
my $reason; |
385
|
|
|
|
|
|
|
|
386
|
13
|
|
|
|
|
26
|
my ( $sitedir, $log_message, $status ); |
387
|
|
|
|
|
|
|
GET_CANDIDATE_DIR: { |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# look in paramhash for sitedir |
390
|
13
|
|
|
|
|
20
|
$log->debug( "SITEDIR SEARCH, ROUND 1 (sitedir parameter):", cell => 1 ); |
|
13
|
|
|
|
|
62
|
|
391
|
13
|
100
|
|
|
|
45
|
if ( $sitedir = $paramhash{sitedir} ) { |
392
|
3
|
|
|
|
|
6
|
$log_message = "Viable sitedir passed as argument"; |
393
|
3
|
100
|
|
|
|
10
|
last GET_CANDIDATE_DIR if is_directory_viable( $sitedir ); |
394
|
1
|
|
|
|
|
5
|
$reason = "CELL load routine received 'sitedir' argument ->$sitedir<- " . |
395
|
|
|
|
|
|
|
"but this is not a viable directory ($App::CELL::Util::not_viable_reason)"; |
396
|
1
|
|
|
|
|
8
|
$log->err( $reason, cell => 1 ); |
397
|
1
|
|
|
|
|
6
|
return App::CELL::Status->new( level => 'ERR', code => $reason ); |
398
|
|
|
|
|
|
|
} |
399
|
10
|
|
|
|
|
52
|
$log->debug( "looked at function arguments but they do not " . |
400
|
|
|
|
|
|
|
"contain a literal site dir path", cell => 1 ); |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
# look in paramhash for name of environment variable |
403
|
10
|
|
|
|
|
49
|
$log->debug( "SITEDIR SEARCH, ROUND 2 (enviro parameter):", cell => 1 ); |
404
|
10
|
100
|
|
|
|
33
|
if ( $paramhash{enviro} ) |
405
|
|
|
|
|
|
|
{ |
406
|
1
|
50
|
|
|
|
5
|
if ( $sitedir = $ENV{ $paramhash{enviro} } ) { |
407
|
|
|
|
|
|
|
$log_message = "Found viable sitedir in " . $paramhash{enviro} |
408
|
0
|
|
|
|
|
0
|
. " environment variable"; |
409
|
0
|
0
|
|
|
|
0
|
last GET_CANDIDATE_DIR if is_directory_viable( $sitedir ); |
410
|
0
|
|
|
|
|
0
|
$reason = "CELL load routine received 'enviro' argument ->$paramhash{enviro}<- " . |
411
|
|
|
|
|
|
|
"which expanded to ->$sitedir<- but this is not a viable directory " . |
412
|
|
|
|
|
|
|
"($App::CELL::Util::not_viable_reason)"; |
413
|
0
|
|
|
|
|
0
|
return App::CELL::Status->new( level => 'ERR', code => $reason ); |
414
|
|
|
|
|
|
|
} else { |
415
|
1
|
|
|
|
|
4
|
$reason = "CELL load routine: enviro argument contained ->$paramhash{enviro}<- " . |
416
|
|
|
|
|
|
|
"but no such variable found in the environment"; |
417
|
1
|
|
|
|
|
5
|
return App::CELL::Status->new( level => 'ERR', code => $reason ); |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
# fall back to hard-coded environment variable |
422
|
9
|
|
|
|
|
48
|
$log->debug( "SITEDIR SEARCH, ROUND 3 (fallback to CELL_SITEDIR " . |
423
|
|
|
|
|
|
|
"environment variable):", cell => 1 ); |
424
|
9
|
|
|
|
|
21
|
$sitedir = undef; |
425
|
9
|
100
|
|
|
|
34
|
if ( $sitedir = $ENV{ 'CELL_SITEDIR' } ) { |
426
|
1
|
|
|
|
|
3
|
$log_message = "Found viable sitedir in CELL_SITEDIR environment variable"; |
427
|
1
|
50
|
|
|
|
4
|
last GET_CANDIDATE_DIR if is_directory_viable( $sitedir ); |
428
|
1
|
|
|
|
|
6
|
$reason = "CELL load routine: no 'sitedir', 'enviro' arguments specified; " . |
429
|
|
|
|
|
|
|
"fell back to CELL_SITEDIR environment variable, which exists " . |
430
|
|
|
|
|
|
|
"with value ->$sitedir<- but this is not a viable directory" . |
431
|
|
|
|
|
|
|
"($App::CELL::Util::not_viable_reason)"; |
432
|
1
|
50
|
|
|
|
6
|
if ( $meta->CELL_META_SITEDIR_LOADED ) { |
433
|
0
|
|
|
|
|
0
|
$log->warn( $reason, cell => 1 ); |
434
|
|
|
|
|
|
|
$log->notice( "The following sitedirs have been loaded already " . |
435
|
0
|
|
|
|
|
0
|
join( ' ', @{ $meta->CELL_META_SITEDIR_LIST }), |
|
0
|
|
|
|
|
0
|
|
436
|
|
|
|
|
|
|
cell => 1 ); |
437
|
0
|
|
|
|
|
0
|
return App::CELL::Status->ok; |
438
|
|
|
|
|
|
|
} |
439
|
1
|
|
|
|
|
5
|
return App::CELL::Status->new( level => 'WARN', code => $reason ); |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
# failed to find a sitedir |
443
|
8
|
|
|
|
|
21
|
$reason = "CELL load routine gave up (no sitedir argument, no enviro " . |
444
|
|
|
|
|
|
|
"argument, no CELL_SITEDIR environment variable)"; |
445
|
8
|
50
|
|
|
|
50
|
if ( $meta->CELL_META_SITEDIR_LOADED ) { |
446
|
0
|
|
|
|
|
0
|
$log->warn( $reason, cell => 1 ); |
447
|
|
|
|
|
|
|
$log->notice( "The following sitedirs have been loaded already " . |
448
|
0
|
|
|
|
|
0
|
join( ' ', @{ $meta->CELL_META_SITEDIR_LIST } ), |
|
0
|
|
|
|
|
0
|
|
449
|
|
|
|
|
|
|
cell => 1 ); |
450
|
0
|
|
|
|
|
0
|
return App::CELL::Status->ok; |
451
|
|
|
|
|
|
|
} |
452
|
8
|
|
|
|
|
82
|
return App::CELL::Status->new( level => 'WARN', code => $reason ); |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# SUCCEED |
456
|
2
|
|
|
|
|
13
|
$log->info( $log_message, cell => 1 ); |
457
|
2
|
|
|
|
|
8
|
return App::CELL::Status->ok( $sitedir ); |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=head2 find_files |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Takes two arguments: full directory path and config file type. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
Always returns an array reference. On "failure", the array reference will |
466
|
|
|
|
|
|
|
be empty. |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
How it works: first, the function checks a state variable to see if the |
469
|
|
|
|
|
|
|
"work" of walking the configuration directory has already been done. If |
470
|
|
|
|
|
|
|
so, then the function simply returns the corresponding array reference from |
471
|
|
|
|
|
|
|
its cache (the state hash C<%resultlist>). If this is the first invocation |
472
|
|
|
|
|
|
|
for this directory, the function walks the directory (and all its |
473
|
|
|
|
|
|
|
subdirectories) to find files matching one of the four regular expressions |
474
|
|
|
|
|
|
|
corresponding to the four types of configuration files('meta', 'core', |
475
|
|
|
|
|
|
|
'site', 'message'). For each matching file, the full path is pushed onto |
476
|
|
|
|
|
|
|
the corresponding array in the cache. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
Note that there is a ceiling on the number of files that will be considered |
479
|
|
|
|
|
|
|
while walking the directory tree. This ceiling is defined in the package |
480
|
|
|
|
|
|
|
variable C<$max_files> (see below). |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=cut |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# regular expressions for each file type |
485
|
|
|
|
|
|
|
our $typeregex = { |
486
|
|
|
|
|
|
|
'meta' => qr/^.+_MetaConfig.pm$/ , |
487
|
|
|
|
|
|
|
'core' => qr/^.+_Config.pm$/ , |
488
|
|
|
|
|
|
|
'site' => qr/^.+_SiteConfig.pm$/ , |
489
|
|
|
|
|
|
|
'message' => qr/^.+_Message(_[^_]+){0,1}.conf$/ , |
490
|
|
|
|
|
|
|
}; |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
# C<$max_files> puts a limit on how many files we will look at in our directory |
493
|
|
|
|
|
|
|
# tree walk |
494
|
|
|
|
|
|
|
our $max_files = 1000; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
sub find_files { |
497
|
50
|
|
|
50
|
1
|
598
|
my ( $type, $dirpath ) = @_; |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
# |
500
|
|
|
|
|
|
|
# FIXME: convert $dirpath into an absolute path so it's always the same |
501
|
|
|
|
|
|
|
# |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# re-entrant function |
504
|
14
|
|
|
14
|
|
102
|
use feature "state"; |
|
14
|
|
|
|
|
36
|
|
|
14
|
|
|
|
|
17132
|
|
505
|
50
|
|
|
|
|
80
|
state $resultcache = {}; |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
# If $dirpath key exists in %resultcache, we are re-entering. |
508
|
|
|
|
|
|
|
# In other words, $dirpath has already been walked and all the |
509
|
|
|
|
|
|
|
# filepaths are already in the array stored within %resultcache |
510
|
50
|
100
|
|
|
|
124
|
if ( exists $resultcache->{ $dirpath } ) { |
511
|
38
|
100
|
|
|
|
172
|
$log->debug( "Re-entering find_files for $dirpath (type '$type')", |
512
|
|
|
|
|
|
|
cell => 1) if $meta->CELL_META_LOAD_VERBOSE; |
513
|
38
|
|
|
|
|
103
|
return $resultcache->{ $dirpath }->{ $type }; |
514
|
|
|
|
|
|
|
} else { # create it |
515
|
12
|
|
|
|
|
89
|
$resultcache->{ $dirpath } = { |
516
|
|
|
|
|
|
|
'meta' => [], |
517
|
|
|
|
|
|
|
'core' => [], |
518
|
|
|
|
|
|
|
'site' => [], |
519
|
|
|
|
|
|
|
'message' => [], |
520
|
|
|
|
|
|
|
}; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
# walk the directory (do we need some error checking here?) |
524
|
12
|
|
|
|
|
172
|
$log->debug( "Preparing to walk $dirpath", cell => 1 ); |
525
|
12
|
|
|
|
|
55
|
my $iter = File::Next::files( $dirpath ); |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# while we are walking, go ahead and populate the result cache for _all |
528
|
|
|
|
|
|
|
# four_ types (even though we were asked for just one type) |
529
|
12
|
|
|
|
|
1255
|
my $walk_counter = 0; |
530
|
12
|
|
|
|
|
56
|
ITER_LOOP: while ( defined ( my $file = $iter->() ) ) { |
531
|
57
|
|
|
|
|
3743
|
$log->debug( "Now considering $file", cell => 1 ); |
532
|
57
|
|
|
|
|
85
|
$walk_counter += 1; |
533
|
57
|
50
|
|
|
|
144
|
if ( $walk_counter > $max_files ) { |
534
|
0
|
|
|
|
|
0
|
App::CELL::Status->new ( |
535
|
|
|
|
|
|
|
level => 'ERROR', |
536
|
|
|
|
|
|
|
code => 'Maximum number of configuration file candidates ->%s<- exceeded in %s', |
537
|
|
|
|
|
|
|
args => [ $max_files, $dirpath ], |
538
|
|
|
|
|
|
|
); |
539
|
0
|
|
|
|
|
0
|
last ITER_LOOP; # stop looping if there are so many files |
540
|
|
|
|
|
|
|
} |
541
|
57
|
50
|
|
|
|
821
|
if ( not -r $file ) { |
542
|
0
|
|
|
|
|
0
|
App::CELL::Status->new ( |
543
|
|
|
|
|
|
|
level => 'WARN', |
544
|
|
|
|
|
|
|
code => 'Load operation passed over file ->%s<- (not readable)', |
545
|
|
|
|
|
|
|
args => [ $file ], |
546
|
|
|
|
|
|
|
); |
547
|
0
|
|
|
|
|
0
|
next ITER_LOOP; # jump to next file |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
# $file is now a "candidate" |
550
|
57
|
|
|
|
|
126
|
my $counter = 0; |
551
|
57
|
|
|
|
|
109
|
foreach my $type ( 'meta', 'core', 'site', 'message' ) { |
552
|
163
|
100
|
|
|
|
188
|
if ( $file =~ /${ $typeregex }{ $type }/ ) { |
|
163
|
|
|
|
|
816
|
|
553
|
47
|
|
|
|
|
78
|
push @{ $resultcache->{ $dirpath}->{ $type } }, $file; |
|
47
|
|
|
|
|
146
|
|
554
|
47
|
|
|
|
|
68
|
$counter += 1; |
555
|
47
|
|
|
|
|
197
|
next ITER_LOOP; |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
} |
558
|
10
|
100
|
66
|
|
|
124
|
$log->info( "Load operation passed over file $file (type not " . |
559
|
|
|
|
|
|
|
"recognized)", cell => 1 ) if not $counter and $meta->CELL_META_LOAD_VERBOSE; |
560
|
|
|
|
|
|
|
} |
561
|
12
|
100
|
|
|
|
157
|
$log->debug( "Returning " . join( ',', @{ $resultcache->{ $dirpath }->{ $type } } ), |
|
6
|
|
|
|
|
56
|
|
562
|
|
|
|
|
|
|
cell => 1 ) if $meta->CELL_META_LOAD_VERBOSE; |
563
|
12
|
|
|
|
|
111
|
return $resultcache->{ $dirpath }->{ $type }; |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=head2 parse_message_file |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
This function is where message files are parsed. It takes a PARAMHASH |
570
|
|
|
|
|
|
|
consisting of: |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
=over |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
=item C - filename (full path) |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
=item C - hash reference (where to store the message templates). |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=back |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
Returns: number of stanzas successfully parsed and loaded |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=cut |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
sub parse_message_file { |
585
|
13
|
|
|
13
|
1
|
73
|
my @ARGS = @_; |
586
|
13
|
|
|
|
|
67
|
my %ARGS = ( |
587
|
|
|
|
|
|
|
'File' => undef, |
588
|
|
|
|
|
|
|
'Dest' => undef, |
589
|
|
|
|
|
|
|
@ARGS, |
590
|
|
|
|
|
|
|
); |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
my $process_stanza_sub = sub { |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
# get arguments |
595
|
184
|
|
|
184
|
|
336
|
my ( $file, $line, $lang, $stanza, $destref ) = @_; |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
# put first token on first line into $code |
598
|
184
|
|
|
|
|
526
|
my ( $code ) = $stanza->[0] =~ m/^\s*(\S+)/; |
599
|
184
|
50
|
|
|
|
313
|
if ( not $code ) { |
600
|
0
|
|
|
|
|
0
|
$log->info( |
601
|
|
|
|
|
|
|
"ERROR: Could not process stanza ->" . join( " ", @$stanza ) . "<- in $file", |
602
|
|
|
|
|
|
|
cell => 1, |
603
|
|
|
|
|
|
|
); |
604
|
0
|
|
|
|
|
0
|
return 0; |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# The rest of the lines are the message template |
608
|
184
|
|
|
|
|
212
|
my $text = ''; |
609
|
184
|
|
|
|
|
237
|
foreach ( @$stanza[1 .. $#{ $stanza }] ) { |
|
184
|
|
|
|
|
362
|
|
610
|
193
|
|
|
|
|
223
|
chomp; |
611
|
193
|
|
|
|
|
409
|
$text = $text . " " . $_; |
612
|
|
|
|
|
|
|
} |
613
|
184
|
|
|
|
|
540
|
$text =~ s/^\s+//g; |
614
|
184
|
50
|
33
|
|
|
648
|
if ( $code and $lang and $text ) { |
|
|
|
33
|
|
|
|
|
615
|
184
|
|
|
|
|
893
|
$log->debug( |
616
|
|
|
|
|
|
|
"Parsed message CODE ->$code<- LANG ->$lang<- TEXT ->$text<-", |
617
|
|
|
|
|
|
|
cell => 1, |
618
|
|
|
|
|
|
|
); |
619
|
|
|
|
|
|
|
# we have a candidate, but we don't want to overwrite |
620
|
|
|
|
|
|
|
# an existing entry with the same $code-$lang pair |
621
|
184
|
100
|
|
|
|
553
|
if ( $destref->{ $code }->{ $lang } ) { |
622
|
1
|
|
|
|
|
3
|
my $existing_text = $destref->{ $code }->{ $lang }->{ 'Text' }; |
623
|
|
|
|
|
|
|
$log->error( |
624
|
|
|
|
|
|
|
"ERROR: not loading code-lang pair ->$code" . |
625
|
|
|
|
|
|
|
"/$lang<- with text ->$text<- because this would" . |
626
|
1
|
|
|
|
|
13
|
" overwrite existing pair from " . $destref->{$code}->{$lang}->{'File'}, |
627
|
|
|
|
|
|
|
cell => 1, |
628
|
|
|
|
|
|
|
); |
629
|
1
|
|
|
|
|
2
|
return 0; |
630
|
|
|
|
|
|
|
} else { |
631
|
183
|
100
|
|
|
|
687
|
$log->debug( |
632
|
|
|
|
|
|
|
"OK: loading code-lang pair ->$code/$lang<- with text ->$text<-", |
633
|
|
|
|
|
|
|
cell => 1, |
634
|
|
|
|
|
|
|
) if $meta->CELL_META_LOAD_VERBOSE; |
635
|
183
|
|
|
|
|
612
|
$destref->{ $code }->{ $lang } = { |
636
|
|
|
|
|
|
|
'Text' => $text, |
637
|
|
|
|
|
|
|
'File' => $file, |
638
|
|
|
|
|
|
|
'Line' => $line, |
639
|
|
|
|
|
|
|
}; |
640
|
183
|
|
|
|
|
330
|
return 1; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
$log->error( |
644
|
0
|
|
0
|
|
|
0
|
"Parsed " . ( $code || "" ) . " but something missing!!", |
645
|
|
|
|
|
|
|
cell => 1, |
646
|
|
|
|
|
|
|
); |
647
|
0
|
|
|
|
|
0
|
return 0; |
648
|
13
|
|
|
|
|
122
|
}; |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
# determine language from file name |
651
|
13
|
|
|
|
|
134
|
my ( $lang ) = $ARGS{'File'} =~ m/_Message_([^_]+).conf$/; |
652
|
13
|
100
|
|
|
|
43
|
if ( not $lang ) { |
653
|
1
|
|
|
|
|
12
|
$log->warn( |
654
|
|
|
|
|
|
|
"Could not determine language from filename $ARGS{'File'} " . |
655
|
|
|
|
|
|
|
"-- reverting to default language ->en<-", |
656
|
|
|
|
|
|
|
cell => 1, |
657
|
|
|
|
|
|
|
); |
658
|
1
|
|
|
|
|
2
|
$lang = 'en'; |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
# open the file for reading |
662
|
13
|
50
|
|
|
|
481
|
open( my $fh, "<", $ARGS{'File'} ) |
663
|
|
|
|
|
|
|
or die "cannot open < $ARGS{'File'}: $!"; |
664
|
|
|
|
|
|
|
|
665
|
13
|
|
|
|
|
44
|
my @stanza = (); |
666
|
13
|
|
|
|
|
90
|
my $index = 0; |
667
|
13
|
|
|
|
|
23
|
my $count = 0; |
668
|
13
|
|
|
|
|
23
|
my $line = 0; |
669
|
13
|
|
|
|
|
347
|
while ( <$fh> ) { |
670
|
1036
|
|
|
|
|
1268
|
chomp( $_ ); |
671
|
1036
|
|
|
|
|
982
|
$line += 1; |
672
|
|
|
|
|
|
|
#$log->debug( "Read line =>$_<= from $ARGS{'File'}", cell => 1 ); |
673
|
1036
|
100
|
|
|
|
1842
|
$_ = '' if /^\s+$/; |
674
|
1036
|
100
|
|
|
|
1280
|
if ( $_ ) { |
675
|
840
|
100
|
|
|
|
1916
|
if ( ! /^\s*#/ ) { |
676
|
377
|
|
|
|
|
1078
|
s/^\s*//g; |
677
|
377
|
|
|
|
|
1988
|
s/\s*$//g; |
678
|
377
|
|
|
|
|
1179
|
$stanza[ $index++ ] = $_; |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
} else { |
681
|
|
|
|
|
|
|
$count += &$process_stanza_sub( $ARGS{'File'}, $line, $lang, \@stanza, |
682
|
196
|
100
|
|
|
|
460
|
$ARGS{'Dest'} ) if @stanza; |
683
|
196
|
|
|
|
|
280
|
@stanza = (); |
684
|
196
|
|
|
|
|
544
|
$index = 0; |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
# There might be one stanza left at the end |
688
|
|
|
|
|
|
|
$count += &$process_stanza_sub( $ARGS{'File'}, $line, $lang, \@stanza, |
689
|
13
|
100
|
|
|
|
89
|
$ARGS{'Dest'} ) if @stanza; |
690
|
|
|
|
|
|
|
|
691
|
13
|
|
|
|
|
157
|
close $fh; |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
# $log->info( "Parsed and loaded $count configuration stanzas " |
694
|
|
|
|
|
|
|
# . "from $ARGS{'File'}", cell => 1 ); |
695
|
|
|
|
|
|
|
|
696
|
13
|
|
|
|
|
226
|
return $count; |
697
|
|
|
|
|
|
|
}; |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=head2 parse_config_file |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
Parses a configuration file and adds the parameters found to the hashref |
703
|
|
|
|
|
|
|
provided. If a parameter already exists in the hashref, a warning is |
704
|
|
|
|
|
|
|
generated, the existing parameter is not overwritten, and processing |
705
|
|
|
|
|
|
|
continues. |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
This function doesn't care what type of configuration parameters |
708
|
|
|
|
|
|
|
are in the file, except that they must be scalar values. Since the |
709
|
|
|
|
|
|
|
configuration files are actually Perl modules, the value can even be |
710
|
|
|
|
|
|
|
a reference (to an array, a hash, or a subroutine, or any other complex |
711
|
|
|
|
|
|
|
data structure). |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
The technique used in the C, derived from Request Tracker, can be |
714
|
|
|
|
|
|
|
described as follows: a local typeglob "set" is defined, containing a |
715
|
|
|
|
|
|
|
reference to an anonymous subroutine. Subsequently, a config file (Perl |
716
|
|
|
|
|
|
|
module) consisting of calls to this "set" subroutine is Cd. |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
Note: If even one call to C fails to compile, the entire file will be |
719
|
|
|
|
|
|
|
rejected and no configuration parameters from that file will be loaded. |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
The C function takes a PARAMHASH consisting of: |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
=over |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=item C - filename (full path) |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=item C - hash reference (where to store the config params). |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=back |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
Returns: number of configuration parameters parsed/loaded |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
(IMPORTANT NOTE: If even one call to C fails to compile, the entire |
734
|
|
|
|
|
|
|
file will be rejected and no configuration parameters from that file will |
735
|
|
|
|
|
|
|
be loaded.) |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=cut |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
sub parse_config_file { |
740
|
31
|
|
|
31
|
1
|
385
|
my %ARGS = ( |
741
|
|
|
|
|
|
|
'File' => undef, |
742
|
|
|
|
|
|
|
'Dest' => undef, |
743
|
|
|
|
|
|
|
@_, |
744
|
|
|
|
|
|
|
); |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
# This is so we can use the C<$self> variable (in the C |
747
|
|
|
|
|
|
|
# statement, below) to reach the C<_conf_from_config> functions from |
748
|
|
|
|
|
|
|
# the configuration file. |
749
|
31
|
|
|
|
|
58
|
my $self = {}; |
750
|
31
|
|
|
|
|
79
|
bless $self, 'App::CELL::Load'; |
751
|
|
|
|
|
|
|
|
752
|
31
|
|
|
|
|
51
|
my $count = 0; |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
# ideally this should be 'debug' for sharedir and 'info' for sitedir |
755
|
|
|
|
|
|
|
# but in this routine I have no easy way of telling one from the other |
756
|
31
|
|
|
|
|
165
|
$log->debug( "Loading =>$ARGS{'File'}<=", cell => 1 ); |
757
|
31
|
50
|
|
|
|
87
|
if ( not ref( $ARGS{'Dest'} ) ) { |
758
|
0
|
|
|
|
|
0
|
$log->warn( |
759
|
|
|
|
|
|
|
"Something strange happened: destination is not a reference?!?", |
760
|
|
|
|
|
|
|
cell => 1, |
761
|
|
|
|
|
|
|
); |
762
|
|
|
|
|
|
|
} |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
{ |
765
|
14
|
|
|
14
|
|
95
|
use Try::Tiny; |
|
14
|
|
|
|
|
32
|
|
|
14
|
|
|
|
|
7901
|
|
|
31
|
|
|
|
|
43
|
|
766
|
|
|
|
|
|
|
try { |
767
|
|
|
|
|
|
|
local *set = sub(@) { |
768
|
156
|
|
|
|
|
241
|
my $number_of_params = scalar @_; |
769
|
156
|
|
|
|
|
262
|
my @params = @_; |
770
|
156
|
|
|
|
|
191
|
my $param; |
771
|
|
|
|
|
|
|
my $value; |
772
|
156
|
50
|
|
|
|
420
|
if ( $number_of_params == 0 ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
773
|
0
|
|
|
|
|
0
|
my $msg = "set() called with no parameters"; |
774
|
0
|
|
|
|
|
0
|
$log->crit( $msg, cell => 1 ); |
775
|
0
|
|
|
|
|
0
|
die $msg; |
776
|
|
|
|
|
|
|
} elsif ( $number_of_params == 1 ) { |
777
|
1
|
|
|
|
|
2
|
$param = $params[0]; |
778
|
1
|
|
|
|
|
7
|
$log->warn( |
779
|
|
|
|
|
|
|
"set() called with parameter $param but no value - set to \"\"", |
780
|
|
|
|
|
|
|
cell => 1, |
781
|
|
|
|
|
|
|
); |
782
|
|
|
|
|
|
|
} elsif ( $number_of_params == 2 ) { |
783
|
154
|
|
|
|
|
187
|
$param = $params[0]; |
784
|
154
|
|
|
|
|
165
|
$value = $params[1]; |
785
|
154
|
|
|
|
|
632
|
$log->debug( |
786
|
|
|
|
|
|
|
"set() called with parameter $param and one value", |
787
|
|
|
|
|
|
|
cell => 1, |
788
|
|
|
|
|
|
|
); |
789
|
|
|
|
|
|
|
} else { |
790
|
1
|
|
|
|
|
1
|
$param = $params[0]; |
791
|
1
|
|
|
|
|
2
|
$value = $params[1]; |
792
|
1
|
|
|
|
|
5
|
$log->warn( |
793
|
|
|
|
|
|
|
"set() called with $number_of_params parameters. Only " . |
794
|
|
|
|
|
|
|
"the first two were used; the rest were ignored.", |
795
|
|
|
|
|
|
|
cell => 1, |
796
|
|
|
|
|
|
|
); |
797
|
|
|
|
|
|
|
} |
798
|
156
|
|
|
|
|
337
|
my ( undef, $file, $line ) = caller; |
799
|
|
|
|
|
|
|
$count += $self->_conf_from_config( |
800
|
156
|
|
|
|
|
362
|
'Dest' => $ARGS{'Dest'}, |
801
|
|
|
|
|
|
|
'Param' => $param, |
802
|
|
|
|
|
|
|
'Value' => $value, |
803
|
|
|
|
|
|
|
'File' => $file, |
804
|
|
|
|
|
|
|
'Line' => $line, |
805
|
|
|
|
|
|
|
); |
806
|
31
|
|
|
31
|
|
1266
|
}; |
807
|
31
|
|
|
|
|
12853
|
require $ARGS{'File'}; |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
catch { |
810
|
0
|
|
|
0
|
|
0
|
my $errmsg = $_; |
811
|
0
|
|
|
|
|
0
|
$errmsg =~ s/\012/ -- /g; |
812
|
0
|
|
|
|
|
0
|
$log->err( |
813
|
|
|
|
|
|
|
"CELL_CONFIG_LOAD_FAIL on file $ARGS{File} with error message: $errmsg", |
814
|
|
|
|
|
|
|
cell => 1, |
815
|
|
|
|
|
|
|
); |
816
|
0
|
|
|
|
|
0
|
$log->debug( "The count is $count", cell => 1 ); |
817
|
0
|
|
|
|
|
0
|
return $count; |
818
|
31
|
|
|
|
|
215
|
}; |
819
|
|
|
|
|
|
|
} |
820
|
|
|
|
|
|
|
#$log->info( "Successfully loaded $count configuration parameters " |
821
|
|
|
|
|
|
|
# . "from $ARGS{'File'}", cell => 1 ); |
822
|
|
|
|
|
|
|
|
823
|
31
|
|
|
|
|
613
|
return $count; |
824
|
|
|
|
|
|
|
} |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=head2 _conf_from_config |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
This function takes a target hashref (which points to one of the 'meta', |
830
|
|
|
|
|
|
|
'core', or 'site' package hashes in C), a config parameter |
831
|
|
|
|
|
|
|
(i.e. a string), config value, config file name, and line number. |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Let's imagine that the configuration parameter is "FOO_BAR". The function |
834
|
|
|
|
|
|
|
first checks if a key named "FOO_BAR" already exists in the package hash |
835
|
|
|
|
|
|
|
(which is passed into the function as C<%ARGS{'Dest'}>). If there isn't |
836
|
|
|
|
|
|
|
one, it creates that key. If there is one, it leaves it untouched and |
837
|
|
|
|
|
|
|
triggers a warning. |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
Although the arguments are passed to the function in the form of a |
840
|
|
|
|
|
|
|
PARAMHASH, the function converts them into ordinary private variables. |
841
|
|
|
|
|
|
|
This was necessary to avoid extreme notational ugliness. |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
=cut |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
sub _conf_from_config { |
846
|
156
|
|
|
156
|
|
188
|
my $self = shift; |
847
|
156
|
|
|
|
|
3433
|
my ( %ARGS ) = validate( @_, { |
848
|
|
|
|
|
|
|
Dest => { type => HASHREF }, |
849
|
|
|
|
|
|
|
Param => { type => SCALAR }, |
850
|
|
|
|
|
|
|
Value => { type => SCALAR|SCALARREF|ARRAYREF|HASHREF|CODEREF|UNDEF }, |
851
|
|
|
|
|
|
|
File => { type => SCALAR }, |
852
|
|
|
|
|
|
|
Line => { type => SCALAR }, |
853
|
|
|
|
|
|
|
} ); |
854
|
|
|
|
|
|
|
# convert PARAMHASH into private variables |
855
|
156
|
|
|
|
|
772
|
my $desthash = $ARGS{'Dest'}; |
856
|
156
|
|
|
|
|
198
|
my $param = $ARGS{'Param'}; |
857
|
156
|
|
|
|
|
213
|
my $value = $ARGS{'Value'}; |
858
|
156
|
|
|
|
|
240
|
my $file = $ARGS{'File'}; |
859
|
156
|
|
|
|
|
182
|
my $line = $ARGS{'Line'}; |
860
|
|
|
|
|
|
|
|
861
|
156
|
100
|
|
|
|
189
|
if ( keys( %{ $desthash->{ $param } } ) ) |
|
156
|
|
|
|
|
458
|
|
862
|
|
|
|
|
|
|
{ |
863
|
|
|
|
|
|
|
$log->warn( |
864
|
|
|
|
|
|
|
"ignoring duplicate definition of config parameter $param in line $line " . |
865
|
|
|
|
|
|
|
"of config file $file because it conflicts with a similar parameter in " . |
866
|
2
|
|
|
|
|
32
|
$desthash->{ $param }->{'File'}, |
867
|
|
|
|
|
|
|
cell => 1, |
868
|
|
|
|
|
|
|
); |
869
|
2
|
|
|
|
|
8
|
return 0; |
870
|
|
|
|
|
|
|
} else { |
871
|
154
|
|
|
|
|
368
|
$desthash->{ $param } = { |
872
|
|
|
|
|
|
|
'Value' => $value, |
873
|
|
|
|
|
|
|
'File' => $file, |
874
|
|
|
|
|
|
|
'Line' => $line, |
875
|
|
|
|
|
|
|
}; |
876
|
154
|
100
|
|
|
|
612
|
$log->debug( |
877
|
|
|
|
|
|
|
"Parsed parameter $param from $file, line $line", |
878
|
|
|
|
|
|
|
cell => 1, |
879
|
|
|
|
|
|
|
suppress_caller => 1 |
880
|
|
|
|
|
|
|
) if $meta->CELL_META_LOAD_VERBOSE; |
881
|
154
|
|
|
|
|
535
|
return 1; |
882
|
|
|
|
|
|
|
} |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
1; |