Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/Configure/Load.pm |
Statements | Executed 2046 statements in 24.4ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 11.7ms | 24.5ms | readConfig | Foswiki::Configure::Load::
596 | 4 | 2 | 11.2ms | 12.8ms | expandValue (recurses: max depth 4, inclusive time 26.6ms) | Foswiki::Configure::Load::
467 | 1 | 1 | 788µs | 788µs | CORE:subst (opcode) | Foswiki::Configure::Load::
20 | 1 | 1 | 766µs | 766µs | _handleExpand | Foswiki::Configure::Load::
33 | 1 | 1 | 107µs | 107µs | CORE:substcont (opcode) | Foswiki::Configure::Load::
1 | 1 | 1 | 28µs | 35µs | BEGIN@14 | Foswiki::Configure::Load::
4 | 4 | 1 | 20µs | 20µs | CORE:qr (opcode) | Foswiki::Configure::Load::
1 | 1 | 1 | 18µs | 47µ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 | 51µs | 2 | 43µs | # spent 35µs (28+8) within Foswiki::Configure::Load::BEGIN@14 which was called:
# once (28µs+8µs) by Foswiki::BEGIN@51 at line 14 # spent 35µs making 1 call to Foswiki::Configure::Load::BEGIN@14
# spent 8µs making 1 call to strict::import |
15 | 2 | 1.81ms | 2 | 76µs | # spent 47µs (18+29) within Foswiki::Configure::Load::BEGIN@15 which was called:
# once (18µs+29µs) by Foswiki::BEGIN@51 at line 15 # spent 47µs making 1 call to Foswiki::Configure::Load::BEGIN@15
# spent 29µs making 1 call to warnings::import |
16 | |||||
17 | 1 | 2µs | our $TRUE = 1; | ||
18 | 1 | 1µs | 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 | 6µ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 24.5ms (11.7+12.8) within Foswiki::Configure::Load::readConfig which was called:
# once (11.7ms+12.8ms) by Foswiki::BEGIN@134 at line 331 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm | ||||
56 | 12 | 61µs | my $noexpand = shift; | ||
57 | |||||
58 | return if $Foswiki::cfg{ConfigurationFinished}; | ||||
59 | my $validLSC = | ||||
60 | 1; # Assume it's valid - will be set false if errors detected. | ||||
61 | |||||
62 | # Read Foswiki.spec and LocalSite.cfg | ||||
63 | for my $file (qw( Foswiki.spec LocalSite.cfg)) { | ||||
64 | 2 | 9.46ms | 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 | 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 | 30µs | unless ( defined $Foswiki::cfg{$var} ) { | ||
112 | $Foswiki::cfg{$var} = 'NOT SET'; | ||||
113 | $validLSC = 0; | ||||
114 | } | ||||
115 | } | ||||
116 | |||||
117 | # Patch deprecated config settings | ||||
118 | if ( exists $Foswiki::cfg{StoreImpl} ) { | ||||
119 | $Foswiki::cfg{Store}{Implementation} = | ||||
120 | 'Foswiki::Store::' . $Foswiki::cfg{StoreImpl}; | ||||
121 | delete $Foswiki::cfg{StoreImpl}; | ||||
122 | } | ||||
123 | foreach my $el ( keys %remap ) { | ||||
124 | 6 | 244µs | if ( eval 'exists $Foswiki::cfg' . $el ) { # spent 6µs executing statements in string eval
# spent 6µs executing statements in string eval
# spent 6µs executing statements in string eval
# spent 5µs executing statements in string eval
# spent 5µs executing statements in string eval
# spent 5µ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 | 12.8ms | expandValue( \%Foswiki::cfg ) unless $noexpand; # spent 12.8ms making 1 call to Foswiki::Configure::Load::expandValue | ||
135 | |||||
136 | $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 | 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 | *TWiki::cfg = \%Foswiki::cfg; | ||||
160 | |||||
161 | # Explicit return true if we've completed the load | ||||
162 | 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 12.8ms (11.2+1.66) within Foswiki::Configure::Load::expandValue which was called 596 times, avg 22µs/call:
# 535 times (9.63ms+-9.63ms) by Foswiki::Configure::Load::expandValue at line 177, avg 0s/call
# 59 times (681µs+-681µs) by Foswiki::Configure::Load::expandValue at line 180, avg 0s/call
# once (821µs+12.0ms) by Foswiki::Configure::Load::readConfig at line 134
# once (25µs+6µs) by Foswiki::Logger::PlainFile::_getLogForLevel at line 239 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Logger/PlainFile.pm | ||||
176 | 1192 | 8.94ms | if ( ref( $_[0] ) eq 'HASH' ) { | ||
177 | 676 | 2.70ms | 535 | 0s | map { expandValue($_) } values %{ $_[0] }; # spent 25.9ms making 535 calls to Foswiki::Configure::Load::expandValue, avg 48µs/call, recursion: max depth 4, sum of overlapping time 25.9ms |
178 | } | ||||
179 | elsif ( ref( $_[0] ) eq 'ARRAY' ) { | ||||
180 | 60 | 268µs | 59 | 0s | map { expandValue($_) } @{ $_[0] }; # spent 768µs making 59 calls to Foswiki::Configure::Load::expandValue, avg 13µs/call, recursion: max depth 2, sum of overlapping time 768µ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 | 20 | 99µs | 500 | 895µs | while ( # spent 788µs making 467 calls to Foswiki::Configure::Load::CORE:subst, avg 2µs/call
# spent 107µs making 33 calls to Foswiki::Configure::Load::CORE:substcont, avg 3µs/call |
189 | 20 | 766µs | $_[0] =~ s/(\$Foswiki::cfg{[[A-Za-z0-9{}]+})/_handleExpand($1)/ge ) # spent 766µs making 20 calls to Foswiki::Configure::Load::_handleExpand, avg 38µ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 766µs within Foswiki::Configure::Load::_handleExpand which was called 20 times, avg 38µs/call:
# 20 times (766µs+0s) by Foswiki::Configure::Load::expandValue at line 189, avg 38µs/call | ||||
199 | 60 | 710µs | my $val = eval $_[0]; # spent 20µs executing statements in 4 string evals (merged)
# spent 19µs executing statements in 4 string evals (merged)
# spent 19µs executing statements in 4 string evals (merged)
# spent 15µs executing statements in 3 string evals (merged)
# spent 5µs executing statements in string eval
# spent 5µs executing statements in string eval
# spent 5µs executing statements in string eval
# spent 5µs executing statements in string eval
# spent 5µs executing statements in string eval | ||
200 | $val = ( defined $val ) ? $val : 'undef'; | ||||
201 | 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 | 8µs | 1; | ||
321 | __END__ | ||||
# spent 20µs within Foswiki::Configure::Load::CORE:qr which was called 4 times, avg 5µs/call:
# once (11µs+0s) by Foswiki::Configure::Load::readConfig at line 348 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec
# once (3µs+0s) by Foswiki::Configure::Load::readConfig at line 645 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec
# once (3µs+0s) by Foswiki::Configure::Load::readConfig at line 652 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec
# once (3µs+0s) by Foswiki::Configure::Load::readConfig at line 1102 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec | |||||
# spent 788µs within Foswiki::Configure::Load::CORE:subst which was called 467 times, avg 2µs/call:
# 467 times (788µs+0s) by Foswiki::Configure::Load::expandValue at line 188, avg 2µs/call | |||||
# spent 107µs within Foswiki::Configure::Load::CORE:substcont which was called 33 times, avg 3µs/call:
# 33 times (107µs+0s) by Foswiki::Configure::Load::expandValue at line 188, avg 3µs/call |