Filename | /var/www/foswiki11/lib/Foswiki/Configure/Load.pm |
Statements | Executed 2349 statements in 13.7ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 8.88ms | 13.2ms | readConfig | Foswiki::Configure::Load::
741 | 4 | 2 | 3.72ms | 4.32ms | expandValue (recurses: max depth 4, inclusive time 8.33ms) | Foswiki::Configure::Load::
23 | 1 | 1 | 606µs | 606µs | _handleExpand | Foswiki::Configure::Load::
1 | 1 | 1 | 20µs | 43µs | BEGIN@14 | Foswiki::Configure::Load::
1 | 1 | 1 | 14µs | 24µs | BEGIN@15 | Foswiki::Configure::Load::
0 | 0 | 0 | 0s | 0s | _loadDefaultsFrom | Foswiki::Configure::Load::
0 | 0 | 0 | 0s | 0s | mergeHash | Foswiki::Configure::Load::
0 | 0 | 0 | 0s | 0s | readDefaults | Foswiki::Configure::Load::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::Configure::Load | ||||
6 | |||||
7 | Handling for loading configuration information (Foswiki.spec, Config.spec and | ||||
8 | LocalSite.cfg) as efficiently and flexibly as possible. | ||||
9 | |||||
10 | =cut | ||||
11 | |||||
12 | package Foswiki::Configure::Load; | ||||
13 | |||||
14 | 2 | 40µs | 2 | 67µs | # spent 43µs (20+24) within Foswiki::Configure::Load::BEGIN@14 which was called:
# once (20µs+24µs) by Foswiki::BEGIN@51 at line 14 # spent 43µs making 1 call to Foswiki::Configure::Load::BEGIN@14
# spent 24µs making 1 call to strict::import |
15 | 2 | 1.52ms | 2 | 34µs | # spent 24µs (14+10) within Foswiki::Configure::Load::BEGIN@15 which was called:
# once (14µs+10µs) by Foswiki::BEGIN@51 at line 15 # spent 24µs making 1 call to Foswiki::Configure::Load::BEGIN@15
# spent 10µs making 1 call to warnings::import |
16 | |||||
17 | 1 | 500ns | our $TRUE = 1; | ||
18 | 1 | 100ns | our $FALSE = 0; | ||
19 | |||||
20 | # Configuration items that have been deprecated and must be mapped to | ||||
21 | # new configuration items. The value is mapped unchanged. | ||||
22 | 1 | 5µs | our %remap = ( | ||
23 | '{StoreImpl}' => '{Store}{Implementation}', | ||||
24 | '{AutoAttachPubFiles}' => '{RCS}{AutoAttachPubFiles}', | ||||
25 | '{QueryAlgorithm}' => '{Store}{QueryAlgorithm}', | ||||
26 | '{SearchAlgorithm}' => '{Store}{SearchAlgorithm}', | ||||
27 | '{RCS}{FgrepCmd}' => '{Store}{FgrepCmd}', | ||||
28 | '{RCS}{EgrepCmd}' => '{Store}{EgrepCmd}', | ||||
29 | ); | ||||
30 | |||||
31 | =begin TML | ||||
32 | |||||
33 | ---++ StaticMethod readConfig([$noexpand]) | ||||
34 | |||||
35 | In normal Foswiki operations as a web server this method is called by the | ||||
36 | =BEGIN= block of =Foswiki.pm=. However, when benchmarking/debugging it can be | ||||
37 | replaced by custom code which sets the configuration hash. To prevent us from | ||||
38 | overriding the custom code again, we use an "unconfigurable" key | ||||
39 | =$cfg{ConfigurationFinished}= as an indicator. | ||||
40 | |||||
41 | Note that this method is called by Foswiki and configure, and *only* reads | ||||
42 | Foswiki.spec= to get defaults. Other spec files (those for extensions) are | ||||
43 | *not* read. | ||||
44 | |||||
45 | The assumption is that =configure= will be run when an extension is installed, | ||||
46 | and that will add the config values to LocalSite.cfg, so no defaults are | ||||
47 | needed. Foswiki.spec is still read because so much of the core code doesn't | ||||
48 | provide defaults, and it would be silly to have them in two places anyway. | ||||
49 | |||||
50 | $noexpand can be set to suppress expansion of $Foswiki vars embedded in | ||||
51 | values. | ||||
52 | |||||
53 | =cut | ||||
54 | |||||
55 | # spent 13.2ms (8.88+4.29) within Foswiki::Configure::Load::readConfig which was called:
# once (8.88ms+4.29ms) by Foswiki::BEGIN@137 at line 334 of /var/www/foswiki11/lib/Foswiki.pm | ||||
56 | 1 | 800ns | my $noexpand = shift; | ||
57 | |||||
58 | 1 | 500ns | return if $Foswiki::cfg{ConfigurationFinished}; | ||
59 | 1 | 300ns | my $validLSC = | ||
60 | 1; # Assume it's valid - will be set false if errors detected. | ||||
61 | |||||
62 | # Read Foswiki.spec and LocalSite.cfg | ||||
63 | 1 | 1µs | for my $file (qw( Foswiki.spec LocalSite.cfg)) { | ||
64 | 2 | 7.54ms | unless ( my $return = do $file ) { | ||
65 | my $errorMessage; | ||||
66 | if ($@) { | ||||
67 | $errorMessage = "Could not parse $file: $@"; | ||||
68 | print STDERR "$errorMessage \n"; | ||||
69 | } | ||||
70 | elsif ( not defined $return ) { | ||||
71 | print STDERR | ||||
72 | "Could not 'do' $file: $! \n - This might be okay if file LocalSite.cfg does not exist in a new installation.\n"; | ||||
73 | unless ( $! == 2 && $file eq 'LocalSite.cfg' ) { | ||||
74 | |||||
75 | # LocalSite.cfg doesn't exist, which is OK | ||||
76 | $errorMessage = "Could not do $file: $!"; | ||||
77 | } | ||||
78 | $validLSC = 0; | ||||
79 | } | ||||
80 | elsif ( not $return eq '1' ) { | ||||
81 | print STDERR | ||||
82 | "Running file $file returned unexpected results: $return \n"; | ||||
83 | $errorMessage = "Could not run $file" unless $return; | ||||
84 | } | ||||
85 | if ($errorMessage) { | ||||
86 | die <<GOLLYGOSH; | ||||
87 | Content-type: text/plain | ||||
88 | |||||
89 | $errorMessage | ||||
90 | Please inform the site admin. | ||||
91 | GOLLYGOSH | ||||
92 | exit 1; | ||||
93 | } | ||||
94 | } | ||||
95 | } | ||||
96 | |||||
97 | # If we got this far without definitions for key variables, then | ||||
98 | # we need to default them. otherwise we get peppered with | ||||
99 | # 'uninitialised variable' alerts later. | ||||
100 | |||||
101 | 1 | 1µs | foreach my $var ( | ||
102 | qw( DataDir DefaultUrlHost PubUrlPath ToolsDir WorkingDir | ||||
103 | PubDir TemplateDir ScriptDir ScriptUrlPath LocalesDir ) | ||||
104 | ) | ||||
105 | { | ||||
106 | |||||
107 | # We can't do this, because it prevents Foswiki being run without | ||||
108 | # a LocalSite.cfg, which we don't want | ||||
109 | # die "$var must be defined in LocalSite.cfg" | ||||
110 | # unless( defined $Foswiki::cfg{$var} ); | ||||
111 | 10 | 5µs | unless ( defined $Foswiki::cfg{$var} ) { | ||
112 | $Foswiki::cfg{$var} = 'NOT SET'; | ||||
113 | $validLSC = 0; | ||||
114 | } | ||||
115 | } | ||||
116 | |||||
117 | # Patch deprecated config settings | ||||
118 | 1 | 500ns | if ( exists $Foswiki::cfg{StoreImpl} ) { | ||
119 | $Foswiki::cfg{Store}{Implementation} = | ||||
120 | 'Foswiki::Store::' . $Foswiki::cfg{StoreImpl}; | ||||
121 | delete $Foswiki::cfg{StoreImpl}; | ||||
122 | } | ||||
123 | 1 | 3µs | foreach my $el ( keys %remap ) { | ||
124 | 6 | 278µs | if ( eval 'exists $Foswiki::cfg' . $el ) { # spent 9µs executing statements in string eval
# spent 4µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 2µs executing statements in string eval
# spent 2µs executing statements in string eval
# spent 2µs executing statements in string eval | ||
125 | eval <<CODE; | ||||
126 | \$Foswiki::cfg$remap{$el}=\$Foswiki::cfg$el; | ||||
127 | delete \$Foswiki::cfg$el; | ||||
128 | CODE | ||||
129 | } | ||||
130 | } | ||||
131 | |||||
132 | # Expand references to $Foswiki::cfg vars embedded in the values of | ||||
133 | # other $Foswiki::cfg vars. | ||||
134 | 1 | 3µs | 1 | 4.29ms | expandValue( \%Foswiki::cfg ) unless $noexpand; # spent 4.29ms making 1 call to Foswiki::Configure::Load::expandValue |
135 | |||||
136 | 1 | 1µs | $Foswiki::cfg{ConfigurationFinished} = 1; | ||
137 | |||||
138 | #on Windows, File::Spec returns a really useless empty string for tempdir under apache | ||||
139 | #(in its unix code, it assumes /tmp - but at least thats standard..) | ||||
140 | #so defaulting $ENV{TMP} can get us limping along (and can over-ride using TMPDIR or TEMP env | ||||
141 | 1 | 1µs | if ( $^O eq 'MSWin32' ) { | ||
142 | |||||
143 | #force paths to use '/' | ||||
144 | $Foswiki::cfg{PubDir} =~ s|\\|/|g; | ||||
145 | $Foswiki::cfg{DataDir} =~ s|\\|/|g; | ||||
146 | $Foswiki::cfg{ToolsDir} =~ s|\\|/|g; | ||||
147 | $Foswiki::cfg{ScriptDir} =~ s|\\|/|g; | ||||
148 | $Foswiki::cfg{TemplateDir} =~ s|\\|/|g; | ||||
149 | $Foswiki::cfg{LocalesDir} =~ s|\\|/|g; | ||||
150 | $Foswiki::cfg{WorkingDir} =~ s|\\|/|g; | ||||
151 | |||||
152 | #$ENV{TMPDIR} | ||||
153 | #$ENV{TEMP} | ||||
154 | #$ENV{TMP} | ||||
155 | $ENV{TMP} = $Foswiki::cfg{WorkingDir}; | ||||
156 | } | ||||
157 | |||||
158 | # Alias TWiki cfg to Foswiki cfg for plugins and contribs | ||||
159 | 1 | 2µs | *TWiki::cfg = \%Foswiki::cfg; | ||
160 | |||||
161 | # Explicit return true if we've completed the load | ||||
162 | 1 | 5µs | return $validLSC; | ||
163 | } | ||||
164 | |||||
165 | =begin TML | ||||
166 | |||||
167 | ---++ StaticMethod expandValue($datum) | ||||
168 | |||||
169 | Expands references to Foswiki configuration items which occur in the | ||||
170 | values configuration items contained within the datum, which may be a | ||||
171 | hash reference or a scalar value. The replacement is done in-place. | ||||
172 | |||||
173 | =cut | ||||
174 | |||||
175 | # spent 4.32ms (3.72+606µs) within Foswiki::Configure::Load::expandValue which was called 741 times, avg 6µs/call:
# 652 times (3.18ms+-3.18ms) by Foswiki::Configure::Load::expandValue at line 177, avg 0s/call
# 85 times (155µs+-155µs) by Foswiki::Configure::Load::expandValue at line 180, avg 0s/call
# 3 times (32µs+0s) by Foswiki::Logger::PlainFile::_getLogForLevel at line 249 of /var/www/foswiki11/lib/Foswiki/Logger/PlainFile.pm, avg 11µs/call
# once (348µs+3.94ms) by Foswiki::Configure::Load::readConfig at line 134 | ||||
176 | 741 | 1.78ms | if ( ref( $_[0] ) eq 'HASH' ) { | ||
177 | 820 | 1.11ms | 652 | 0s | map { expandValue($_) } values %{ $_[0] }; # spent 8.18ms making 652 calls to Foswiki::Configure::Load::expandValue, avg 13µs/call, recursion: max depth 4, sum of overlapping time 8.18ms |
178 | } | ||||
179 | elsif ( ref( $_[0] ) eq 'ARRAY' ) { | ||||
180 | 88 | 113µs | 85 | 0s | map { expandValue($_) } @{ $_[0] }; # spent 155µs making 85 calls to Foswiki::Configure::Load::expandValue, avg 2µs/call, recursion: max depth 3, sum of overlapping time 155µs |
181 | |||||
182 | # Can't do this, because Windows uses an object (Regexp) for regular | ||||
183 | # expressions. | ||||
184 | # } elsif (ref($_[0])) { | ||||
185 | # Carp::confess("Can't handle a ".ref($_[0])); | ||||
186 | } | ||||
187 | elsif ( defined( $_[0] ) ) { | ||||
188 | 570 | 621µs | while ( | ||
189 | 23 | 34µs | 23 | 606µs | $_[0] =~ s/(\$Foswiki::cfg{[[A-Za-z0-9{}]+})/_handleExpand($1)/ge ) # spent 606µs making 23 calls to Foswiki::Configure::Load::_handleExpand, avg 26µs/call |
190 | { | ||||
191 | } | ||||
192 | } | ||||
193 | } | ||||
194 | |||||
195 | # Used to expand the $Foswiki::cfg variable in the expand* routines. | ||||
196 | # Resolves issue with defined but null variables expanding as "undef" | ||||
197 | # Tasks:Item5608 | ||||
198 | # spent 606µs within Foswiki::Configure::Load::_handleExpand which was called 23 times, avg 26µs/call:
# 23 times (606µs+0s) by Foswiki::Configure::Load::expandValue at line 189, avg 26µs/call | ||||
199 | 23 | 504µs | my $val = eval $_[0]; # spent 14µs executing statements in 5 string evals (merged)
# spent 12µs executing statements in 4 string evals (merged)
# spent 11µs executing statements in 4 string evals (merged)
# spent 10µs executing statements in 4 string evals (merged)
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval | ||
200 | 23 | 6µs | $val = ( defined $val ) ? $val : 'undef'; | ||
201 | 23 | 86µs | return $val; | ||
202 | } | ||||
203 | |||||
204 | =begin TML | ||||
205 | |||||
206 | ---++ StaticMethod readDefaults() -> \@errors | ||||
207 | |||||
208 | This is only called by =configure= to initialise the Foswiki config hash with | ||||
209 | default values from the .spec files. | ||||
210 | |||||
211 | Normally all configuration values come from LocalSite.cfg. However when | ||||
212 | =configure= runs it has to get default values for config vars that have not | ||||
213 | yet been saved to =LocalSite.cfg=. | ||||
214 | |||||
215 | Returns a reference to a list of the errors it saw. | ||||
216 | |||||
217 | SEE ALSO: Foswiki::Configure::FoswikiCfg::load | ||||
218 | |||||
219 | =cut | ||||
220 | |||||
221 | sub readDefaults { | ||||
222 | my %read = (); | ||||
223 | my @errors; | ||||
224 | |||||
225 | eval { | ||||
226 | do 'Foswiki.spec'; | ||||
227 | $read{'Foswiki.spec'} = $INC{'Foswiki.spec'}; | ||||
228 | }; | ||||
229 | push( @errors, $@ ) if ($@); | ||||
230 | foreach my $dir (@INC) { | ||||
231 | my $root; # SMELL: Not used | ||||
232 | _loadDefaultsFrom( "$dir/Foswiki/Plugins", $root, \%read, \@errors ); | ||||
233 | _loadDefaultsFrom( "$dir/Foswiki/Contrib", $root, \%read, \@errors ); | ||||
234 | _loadDefaultsFrom( "$dir/TWiki/Plugins", $root, \%read, \@errors ); | ||||
235 | _loadDefaultsFrom( "$dir/TWiki/Contrib", $root, \%read, \@errors ); | ||||
236 | } | ||||
237 | |||||
238 | # SMELL: This will create the %TWiki::cfg | ||||
239 | # But as it ought to be aliased to %Foswiki::cfg, it's not a big deal | ||||
240 | # XXX: Do we still need this code? | ||||
241 | if ( %TWiki::cfg && \%TWiki::cfg != \%Foswiki::cfg ) { | ||||
242 | |||||
243 | # We had some TWiki plugins, need to map their config to Foswiki | ||||
244 | sub mergeHash { | ||||
245 | |||||
246 | # Merges the keys in the right hashref to the ones in the | ||||
247 | # left hashref | ||||
248 | my ( $left, $right, $errors ) = @_; | ||||
249 | while ( my ( $key, $value ) = each %$right ) { | ||||
250 | if ( exists $left->{$key} ) { | ||||
251 | if ( ref($value) ne ref( $left->{$key} ) ) { | ||||
252 | push @$errors, | ||||
253 | 'Trying to overwrite $Foswiki::cfg{' | ||||
254 | . $key | ||||
255 | . '} with its $TWiki::cfg version (' | ||||
256 | . $value . ')'; | ||||
257 | } | ||||
258 | elsif ( ref($value) eq 'SCALAR' ) { | ||||
259 | $left->{$key} = $value; | ||||
260 | } | ||||
261 | elsif ( ref($value) eq 'HASH' ) { | ||||
262 | $left->{$key} = | ||||
263 | mergeHash( $left->{$key}, $value, $errors ); | ||||
264 | } | ||||
265 | elsif ( ref($value) eq 'ARRAY' ) { | ||||
266 | |||||
267 | # It's an array. try to be smart | ||||
268 | # SMELL: Ideally, it should keep order too | ||||
269 | foreach my $item (@$value) { | ||||
270 | unless ( grep /^$item$/, @{ $left->{$key} } ) { | ||||
271 | |||||
272 | # The item isn't in the current list, | ||||
273 | # add it at the end | ||||
274 | unshift @{ $left->{$key} }, $item; | ||||
275 | } | ||||
276 | } | ||||
277 | } | ||||
278 | else { | ||||
279 | |||||
280 | # It's something else (GLOB, coderef, ...) | ||||
281 | push @$errors, | ||||
282 | '$TWiki::cfg{' | ||||
283 | . $key | ||||
284 | . '} is a reference to a' | ||||
285 | . ref($value) | ||||
286 | . '. No idea how to merge that, sorry.'; | ||||
287 | } | ||||
288 | } | ||||
289 | else { | ||||
290 | |||||
291 | # We don't already have such a key in the Foswiki scope | ||||
292 | $left->{$key} = $value; | ||||
293 | } | ||||
294 | } | ||||
295 | return $left; | ||||
296 | } | ||||
297 | mergeHash \%Foswiki::cfg, \%TWiki::cfg, \@errors; | ||||
298 | } | ||||
299 | |||||
300 | return \@errors; | ||||
301 | } | ||||
302 | |||||
303 | sub _loadDefaultsFrom { | ||||
304 | my ( $dir, $root, $read, $errors ) = @_; | ||||
305 | |||||
306 | return unless opendir( D, $dir ); | ||||
307 | foreach my $extension ( grep { !/^\./ } readdir D ) { | ||||
308 | $extension =~ /(.*)/; | ||||
309 | $extension = $1; # untaint | ||||
310 | next if $read->{$extension}; | ||||
311 | my $file = "$dir/$extension/Config.spec"; | ||||
312 | next unless -e $file; | ||||
313 | eval { do $file; }; | ||||
314 | push( @$errors, $@ ) if ($@); | ||||
315 | $read->{$extension} = $file; | ||||
316 | } | ||||
317 | closedir(D); | ||||
318 | } | ||||
319 | |||||
320 | 1 | 6µs | 1; | ||
321 | __END__ |