133
133
class ConfigObj(configobj.ConfigObj):
135
135
def __init__(self, infile=None, **kwargs):
136
# We define our own interpolation mechanism
136
# We define our own interpolation mechanism calling it option expansion
137
137
super(ConfigObj, self).__init__(infile=infile,
138
138
interpolation=False,
195
195
option_ref_re = None
197
def interpolate(self, string, env=None):
198
"""Interpolate the string in the configuration context.
197
def expand_options(self, string, env=None):
198
"""Expand option references in the string in the configuration context.
200
:param string: The string to interpolate
200
:param string: The string containing option to expand.
202
202
:param env: An option dict defining additional configuration options or
203
203
overriding existing ones.
205
:returns: The interpolated string.
205
:returns: The expanded string.
207
return self._interpolate_string(string, env)
207
return self._expand_options_in_string(string, env)
209
def _interpolate_list(self, slist, env=None, _ref_stack=None):
210
"""Interpolate a list of strings in the configuration context.
209
def _expand_options_in_list(self, slist, env=None, _ref_stack=None):
210
"""Expand options in a list of strings in the configuration context.
212
212
:param slist: A list of strings.
215
215
overriding existing ones.
217
217
:param _ref_stack: Private list containing the options being
218
interpolated to detect loops.
218
expanded to detect loops.
220
:returns: The flatten list of interpolated strings.
220
:returns: The flatten list of expanded strings.
222
# interpolate each value separately flattening lists
222
# expand options in each value separately flattening lists
225
value = self._interpolate_string(s, env, _ref_stack)
225
value = self._expand_options_in_string(s, env, _ref_stack)
226
226
if isinstance(value, list):
227
227
result.extend(value)
229
229
result.append(value)
232
def _interpolate_string(self, string, env=None, _ref_stack=None):
233
"""Interpolate the string in the configuration context.
232
def _expand_options_in_string(self, string, env=None, _ref_stack=None):
233
"""Expand options in the string in the configuration context.
235
:param string: The string to interpolate
235
:param string: The string to be expanded.
237
237
:param env: An option dict defining additional configuration options or
238
238
overriding existing ones.
240
240
:param _ref_stack: Private list containing the options being
241
interpolated to detect loops.
241
expanded to detect loops.
243
:returns: The interpolated string.
243
:returns: The expanded string.
245
245
if string is None:
246
# Not much to interpolate there
246
# Not much to expand there
248
248
if _ref_stack is None:
249
249
# What references are currently resolved (to detect loops)
278
278
name = chunk[1:-1]
279
279
if name in _ref_stack:
280
raise errors.InterpolationLoop(string, _ref_stack)
280
raise errors.OptionExpansionLoop(string, _ref_stack)
281
281
_ref_stack.append(name)
282
value = self._interpolate_option(name, env, _ref_stack)
282
value = self._expand_option(name, env, _ref_stack)
283
283
if value is None:
284
raise errors.InterpolationUnknownOption(name, string)
284
raise errors.ExpandingUnknownOption(name, string)
285
285
if isinstance(value, list):
286
286
list_value = True
287
287
chunks.extend(value)
291
291
chunk_is_ref = False
293
# Once a list appears as the result of an interpolation, all
293
# Once a list appears as the result of an expansion, all
294
294
# callers will get a list result. This allows a consistent
295
# behavior even when some options in the interpolation chain
296
# may be seen defined as strings even if their interpolated
295
# behavior even when some options in the expansion chain
296
# may be seen defined as strings even if their expanded
297
297
# value is a list.
298
return self._interpolate_list(chunks, env, _ref_stack)
298
return self._expand_options_in_list(chunks, env, _ref_stack)
300
300
result = ''.join(chunks)
303
def _interpolate_option(self, name, env, _ref_stack):
303
def _expand_option(self, name, env, _ref_stack):
304
304
if env is not None and name in env:
305
305
# Special case, values provided in env takes precedence over
309
309
# FIXME: This is a limited implementation, what we really need
310
310
# is a way to query the bzr config for the value of an option,
311
311
# respecting the scope rules -- vila 20101222
312
value = self.get_user_option(name, interpolate=False)
312
value = self.get_user_option(name, expand=False)
313
313
if isinstance(value, list):
314
value = self._interpolate_list(value, env, _ref_stack)
314
value = self._expand_options_in_list(value, env, _ref_stack)
316
value = self._interpolate_string(value, env, _ref_stack)
316
value = self._expand_options_in_string(value, env, _ref_stack)
319
319
def _get_user_option(self, option_name):
320
320
"""Template method to provide a user option."""
323
def get_user_option(self, option_name, interpolate=True):
324
"""Get a generic option - no special process, no default."""
323
def get_user_option(self, option_name, expand=True):
324
"""Get a generic option - no special process, no default.
327
:param option_name: The queried option.
329
:param expand: Whether options references should be expanded.
331
:returns: The value of the option.
325
333
value = self._get_user_option(option_name)
327
335
if isinstance(value, list):
328
value = self._interpolate_list(value)
336
value = self._expand_options_in_list(value)
329
337
elif isinstance(value, dict):
330
338
trace.warning('Cannot expand "%s":'
331
339
' Dicts do not support option expansion'
332
340
% (option_name,))
334
value = self._interpolate_string(value)
342
value = self._expand_options_in_string(value)
337
345
def get_user_option_as_bool(self, option_name):
340
348
:return None if the option doesn't exist or its value can't be
341
349
interpreted as a boolean. Returns True or False otherwise.
343
s = self._get_user_option(option_name)
351
s = self.get_user_option(option_name)
345
353
# The option doesn't exist
357
365
:return None if the option doesn't exist. Returns the value as a list
360
l = self._get_user_option(option_name)
368
l = self.get_user_option(option_name)
361
369
if isinstance(l, (str, unicode)):
362
370
# A single value, most probably the user forgot (or didn't care to
363
371
# add) the final ','
511
519
# This should be done through the proposed config defaults mechanism
512
520
# when it becomes available in the future.
513
521
command_line = (self.get_user_option('bzr.mergetool.%s' % name,
515
523
or mergetools.known_merge_tools.get(name, None))
516
524
return command_line