215
895
def _get_user_option(self, option_name):
216
896
"""See Config._get_user_option."""
218
return self._get_parser().get_value(self._get_section(),
897
for (section, extra_path) in self._get_matching_sections():
899
value = self._get_parser().get_value(section, option_name)
902
policy = self._get_option_policy(section, option_name)
903
if policy == POLICY_NONE:
905
elif policy == POLICY_NORECURSE:
906
# norecurse items only apply to the exact path
911
elif policy == POLICY_APPENDPATH:
913
value = urlutils.join(value, extra_path)
916
raise AssertionError('Unexpected config policy %r' % policy)
223
920
def _gpg_signing_command(self):
224
921
"""See Config.gpg_signing_command."""
225
922
return self._get_user_option('gpg_signing_command')
227
def __init__(self, get_filename):
228
super(IniBasedConfig, self).__init__()
229
self._get_filename = get_filename
924
def _log_format(self):
925
"""See Config.log_format."""
926
return self._get_user_option('log_format')
928
def _validate_signatures_in_log(self):
929
"""See Config.validate_signatures_in_log."""
930
return self._get_user_option('validate_signatures_in_log')
932
def _acceptable_keys(self):
933
"""See Config.acceptable_keys."""
934
return self._get_user_option('acceptable_keys')
232
936
def _post_commit(self):
233
937
"""See Config.post_commit."""
234
938
return self._get_user_option('post_commit')
236
def _string_to_signature_policy(self, signature_string):
237
"""Convert a string to a signing policy."""
238
if signature_string.lower() == 'check-available':
239
return CHECK_IF_POSSIBLE
240
if signature_string.lower() == 'ignore':
242
if signature_string.lower() == 'require':
244
raise errors.BzrError("Invalid signatures policy '%s'"
248
class GlobalConfig(IniBasedConfig):
940
def _get_alias(self, value):
942
return self._get_parser().get_value("ALIASES",
947
def _get_nickname(self):
948
return self.get_user_option('nickname')
950
def remove_user_option(self, option_name, section_name=None):
951
"""Remove a user option and save the configuration file.
953
:param option_name: The option to be removed.
955
:param section_name: The section the option is defined in, default to
959
parser = self._get_parser()
960
if section_name is None:
963
section = parser[section_name]
965
del section[option_name]
967
raise errors.NoSuchConfigOption(option_name)
968
self._write_config_file()
969
for hook in OldConfigHooks['remove']:
970
hook(self, option_name)
972
def _write_config_file(self):
973
if self.file_name is None:
974
raise AssertionError('We cannot save, self.file_name is None')
975
conf_dir = os.path.dirname(self.file_name)
976
ensure_config_dir_exists(conf_dir)
977
atomic_file = atomicfile.AtomicFile(self.file_name)
978
self._get_parser().write(atomic_file)
981
osutils.copy_ownership_from_path(self.file_name)
982
for hook in OldConfigHooks['save']:
986
class LockableConfig(IniBasedConfig):
987
"""A configuration needing explicit locking for access.
989
If several processes try to write the config file, the accesses need to be
992
Daughter classes should decorate all methods that update a config with the
993
``@needs_write_lock`` decorator (they call, directly or indirectly, the
994
``_write_config_file()`` method. These methods (typically ``set_option()``
995
and variants must reload the config file from disk before calling
996
``_write_config_file()``), this can be achieved by calling the
997
``self.reload()`` method. Note that the lock scope should cover both the
998
reading and the writing of the config file which is why the decorator can't
999
be applied to ``_write_config_file()`` only.
1001
This should be enough to implement the following logic:
1002
- lock for exclusive write access,
1003
- reload the config file from disk,
1007
This logic guarantees that a writer can update a value without erasing an
1008
update made by another writer.
1013
def __init__(self, file_name):
1014
super(LockableConfig, self).__init__(file_name=file_name)
1015
self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
1016
# FIXME: It doesn't matter that we don't provide possible_transports
1017
# below since this is currently used only for local config files ;
1018
# local transports are not shared. But if/when we start using
1019
# LockableConfig for other kind of transports, we will need to reuse
1020
# whatever connection is already established -- vila 20100929
1021
self.transport = transport.get_transport_from_path(self.dir)
1022
self._lock = lockdir.LockDir(self.transport, self.lock_name)
1024
def _create_from_string(self, unicode_bytes, save):
1025
super(LockableConfig, self)._create_from_string(unicode_bytes, False)
1027
# We need to handle the saving here (as opposed to IniBasedConfig)
1028
# to be able to lock
1030
self._write_config_file()
1033
def lock_write(self, token=None):
1034
"""Takes a write lock in the directory containing the config file.
1036
If the directory doesn't exist it is created.
1038
ensure_config_dir_exists(self.dir)
1039
return self._lock.lock_write(token)
1044
def break_lock(self):
1045
self._lock.break_lock()
1048
def remove_user_option(self, option_name, section_name=None):
1049
super(LockableConfig, self).remove_user_option(option_name,
1052
def _write_config_file(self):
1053
if self._lock is None or not self._lock.is_held:
1054
# NB: if the following exception is raised it probably means a
1055
# missing @needs_write_lock decorator on one of the callers.
1056
raise errors.ObjectNotLocked(self)
1057
super(LockableConfig, self)._write_config_file()
1060
class GlobalConfig(LockableConfig):
249
1061
"""The configuration that should be used for a specific location."""
1064
super(GlobalConfig, self).__init__(file_name=config_filename())
1066
def config_id(self):
1070
def from_string(cls, str_or_unicode, save=False):
1071
"""Create a config object from a string.
1073
:param str_or_unicode: A string representing the file content. This
1074
will be utf-8 encoded.
1076
:param save: Whether the file should be saved upon creation.
1079
conf._create_from_string(str_or_unicode, save)
1082
@deprecated_method(deprecated_in((2, 4, 0)))
251
1083
def get_editor(self):
252
1084
return self._get_user_option('editor')
255
super(GlobalConfig, self).__init__(config_filename)
258
class LocationConfig(IniBasedConfig):
259
"""A configuration object that gives the policy for a location."""
261
def __init__(self, location):
262
super(LocationConfig, self).__init__(branches_config_filename)
263
self._global_config = None
264
self.location = location
266
def _get_global_config(self):
267
if self._global_config is None:
268
self._global_config = GlobalConfig()
269
return self._global_config
271
def _get_section(self):
272
"""Get the section we should look in for config items.
274
Returns None if none exists.
275
TODO: perhaps return a NullSection that thunks through to the
278
sections = self._get_parser()
279
location_names = self.location.split('/')
280
if self.location.endswith('/'):
281
del location_names[-1]
283
for section in sections:
284
section_names = section.split('/')
285
if section.endswith('/'):
286
del section_names[-1]
287
names = zip(location_names, section_names)
1087
def set_user_option(self, option, value):
1088
"""Save option and its value in the configuration."""
1089
self._set_option(option, value, 'DEFAULT')
1091
def get_aliases(self):
1092
"""Return the aliases section."""
1093
if 'ALIASES' in self._get_parser():
1094
return self._get_parser()['ALIASES']
1099
def set_alias(self, alias_name, alias_command):
1100
"""Save the alias in the configuration."""
1101
self._set_option(alias_name, alias_command, 'ALIASES')
1104
def unset_alias(self, alias_name):
1105
"""Unset an existing alias."""
1107
aliases = self._get_parser().get('ALIASES')
1108
if not aliases or alias_name not in aliases:
1109
raise errors.NoSuchAlias(alias_name)
1110
del aliases[alias_name]
1111
self._write_config_file()
1113
def _set_option(self, option, value, section):
1115
self._get_parser().setdefault(section, {})[option] = value
1116
self._write_config_file()
1117
for hook in OldConfigHooks['set']:
1118
hook(self, option, value)
1120
def _get_sections(self, name=None):
1121
"""See IniBasedConfig._get_sections()."""
1122
parser = self._get_parser()
1123
# We don't give access to options defined outside of any section, we
1124
# used the DEFAULT section by... default.
1125
if name in (None, 'DEFAULT'):
1126
# This could happen for an empty file where the DEFAULT section
1127
# doesn't exist yet. So we force DEFAULT when yielding
1129
if 'DEFAULT' not in parser:
1130
parser['DEFAULT']= {}
1131
yield (name, parser[name], self.config_id())
1134
def remove_user_option(self, option_name, section_name=None):
1135
if section_name is None:
1136
# We need to force the default section.
1137
section_name = 'DEFAULT'
1138
# We need to avoid the LockableConfig implementation or we'll lock
1140
super(LockableConfig, self).remove_user_option(option_name,
1143
def _iter_for_location_by_parts(sections, location):
1144
"""Keep only the sessions matching the specified location.
1146
:param sections: An iterable of section names.
1148
:param location: An url or a local path to match against.
1150
:returns: An iterator of (section, extra_path, nb_parts) where nb is the
1151
number of path components in the section name, section is the section
1152
name and extra_path is the difference between location and the section
1155
``location`` will always be a local path and never a 'file://' url but the
1156
section names themselves can be in either form.
1158
location_parts = location.rstrip('/').split('/')
1160
for section in sections:
1161
# location is a local path if possible, so we need to convert 'file://'
1162
# urls in section names to local paths if necessary.
1164
# This also avoids having file:///path be a more exact
1165
# match than '/path'.
1167
# FIXME: This still raises an issue if a user defines both file:///path
1168
# *and* /path. Should we raise an error in this case -- vila 20110505
1170
if section.startswith('file://'):
1171
section_path = urlutils.local_path_from_url(section)
1173
section_path = section
1174
section_parts = section_path.rstrip('/').split('/')
1177
if len(section_parts) > len(location_parts):
1178
# More path components in the section, they can't match
1181
# Rely on zip truncating in length to the length of the shortest
1182
# argument sequence.
1183
names = zip(location_parts, section_parts)
289
1184
for name in names:
290
if not fnmatch(name[0], name[1]):
1185
if not fnmatch.fnmatch(name[0], name[1]):
295
# so, for the common prefix they matched.
296
# if section is longer, no match.
297
if len(section_names) > len(location_names):
299
# if path is longer, and recurse is not true, no match
300
if len(section_names) < len(location_names):
302
if not self._get_parser().get_bool(section, 'recurse'):
306
matches.append((len(section_names), section))
309
matches.sort(reverse=True)
312
def _gpg_signing_command(self):
313
"""See Config.gpg_signing_command."""
314
command = super(LocationConfig, self)._gpg_signing_command()
315
if command is not None:
317
return self._get_global_config()._gpg_signing_command()
319
def _get_user_id(self):
320
user_id = super(LocationConfig, self)._get_user_id()
321
if user_id is not None:
323
return self._get_global_config()._get_user_id()
325
def _get_user_option(self, option_name):
326
"""See Config._get_user_option."""
327
option_value = super(LocationConfig,
328
self)._get_user_option(option_name)
329
if option_value is not None:
331
return self._get_global_config()._get_user_option(option_name)
333
def _get_signature_checking(self):
334
"""See Config._get_signature_checking."""
335
check = super(LocationConfig, self)._get_signature_checking()
336
if check is not None:
338
return self._get_global_config()._get_signature_checking()
340
def _post_commit(self):
341
"""See Config.post_commit."""
342
hook = self._get_user_option('post_commit')
345
return self._get_global_config()._post_commit()
347
def set_user_option(self, option, value):
1190
# build the path difference between the section and the location
1191
extra_path = '/'.join(location_parts[len(section_parts):])
1192
yield section, extra_path, len(section_parts)
1195
class LocationConfig(LockableConfig):
1196
"""A configuration object that gives the policy for a location."""
1198
def __init__(self, location):
1199
super(LocationConfig, self).__init__(
1200
file_name=locations_config_filename())
1201
# local file locations are looked up by local path, rather than
1202
# by file url. This is because the config file is a user
1203
# file, and we would rather not expose the user to file urls.
1204
if location.startswith('file://'):
1205
location = urlutils.local_path_from_url(location)
1206
self.location = location
1208
def config_id(self):
1212
def from_string(cls, str_or_unicode, location, save=False):
1213
"""Create a config object from a string.
1215
:param str_or_unicode: A string representing the file content. This will
1218
:param location: The location url to filter the configuration.
1220
:param save: Whether the file should be saved upon creation.
1222
conf = cls(location)
1223
conf._create_from_string(str_or_unicode, save)
1226
def _get_matching_sections(self):
1227
"""Return an ordered list of section names matching this location."""
1228
matches = list(_iter_for_location_by_parts(self._get_parser(),
1230
# put the longest (aka more specific) locations first
1232
key=lambda (section, extra_path, length): (length, section),
1234
for (section, extra_path, length) in matches:
1235
yield section, extra_path
1236
# should we stop looking for parent configs here?
1238
if self._get_parser()[section].as_bool('ignore_parents'):
1243
def _get_sections(self, name=None):
1244
"""See IniBasedConfig._get_sections()."""
1245
# We ignore the name here as the only sections handled are named with
1246
# the location path and we don't expose embedded sections either.
1247
parser = self._get_parser()
1248
for name, extra_path in self._get_matching_sections():
1249
yield (name, parser[name], self.config_id())
1251
def _get_option_policy(self, section, option_name):
1252
"""Return the policy for the given (section, option_name) pair."""
1253
# check for the old 'recurse=False' flag
1255
recurse = self._get_parser()[section].as_bool('recurse')
1259
return POLICY_NORECURSE
1261
policy_key = option_name + ':policy'
1263
policy_name = self._get_parser()[section][policy_key]
1267
return _policy_value[policy_name]
1269
def _set_option_policy(self, section, option_name, option_policy):
1270
"""Set the policy for the given option name in the given section."""
1271
# The old recurse=False option affects all options in the
1272
# section. To handle multiple policies in the section, we
1273
# need to convert it to a policy_norecurse key.
1275
recurse = self._get_parser()[section].as_bool('recurse')
1279
symbol_versioning.warn(
1280
'The recurse option is deprecated as of 0.14. '
1281
'The section "%s" has been converted to use policies.'
1284
del self._get_parser()[section]['recurse']
1286
for key in self._get_parser()[section].keys():
1287
if not key.endswith(':policy'):
1288
self._get_parser()[section][key +
1289
':policy'] = 'norecurse'
1291
policy_key = option_name + ':policy'
1292
policy_name = _policy_name[option_policy]
1293
if policy_name is not None:
1294
self._get_parser()[section][policy_key] = policy_name
1296
if policy_key in self._get_parser()[section]:
1297
del self._get_parser()[section][policy_key]
1300
def set_user_option(self, option, value, store=STORE_LOCATION):
348
1301
"""Save option and its value in the configuration."""
349
# FIXME: RBC 20051029 This should refresh the parser and also take a
350
# file lock on branches.conf.
351
if not os.path.isdir(os.path.dirname(self._get_filename())):
352
os.mkdir(os.path.dirname(self._get_filename()))
1302
if store not in [STORE_LOCATION,
1303
STORE_LOCATION_NORECURSE,
1304
STORE_LOCATION_APPENDPATH]:
1305
raise ValueError('bad storage policy %r for %r' %
353
1308
location = self.location
354
1309
if location.endswith('/'):
355
1310
location = location[:-1]
356
if (not location in self._get_parser() and
357
not location + '/' in self._get_parser()):
358
self._get_parser()[location]={}
359
elif location + '/' in self._get_parser():
1311
parser = self._get_parser()
1312
if not location in parser and not location + '/' in parser:
1313
parser[location] = {}
1314
elif location + '/' in parser:
360
1315
location = location + '/'
361
self._get_parser()[location][option]=value
362
self._get_parser().write()
1316
parser[location][option]=value
1317
# the allowed values of store match the config policies
1318
self._set_option_policy(location, option, store)
1319
self._write_config_file()
1320
for hook in OldConfigHooks['set']:
1321
hook(self, option, value)
365
1324
class BranchConfig(Config):
366
1325
"""A configuration object giving the policy for a branch."""
1327
def __init__(self, branch):
1328
super(BranchConfig, self).__init__()
1329
self._location_config = None
1330
self._branch_data_config = None
1331
self._global_config = None
1332
self.branch = branch
1333
self.option_sources = (self._get_location_config,
1334
self._get_branch_data_config,
1335
self._get_global_config)
1337
def config_id(self):
1340
def _get_branch_data_config(self):
1341
if self._branch_data_config is None:
1342
self._branch_data_config = TreeConfig(self.branch)
1343
self._branch_data_config.config_id = self.config_id
1344
return self._branch_data_config
368
1346
def _get_location_config(self):
369
1347
if self._location_config is None:
370
1348
self._location_config = LocationConfig(self.branch.base)
371
1349
return self._location_config
1351
def _get_global_config(self):
1352
if self._global_config is None:
1353
self._global_config = GlobalConfig()
1354
return self._global_config
1356
def _get_best_value(self, option_name):
1357
"""This returns a user option from local, tree or global config.
1359
They are tried in that order. Use get_safe_value if trusted values
1362
for source in self.option_sources:
1363
value = getattr(source(), option_name)()
1364
if value is not None:
1368
def _get_safe_value(self, option_name):
1369
"""This variant of get_best_value never returns untrusted values.
1371
It does not return values from the branch data, because the branch may
1372
not be controlled by the user.
1374
We may wish to allow locations.conf to control whether branches are
1375
trusted in the future.
1377
for source in (self._get_location_config, self._get_global_config):
1378
value = getattr(source(), option_name)()
1379
if value is not None:
373
1383
def _get_user_id(self):
374
1384
"""Return the full user id for the branch.
376
e.g. "John Hacker <jhacker@foo.org>"
1386
e.g. "John Hacker <jhacker@example.com>"
377
1387
This is looked up in the email controlfile for the branch.
380
return (self.branch.controlfile("email", "r")
382
.decode(bzrlib.user_encoding)
384
except errors.NoSuchFile, e:
387
return self._get_location_config()._get_user_id()
1389
return self._get_best_value('_get_user_id')
1391
def _get_change_editor(self):
1392
return self._get_best_value('_get_change_editor')
389
1394
def _get_signature_checking(self):
390
1395
"""See Config._get_signature_checking."""
391
return self._get_location_config()._get_signature_checking()
1396
return self._get_best_value('_get_signature_checking')
1398
def _get_signing_policy(self):
1399
"""See Config._get_signing_policy."""
1400
return self._get_best_value('_get_signing_policy')
393
1402
def _get_user_option(self, option_name):
394
1403
"""See Config._get_user_option."""
395
return self._get_location_config()._get_user_option(option_name)
1404
for source in self.option_sources:
1405
value = source()._get_user_option(option_name)
1406
if value is not None:
1410
def _get_sections(self, name=None):
1411
"""See IniBasedConfig.get_sections()."""
1412
for source in self.option_sources:
1413
for section in source()._get_sections(name):
1416
def _get_options(self, sections=None):
1418
# First the locations options
1419
for option in self._get_location_config()._get_options():
1421
# Then the branch options
1422
branch_config = self._get_branch_data_config()
1423
if sections is None:
1424
sections = [('DEFAULT', branch_config._get_parser())]
1425
# FIXME: We shouldn't have to duplicate the code in IniBasedConfig but
1426
# Config itself has no notion of sections :( -- vila 20101001
1427
config_id = self.config_id()
1428
for (section_name, section) in sections:
1429
for (name, value) in section.iteritems():
1430
yield (name, value, section_name,
1431
config_id, branch_config._get_parser())
1432
# Then the global options
1433
for option in self._get_global_config()._get_options():
1436
def set_user_option(self, name, value, store=STORE_BRANCH,
1438
if store == STORE_BRANCH:
1439
self._get_branch_data_config().set_option(value, name)
1440
elif store == STORE_GLOBAL:
1441
self._get_global_config().set_user_option(name, value)
1443
self._get_location_config().set_user_option(name, value, store)
1446
if store in (STORE_GLOBAL, STORE_BRANCH):
1447
mask_value = self._get_location_config().get_user_option(name)
1448
if mask_value is not None:
1449
trace.warning('Value "%s" is masked by "%s" from'
1450
' locations.conf', value, mask_value)
1452
if store == STORE_GLOBAL:
1453
branch_config = self._get_branch_data_config()
1454
mask_value = branch_config.get_user_option(name)
1455
if mask_value is not None:
1456
trace.warning('Value "%s" is masked by "%s" from'
1457
' branch.conf', value, mask_value)
1459
def remove_user_option(self, option_name, section_name=None):
1460
self._get_branch_data_config().remove_option(option_name, section_name)
397
1462
def _gpg_signing_command(self):
398
1463
"""See Config.gpg_signing_command."""
399
return self._get_location_config()._gpg_signing_command()
401
def __init__(self, branch):
402
super(BranchConfig, self).__init__()
403
self._location_config = None
1464
return self._get_safe_value('_gpg_signing_command')
406
1466
def _post_commit(self):
407
1467
"""See Config.post_commit."""
408
return self._get_location_config()._post_commit()
1468
return self._get_safe_value('_post_commit')
1470
def _get_nickname(self):
1471
value = self._get_explicit_nickname()
1472
if value is not None:
1474
if self.branch.name:
1475
return self.branch.name
1476
return urlutils.unescape(self.branch.base.split('/')[-2])
1478
def has_explicit_nickname(self):
1479
"""Return true if a nickname has been explicitly assigned."""
1480
return self._get_explicit_nickname() is not None
1482
def _get_explicit_nickname(self):
1483
return self._get_best_value('_get_nickname')
1485
def _log_format(self):
1486
"""See Config.log_format."""
1487
return self._get_best_value('_log_format')
1489
def _validate_signatures_in_log(self):
1490
"""See Config.validate_signatures_in_log."""
1491
return self._get_best_value('_validate_signatures_in_log')
1493
def _acceptable_keys(self):
1494
"""See Config.acceptable_keys."""
1495
return self._get_best_value('_acceptable_keys')
1498
def ensure_config_dir_exists(path=None):
1499
"""Make sure a configuration directory exists.
1500
This makes sure that the directory exists.
1501
On windows, since configuration directories are 2 levels deep,
1502
it makes sure both the directory and the parent directory exists.
1506
if not os.path.isdir(path):
1507
if sys.platform == 'win32':
1508
parent_dir = os.path.dirname(path)
1509
if not os.path.isdir(parent_dir):
1510
trace.mutter('creating config parent directory: %r', parent_dir)
1511
os.mkdir(parent_dir)
1512
trace.mutter('creating config directory: %r', path)
1514
osutils.copy_ownership_from_path(path)
411
1517
def config_dir():
412
"""Return per-user configuration directory.
414
By default this is ~/.bazaar/
1518
"""Return per-user configuration directory as unicode string
1520
By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1521
and Linux. On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1522
that will be used instead.
416
1524
TODO: Global option --config-dir to override this.
418
base = os.environ.get('BZR_HOME', None)
1526
base = osutils.path_from_environ('BZR_HOME')
419
1527
if sys.platform == 'win32':
420
1528
if base is None:
421
base = os.environ.get('APPDATA', None)
423
base = os.environ.get('HOME', None)
425
raise BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
426
return os.path.join(base, 'bazaar', '2.0')
428
# cygwin, linux, and darwin all have a $HOME directory
430
base = os.path.expanduser("~")
431
return os.path.join(base, ".bazaar")
1529
base = win32utils.get_appdata_location()
1531
base = win32utils.get_home_location()
1532
# GZ 2012-02-01: Really the two level subdirs only make sense inside
1533
# APPDATA, but hard to move. See bug 348640 for more.
1534
return osutils.pathjoin(base, 'bazaar', '2.0')
1536
# GZ 2012-02-01: What should OSX use instead of XDG if anything?
1537
if sys.platform != 'darwin':
1538
xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
1540
xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
1541
xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1542
if osutils.isdir(xdg_dir):
1544
"Using configuration in XDG directory %s." % xdg_dir)
1546
base = osutils._get_home_dir()
1547
return osutils.pathjoin(base, ".bazaar")
434
1550
def config_filename():
435
1551
"""Return per-user configuration ini file filename."""
436
return os.path.join(config_dir(), 'bazaar.conf')
439
def branches_config_filename():
1552
return osutils.pathjoin(config_dir(), 'bazaar.conf')
1555
def locations_config_filename():
440
1556
"""Return per-user configuration ini file filename."""
441
return os.path.join(config_dir(), 'branches.conf')
1557
return osutils.pathjoin(config_dir(), 'locations.conf')
1560
def authentication_config_filename():
1561
"""Return per-user authentication ini file filename."""
1562
return osutils.pathjoin(config_dir(), 'authentication.conf')
1565
def user_ignore_config_filename():
1566
"""Return the user default ignore filename"""
1567
return osutils.pathjoin(config_dir(), 'ignore')
1571
"""Return the directory name to store crash files.
1573
This doesn't implicitly create it.
1575
On Windows it's in the config directory; elsewhere it's /var/crash
1576
which may be monitored by apport. It can be overridden by
1579
if sys.platform == 'win32':
1580
return osutils.pathjoin(config_dir(), 'Crash')
1582
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
1584
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
1587
def xdg_cache_dir():
1588
# See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
1589
# Possibly this should be different on Windows?
1590
e = os.environ.get('XDG_CACHE_DIR', None)
1594
return os.path.expanduser('~/.cache')
1597
def _get_default_mail_domain():
1598
"""If possible, return the assumed default email domain.
1600
:returns: string mail domain, or None.
1602
if sys.platform == 'win32':
1603
# No implementation yet; patches welcome
1606
f = open('/etc/mailname')
1607
except (IOError, OSError), e:
1610
domain = f.read().strip()
1616
def default_email():
1617
v = os.environ.get('BZR_EMAIL')
1619
return v.decode(osutils.get_user_encoding())
1620
v = os.environ.get('EMAIL')
1622
return v.decode(osutils.get_user_encoding())
1623
name, email = _auto_user_id()
1625
return u'%s <%s>' % (name, email)
1628
raise errors.NoWhoami()
444
1631
def _auto_user_id():
445
1632
"""Calculate automatic user identification.
447
Returns (realname, email).
1634
:returns: (realname, email), either of which may be None if they can't be
449
1637
Only used when none is set in the environment or the id file.
451
This previously used the FQDN as the default domain, but that can
452
be very slow on machines where DNS is broken. So now we simply
1639
This only returns an email address if we can be fairly sure the
1640
address is reasonable, ie if /etc/mailname is set on unix.
1642
This doesn't use the FQDN as the default domain because that may be
1643
slow, and it doesn't use the hostname alone because that's not normally
1644
a reasonable address.
457
# XXX: Any good way to get real user name on win32?
1646
if sys.platform == 'win32':
1647
# No implementation to reliably determine Windows default mail
1648
# address; please add one.
1651
default_mail_domain = _get_default_mail_domain()
1652
if not default_mail_domain:
462
1658
w = pwd.getpwuid(uid)
463
gecos = w.pw_gecos.decode(bzrlib.user_encoding)
464
username = w.pw_name.decode(bzrlib.user_encoding)
465
comma = gecos.find(',')
469
realname = gecos[:comma]
475
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
477
return realname, (username + '@' + socket.gethostname())
1660
trace.mutter('no passwd entry for uid %d?' % uid)
1663
# we try utf-8 first, because on many variants (like Linux),
1664
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
1665
# false positives. (many users will have their user encoding set to
1666
# latin-1, which cannot raise UnicodeError.)
1668
gecos = w.pw_gecos.decode('utf-8')
1670
except UnicodeError:
1672
encoding = osutils.get_user_encoding()
1673
gecos = w.pw_gecos.decode(encoding)
1674
except UnicodeError, e:
1675
trace.mutter("cannot decode passwd entry %s" % w)
1678
username = w.pw_name.decode(encoding)
1679
except UnicodeError, e:
1680
trace.mutter("cannot decode passwd entry %s" % w)
1683
comma = gecos.find(',')
1687
realname = gecos[:comma]
1689
return realname, (username + '@' + default_mail_domain)
1692
def parse_username(username):
1693
"""Parse e-mail username and return a (name, address) tuple."""
1694
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1696
return (username, '')
1698
return (match.group(1), match.group(2))
480
1701
def extract_email_address(e):
481
1702
"""Return just the address part of an email string.
483
That is just the user@domain part, nothing else.
1704
That is just the user@domain part, nothing else.
484
1705
This part is required to contain only ascii characters.
485
1706
If it can't be extracted, raises an error.
487
1708
>>> extract_email_address('Jane Tester <jane@test.com>')
490
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
492
raise errors.BzrError("%r doesn't seem to contain "
493
"a reasonable email address" % e)
496
class TreeConfig(object):
1711
name, email = parse_username(e)
1713
raise errors.NoEmailInUsername(e)
1717
class TreeConfig(IniBasedConfig):
497
1718
"""Branch configuration data associated with its contents, not location"""
1720
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
498
1722
def __init__(self, branch):
1723
self._config = branch._get_config()
499
1724
self.branch = branch
501
def _get_config(self):
503
obj = ConfigObj(self.branch.controlfile('branch.conf',
506
except errors.NoSuchFile:
1726
def _get_parser(self, file=None):
1727
if file is not None:
1728
return IniBasedConfig._get_parser(file)
1729
return self._config._get_configobj()
510
1731
def get_option(self, name, section=None, default=None):
511
1732
self.branch.lock_read()
513
obj = self._get_config()
515
if section is not None:
1734
return self._config.get_option(name, section, default)
521
1736
self.branch.unlock()
524
1738
def set_option(self, value, name, section=None):
525
1739
"""Set a per-branch configuration option"""
526
self.branch.lock_write()
528
cfg_obj = self._get_config()
533
obj = cfg_obj[section]
535
cfg_obj[section] = {}
536
obj = cfg_obj[section]
538
cfg_obj.encode('UTF-8')
539
out_file = StringIO(''.join([l+'\n' for l in cfg_obj.write()]))
541
self.branch.put_controlfile('branch.conf', out_file, encode=False)
1740
# FIXME: We shouldn't need to lock explicitly here but rather rely on
1741
# higher levels providing the right lock -- vila 20101004
1742
self.branch.lock_write()
1744
self._config.set_option(value, name, section)
1746
self.branch.unlock()
1748
def remove_option(self, option_name, section_name=None):
1749
# FIXME: We shouldn't need to lock explicitly here but rather rely on
1750
# higher levels providing the right lock -- vila 20101004
1751
self.branch.lock_write()
1753
self._config.remove_option(option_name, section_name)
1755
self.branch.unlock()
1758
class AuthenticationConfig(object):
1759
"""The authentication configuration file based on a ini file.
1761
Implements the authentication.conf file described in
1762
doc/developers/authentication-ring.txt.
1765
def __init__(self, _file=None):
1766
self._config = None # The ConfigObj
1768
self._filename = authentication_config_filename()
1769
self._input = self._filename = authentication_config_filename()
1771
# Tests can provide a string as _file
1772
self._filename = None
1775
def _get_config(self):
1776
if self._config is not None:
1779
# FIXME: Should we validate something here ? Includes: empty
1780
# sections are useless, at least one of
1781
# user/password/password_encoding should be defined, etc.
1783
# Note: the encoding below declares that the file itself is utf-8
1784
# encoded, but the values in the ConfigObj are always Unicode.
1785
self._config = ConfigObj(self._input, encoding='utf-8')
1786
except configobj.ConfigObjError, e:
1787
raise errors.ParseConfigError(e.errors, e.config.filename)
1788
except UnicodeError:
1789
raise errors.ConfigContentError(self._filename)
1793
"""Save the config file, only tests should use it for now."""
1794
conf_dir = os.path.dirname(self._filename)
1795
ensure_config_dir_exists(conf_dir)
1796
f = file(self._filename, 'wb')
1798
self._get_config().write(f)
1802
def _set_option(self, section_name, option_name, value):
1803
"""Set an authentication configuration option"""
1804
conf = self._get_config()
1805
section = conf.get(section_name)
1808
section = conf[section]
1809
section[option_name] = value
1812
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1814
"""Returns the matching credentials from authentication.conf file.
1816
:param scheme: protocol
1818
:param host: the server address
1820
:param port: the associated port (optional)
1822
:param user: login (optional)
1824
:param path: the absolute path on the server (optional)
1826
:param realm: the http authentication realm (optional)
1828
:return: A dict containing the matching credentials or None.
1830
- name: the section name of the credentials in the
1831
authentication.conf file,
1832
- user: can't be different from the provided user if any,
1833
- scheme: the server protocol,
1834
- host: the server address,
1835
- port: the server port (can be None),
1836
- path: the absolute server path (can be None),
1837
- realm: the http specific authentication realm (can be None),
1838
- password: the decoded password, could be None if the credential
1839
defines only the user
1840
- verify_certificates: https specific, True if the server
1841
certificate should be verified, False otherwise.
1844
for auth_def_name, auth_def in self._get_config().items():
1845
if type(auth_def) is not configobj.Section:
1846
raise ValueError("%s defined outside a section" % auth_def_name)
1848
a_scheme, a_host, a_user, a_path = map(
1849
auth_def.get, ['scheme', 'host', 'user', 'path'])
1852
a_port = auth_def.as_int('port')
1856
raise ValueError("'port' not numeric in %s" % auth_def_name)
1858
a_verify_certificates = auth_def.as_bool('verify_certificates')
1860
a_verify_certificates = True
1863
"'verify_certificates' not boolean in %s" % auth_def_name)
1866
if a_scheme is not None and scheme != a_scheme:
1868
if a_host is not None:
1869
if not (host == a_host
1870
or (a_host.startswith('.') and host.endswith(a_host))):
1872
if a_port is not None and port != a_port:
1874
if (a_path is not None and path is not None
1875
and not path.startswith(a_path)):
1877
if (a_user is not None and user is not None
1878
and a_user != user):
1879
# Never contradict the caller about the user to be used
1884
# Prepare a credentials dictionary with additional keys
1885
# for the credential providers
1886
credentials = dict(name=auth_def_name,
1893
password=auth_def.get('password', None),
1894
verify_certificates=a_verify_certificates)
1895
# Decode the password in the credentials (or get one)
1896
self.decode_password(credentials,
1897
auth_def.get('password_encoding', None))
1898
if 'auth' in debug.debug_flags:
1899
trace.mutter("Using authentication section: %r", auth_def_name)
1902
if credentials is None:
1903
# No credentials were found in authentication.conf, try the fallback
1904
# credentials stores.
1905
credentials = credential_store_registry.get_fallback_credentials(
1906
scheme, host, port, user, path, realm)
1910
def set_credentials(self, name, host, user, scheme=None, password=None,
1911
port=None, path=None, verify_certificates=None,
1913
"""Set authentication credentials for a host.
1915
Any existing credentials with matching scheme, host, port and path
1916
will be deleted, regardless of name.
1918
:param name: An arbitrary name to describe this set of credentials.
1919
:param host: Name of the host that accepts these credentials.
1920
:param user: The username portion of these credentials.
1921
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1923
:param password: Password portion of these credentials.
1924
:param port: The IP port on the host that these credentials apply to.
1925
:param path: A filesystem path on the host that these credentials
1927
:param verify_certificates: On https, verify server certificates if
1929
:param realm: The http authentication realm (optional).
1931
values = {'host': host, 'user': user}
1932
if password is not None:
1933
values['password'] = password
1934
if scheme is not None:
1935
values['scheme'] = scheme
1936
if port is not None:
1937
values['port'] = '%d' % port
1938
if path is not None:
1939
values['path'] = path
1940
if verify_certificates is not None:
1941
values['verify_certificates'] = str(verify_certificates)
1942
if realm is not None:
1943
values['realm'] = realm
1944
config = self._get_config()
1946
for section, existing_values in config.items():
1947
for key in ('scheme', 'host', 'port', 'path', 'realm'):
1948
if existing_values.get(key) != values.get(key):
1952
config.update({name: values})
1955
def get_user(self, scheme, host, port=None, realm=None, path=None,
1956
prompt=None, ask=False, default=None):
1957
"""Get a user from authentication file.
1959
:param scheme: protocol
1961
:param host: the server address
1963
:param port: the associated port (optional)
1965
:param realm: the realm sent by the server (optional)
1967
:param path: the absolute path on the server (optional)
1969
:param ask: Ask the user if there is no explicitly configured username
1972
:param default: The username returned if none is defined (optional).
1974
:return: The found user.
1976
credentials = self.get_credentials(scheme, host, port, user=None,
1977
path=path, realm=realm)
1978
if credentials is not None:
1979
user = credentials['user']
1985
# Create a default prompt suitable for most cases
1986
prompt = u'%s' % (scheme.upper(),) + u' %(host)s username'
1987
# Special handling for optional fields in the prompt
1988
if port is not None:
1989
prompt_host = '%s:%d' % (host, port)
1992
user = ui.ui_factory.get_username(prompt, host=prompt_host)
1997
def get_password(self, scheme, host, user, port=None,
1998
realm=None, path=None, prompt=None):
1999
"""Get a password from authentication file or prompt the user for one.
2001
:param scheme: protocol
2003
:param host: the server address
2005
:param port: the associated port (optional)
2009
:param realm: the realm sent by the server (optional)
2011
:param path: the absolute path on the server (optional)
2013
:return: The found password or the one entered by the user.
2015
credentials = self.get_credentials(scheme, host, port, user, path,
2017
if credentials is not None:
2018
password = credentials['password']
2019
if password is not None and scheme is 'ssh':
2020
trace.warning('password ignored in section [%s],'
2021
' use an ssh agent instead'
2022
% credentials['name'])
2026
# Prompt user only if we could't find a password
2027
if password is None:
2029
# Create a default prompt suitable for most cases
2030
prompt = u'%s' % scheme.upper() + u' %(user)s@%(host)s password'
2031
# Special handling for optional fields in the prompt
2032
if port is not None:
2033
prompt_host = '%s:%d' % (host, port)
2036
password = ui.ui_factory.get_password(prompt,
2037
host=prompt_host, user=user)
2040
def decode_password(self, credentials, encoding):
2042
cs = credential_store_registry.get_credential_store(encoding)
2044
raise ValueError('%r is not a known password_encoding' % encoding)
2045
credentials['password'] = cs.decode_password(credentials)
2049
class CredentialStoreRegistry(registry.Registry):
2050
"""A class that registers credential stores.
2052
A credential store provides access to credentials via the password_encoding
2053
field in authentication.conf sections.
2055
Except for stores provided by bzr itself, most stores are expected to be
2056
provided by plugins that will therefore use
2057
register_lazy(password_encoding, module_name, member_name, help=help,
2058
fallback=fallback) to install themselves.
2060
A fallback credential store is one that is queried if no credentials can be
2061
found via authentication.conf.
2064
def get_credential_store(self, encoding=None):
2065
cs = self.get(encoding)
2070
def is_fallback(self, name):
2071
"""Check if the named credentials store should be used as fallback."""
2072
return self.get_info(name)
2074
def get_fallback_credentials(self, scheme, host, port=None, user=None,
2075
path=None, realm=None):
2076
"""Request credentials from all fallback credentials stores.
2078
The first credentials store that can provide credentials wins.
2081
for name in self.keys():
2082
if not self.is_fallback(name):
2084
cs = self.get_credential_store(name)
2085
credentials = cs.get_credentials(scheme, host, port, user,
2087
if credentials is not None:
2088
# We found some credentials
2092
def register(self, key, obj, help=None, override_existing=False,
2094
"""Register a new object to a name.
2096
:param key: This is the key to use to request the object later.
2097
:param obj: The object to register.
2098
:param help: Help text for this entry. This may be a string or
2099
a callable. If it is a callable, it should take two
2100
parameters (registry, key): this registry and the key that
2101
the help was registered under.
2102
:param override_existing: Raise KeyErorr if False and something has
2103
already been registered for that key. If True, ignore if there
2104
is an existing key (always register the new value).
2105
:param fallback: Whether this credential store should be
2108
return super(CredentialStoreRegistry,
2109
self).register(key, obj, help, info=fallback,
2110
override_existing=override_existing)
2112
def register_lazy(self, key, module_name, member_name,
2113
help=None, override_existing=False,
2115
"""Register a new credential store to be loaded on request.
2117
:param module_name: The python path to the module. Such as 'os.path'.
2118
:param member_name: The member of the module to return. If empty or
2119
None, get() will return the module itself.
2120
:param help: Help text for this entry. This may be a string or
2122
:param override_existing: If True, replace the existing object
2123
with the new one. If False, if there is already something
2124
registered with the same key, raise a KeyError
2125
:param fallback: Whether this credential store should be
2128
return super(CredentialStoreRegistry, self).register_lazy(
2129
key, module_name, member_name, help,
2130
info=fallback, override_existing=override_existing)
2133
credential_store_registry = CredentialStoreRegistry()
2136
class CredentialStore(object):
2137
"""An abstract class to implement storage for credentials"""
2139
def decode_password(self, credentials):
2140
"""Returns a clear text password for the provided credentials."""
2141
raise NotImplementedError(self.decode_password)
2143
def get_credentials(self, scheme, host, port=None, user=None, path=None,
2145
"""Return the matching credentials from this credential store.
2147
This method is only called on fallback credential stores.
2149
raise NotImplementedError(self.get_credentials)
2153
class PlainTextCredentialStore(CredentialStore):
2154
__doc__ = """Plain text credential store for the authentication.conf file"""
2156
def decode_password(self, credentials):
2157
"""See CredentialStore.decode_password."""
2158
return credentials['password']
2161
credential_store_registry.register('plain', PlainTextCredentialStore,
2162
help=PlainTextCredentialStore.__doc__)
2163
credential_store_registry.default_key = 'plain'
2166
class BzrDirConfig(object):
2168
def __init__(self, bzrdir):
2169
self._bzrdir = bzrdir
2170
self._config = bzrdir._get_config()
2172
def set_default_stack_on(self, value):
2173
"""Set the default stacking location.
2175
It may be set to a location, or None.
2177
This policy affects all branches contained by this bzrdir, except for
2178
those under repositories.
2180
if self._config is None:
2181
raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
2183
self._config.set_option('', 'default_stack_on')
2185
self._config.set_option(value, 'default_stack_on')
2187
def get_default_stack_on(self):
2188
"""Return the default stacking location.
2190
This will either be a location, or None.
2192
This policy affects all branches contained by this bzrdir, except for
2193
those under repositories.
2195
if self._config is None:
2197
value = self._config.get_option('default_stack_on')
2203
class TransportConfig(object):
2204
"""A Config that reads/writes a config file on a Transport.
2206
It is a low-level object that considers config data to be name/value pairs
2207
that may be associated with a section. Assigning meaning to these values
2208
is done at higher levels like TreeConfig.
2211
def __init__(self, transport, filename):
2212
self._transport = transport
2213
self._filename = filename
2215
def get_option(self, name, section=None, default=None):
2216
"""Return the value associated with a named option.
2218
:param name: The name of the value
2219
:param section: The section the option is in (if any)
2220
:param default: The value to return if the value is not set
2221
:return: The value or default value
2223
configobj = self._get_configobj()
2225
section_obj = configobj
2228
section_obj = configobj[section]
2231
value = section_obj.get(name, default)
2232
for hook in OldConfigHooks['get']:
2233
hook(self, name, value)
2236
def set_option(self, value, name, section=None):
2237
"""Set the value associated with a named option.
2239
:param value: The value to set
2240
:param name: The name of the value to set
2241
:param section: The section the option is in (if any)
2243
configobj = self._get_configobj()
2245
configobj[name] = value
2247
configobj.setdefault(section, {})[name] = value
2248
for hook in OldConfigHooks['set']:
2249
hook(self, name, value)
2250
self._set_configobj(configobj)
2252
def remove_option(self, option_name, section_name=None):
2253
configobj = self._get_configobj()
2254
if section_name is None:
2255
del configobj[option_name]
2257
del configobj[section_name][option_name]
2258
for hook in OldConfigHooks['remove']:
2259
hook(self, option_name)
2260
self._set_configobj(configobj)
2262
def _get_config_file(self):
2264
f = StringIO(self._transport.get_bytes(self._filename))
2265
for hook in OldConfigHooks['load']:
2268
except errors.NoSuchFile:
2270
except errors.PermissionDenied, e:
2271
trace.warning("Permission denied while trying to open "
2272
"configuration file %s.", urlutils.unescape_for_display(
2273
urlutils.join(self._transport.base, self._filename), "utf-8"))
2276
def _external_url(self):
2277
return urlutils.join(self._transport.external_url(), self._filename)
2279
def _get_configobj(self):
2280
f = self._get_config_file()
2283
conf = ConfigObj(f, encoding='utf-8')
2284
except configobj.ConfigObjError, e:
2285
raise errors.ParseConfigError(e.errors, self._external_url())
2286
except UnicodeDecodeError:
2287
raise errors.ConfigContentError(self._external_url())
2292
def _set_configobj(self, configobj):
2293
out_file = StringIO()
2294
configobj.write(out_file)
2296
self._transport.put_file(self._filename, out_file)
2297
for hook in OldConfigHooks['save']:
2301
class Option(object):
2302
"""An option definition.
2304
The option *values* are stored in config files and found in sections.
2306
Here we define various properties about the option itself, its default
2307
value, how to convert it from stores, what to do when invalid values are
2308
encoutered, in which config files it can be stored.
2311
def __init__(self, name, override_from_env=None,
2312
default=None, default_from_env=None,
2313
help=None, from_unicode=None, invalid=None, unquote=True):
2314
"""Build an option definition.
2316
:param name: the name used to refer to the option.
2318
:param override_from_env: A list of environment variables which can
2319
provide override any configuration setting.
2321
:param default: the default value to use when none exist in the config
2322
stores. This is either a string that ``from_unicode`` will convert
2323
into the proper type, a callable returning a unicode string so that
2324
``from_unicode`` can be used on the return value, or a python
2325
object that can be stringified (so only the empty list is supported
2328
:param default_from_env: A list of environment variables which can
2329
provide a default value. 'default' will be used only if none of the
2330
variables specified here are set in the environment.
2332
:param help: a doc string to explain the option to the user.
2334
:param from_unicode: a callable to convert the unicode string
2335
representing the option value in a store. This is not called for
2338
:param invalid: the action to be taken when an invalid value is
2339
encountered in a store. This is called only when from_unicode is
2340
invoked to convert a string and returns None or raise ValueError or
2341
TypeError. Accepted values are: None (ignore invalid values),
2342
'warning' (emit a warning), 'error' (emit an error message and
2345
:param unquote: should the unicode value be unquoted before conversion.
2346
This should be used only when the store providing the values cannot
2347
safely unquote them (see http://pad.lv/906897). It is provided so
2348
daughter classes can handle the quoting themselves.
2350
if override_from_env is None:
2351
override_from_env = []
2352
if default_from_env is None:
2353
default_from_env = []
2355
self.override_from_env = override_from_env
2356
# Convert the default value to a unicode string so all values are
2357
# strings internally before conversion (via from_unicode) is attempted.
2360
elif isinstance(default, list):
2361
# Only the empty list is supported
2363
raise AssertionError(
2364
'Only empty lists are supported as default values')
2366
elif isinstance(default, (str, unicode, bool, int, float)):
2367
# Rely on python to convert strings, booleans and integers
2368
self.default = u'%s' % (default,)
2369
elif callable(default):
2370
self.default = default
2372
# other python objects are not expected
2373
raise AssertionError('%r is not supported as a default value'
2375
self.default_from_env = default_from_env
2377
self.from_unicode = from_unicode
2378
self.unquote = unquote
2379
if invalid and invalid not in ('warning', 'error'):
2380
raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2381
self.invalid = invalid
2387
def convert_from_unicode(self, store, unicode_value):
2388
if self.unquote and store is not None and unicode_value is not None:
2389
unicode_value = store.unquote(unicode_value)
2390
if self.from_unicode is None or unicode_value is None:
2391
# Don't convert or nothing to convert
2392
return unicode_value
2394
converted = self.from_unicode(unicode_value)
2395
except (ValueError, TypeError):
2396
# Invalid values are ignored
2398
if converted is None and self.invalid is not None:
2399
# The conversion failed
2400
if self.invalid == 'warning':
2401
trace.warning('Value "%s" is not valid for "%s"',
2402
unicode_value, self.name)
2403
elif self.invalid == 'error':
2404
raise errors.ConfigOptionValueError(self.name, unicode_value)
2407
def get_override(self):
2409
for var in self.override_from_env:
2411
# If the env variable is defined, its value takes precedence
2412
value = os.environ[var].decode(osutils.get_user_encoding())
2418
def get_default(self):
2420
for var in self.default_from_env:
2422
# If the env variable is defined, its value is the default one
2423
value = os.environ[var].decode(osutils.get_user_encoding())
2428
# Otherwise, fallback to the value defined at registration
2429
if callable(self.default):
2430
value = self.default()
2431
if not isinstance(value, unicode):
2432
raise AssertionError(
2433
'Callable default values should be unicode')
2435
value = self.default
2438
def get_help_text(self, additional_see_also=None, plain=True):
2440
from bzrlib import help_topics
2441
result += help_topics._format_see_also(additional_see_also)
2443
result = help_topics.help_as_plain_text(result)
2447
# Predefined converters to get proper values from store
2449
def bool_from_store(unicode_str):
2450
return ui.bool_from_string(unicode_str)
2453
def int_from_store(unicode_str):
2454
return int(unicode_str)
2457
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2459
def int_SI_from_store(unicode_str):
2460
"""Convert a human readable size in SI units, e.g 10MB into an integer.
2462
Accepted suffixes are K,M,G. It is case-insensitive and may be followed
2463
by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2466
:return Integer, expanded to its base-10 value if a proper SI unit is
2467
found, None otherwise.
2469
regexp = "^(\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2470
p = re.compile(regexp, re.IGNORECASE)
2471
m = p.match(unicode_str)
2474
val, _, unit = m.groups()
2478
coeff = _unit_suffixes[unit.upper()]
2480
raise ValueError(gettext('{0} is not an SI unit.').format(unit))
2485
def float_from_store(unicode_str):
2486
return float(unicode_str)
2489
# Use a an empty dict to initialize an empty configobj avoiding all
2490
# parsing and encoding checks
2491
_list_converter_config = configobj.ConfigObj(
2492
{}, encoding='utf-8', list_values=True, interpolation=False)
2495
class ListOption(Option):
2497
def __init__(self, name, default=None, default_from_env=None,
2498
help=None, invalid=None):
2499
"""A list Option definition.
2501
This overrides the base class so the conversion from a unicode string
2502
can take quoting into account.
2504
super(ListOption, self).__init__(
2505
name, default=default, default_from_env=default_from_env,
2506
from_unicode=self.from_unicode, help=help,
2507
invalid=invalid, unquote=False)
2509
def from_unicode(self, unicode_str):
2510
if not isinstance(unicode_str, basestring):
2512
# Now inject our string directly as unicode. All callers got their
2513
# value from configobj, so values that need to be quoted are already
2515
_list_converter_config.reset()
2516
_list_converter_config._parse([u"list=%s" % (unicode_str,)])
2517
maybe_list = _list_converter_config['list']
2518
if isinstance(maybe_list, basestring):
2520
# A single value, most probably the user forgot (or didn't care
2521
# to add) the final ','
2524
# The empty string, convert to empty list
2527
# We rely on ConfigObj providing us with a list already
2532
class RegistryOption(Option):
2533
"""Option for a choice from a registry."""
2535
def __init__(self, name, registry, default_from_env=None,
2536
help=None, invalid=None):
2537
"""A registry based Option definition.
2539
This overrides the base class so the conversion from a unicode string
2540
can take quoting into account.
2542
super(RegistryOption, self).__init__(
2543
name, default=lambda: unicode(registry.default_key),
2544
default_from_env=default_from_env,
2545
from_unicode=self.from_unicode, help=help,
2546
invalid=invalid, unquote=False)
2547
self.registry = registry
2549
def from_unicode(self, unicode_str):
2550
if not isinstance(unicode_str, basestring):
2553
return self.registry.get(unicode_str)
2556
"Invalid value %s for %s."
2557
"See help for a list of possible values." % (unicode_str,
2562
ret = [self._help, "\n\nThe following values are supported:\n"]
2563
for key in self.registry.keys():
2564
ret.append(" %s - %s\n" % (key, self.registry.get_help(key)))
2568
class OptionRegistry(registry.Registry):
2569
"""Register config options by their name.
2571
This overrides ``registry.Registry`` to simplify registration by acquiring
2572
some information from the option object itself.
2575
def register(self, option):
2576
"""Register a new option to its name.
2578
:param option: The option to register. Its name is used as the key.
2580
super(OptionRegistry, self).register(option.name, option,
2583
def register_lazy(self, key, module_name, member_name):
2584
"""Register a new option to be loaded on request.
2586
:param key: the key to request the option later. Since the registration
2587
is lazy, it should be provided and match the option name.
2589
:param module_name: the python path to the module. Such as 'os.path'.
2591
:param member_name: the member of the module to return. If empty or
2592
None, get() will return the module itself.
2594
super(OptionRegistry, self).register_lazy(key,
2595
module_name, member_name)
2597
def get_help(self, key=None):
2598
"""Get the help text associated with the given key"""
2599
option = self.get(key)
2600
the_help = option.help
2601
if callable(the_help):
2602
return the_help(self, key)
2606
option_registry = OptionRegistry()
2609
# Registered options in lexicographical order
2611
option_registry.register(
2612
Option('append_revisions_only',
2613
default=None, from_unicode=bool_from_store, invalid='warning',
2615
Whether to only append revisions to the mainline.
2617
If this is set to true, then it is not possible to change the
2618
existing mainline of the branch.
2620
option_registry.register(
2621
ListOption('acceptable_keys',
2624
List of GPG key patterns which are acceptable for verification.
2626
option_registry.register(
2627
Option('add.maximum_file_size',
2628
default=u'20MB', from_unicode=int_SI_from_store,
2630
Size above which files should be added manually.
2632
Files below this size are added automatically when using ``bzr add`` without
2635
A negative value means disable the size check.
2637
option_registry.register(
2639
default=None, from_unicode=bool_from_store,
2641
Is the branch bound to ``bound_location``.
2643
If set to "True", the branch should act as a checkout, and push each commit to
2644
the bound_location. This option is normally set by ``bind``/``unbind``.
2646
See also: bound_location.
2648
option_registry.register(
2649
Option('bound_location',
2652
The location that commits should go to when acting as a checkout.
2654
This option is normally set by ``bind``.
2658
option_registry.register(
2659
Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
2661
Whether revisions associated with tags should be fetched.
2663
option_registry.register_lazy(
2664
'bzr.transform.orphan_policy', 'bzrlib.transform', 'opt_transform_orphan')
2665
option_registry.register(
2666
Option('bzr.workingtree.worth_saving_limit', default=10,
2667
from_unicode=int_from_store, invalid='warning',
2669
How many changes before saving the dirstate.
2671
-1 means that we will never rewrite the dirstate file for only
2672
stat-cache changes. Regardless of this setting, we will always rewrite
2673
the dirstate file if a file is added/removed/renamed/etc. This flag only
2674
affects the behavior of updating the dirstate file after we notice that
2675
a file has been touched.
2677
option_registry.register(
2678
Option('bugtracker', default=None,
2680
Default bug tracker to use.
2682
This bug tracker will be used for example when marking bugs
2683
as fixed using ``bzr commit --fixes``, if no explicit
2684
bug tracker was specified.
2686
option_registry.register(
2687
Option('check_signatures', default=CHECK_IF_POSSIBLE,
2688
from_unicode=signature_policy_from_unicode,
2690
GPG checking policy.
2692
Possible values: require, ignore, check-available (default)
2694
this option will control whether bzr will require good gpg
2695
signatures, ignore them, or check them if they are
2698
option_registry.register(
2699
Option('child_submit_format',
2700
help='''The preferred format of submissions to this branch.'''))
2701
option_registry.register(
2702
Option('child_submit_to',
2703
help='''Where submissions to this branch are mailed to.'''))
2704
option_registry.register(
2705
Option('create_signatures', default=SIGN_WHEN_REQUIRED,
2706
from_unicode=signing_policy_from_unicode,
2710
Possible values: always, never, when-required (default)
2712
This option controls whether bzr will always create
2713
gpg signatures or not on commits.
2715
option_registry.register(
2716
Option('dirstate.fdatasync', default=True,
2717
from_unicode=bool_from_store,
2719
Flush dirstate changes onto physical disk?
2721
If true (default), working tree metadata changes are flushed through the
2722
OS buffers to physical disk. This is somewhat slower, but means data
2723
should not be lost if the machine crashes. See also repository.fdatasync.
2725
option_registry.register(
2726
ListOption('debug_flags', default=[],
2727
help='Debug flags to activate.'))
2728
option_registry.register(
2729
Option('default_format', default='2a',
2730
help='Format used when creating branches.'))
2731
option_registry.register(
2732
Option('dpush_strict', default=None,
2733
from_unicode=bool_from_store,
2735
The default value for ``dpush --strict``.
2737
If present, defines the ``--strict`` option default value for checking
2738
uncommitted changes before pushing into a different VCS without any
2739
custom bzr metadata.
2741
option_registry.register(
2743
help='The command called to launch an editor to enter a message.'))
2744
option_registry.register(
2745
Option('email', override_from_env=['BZR_EMAIL'], default=default_email,
2746
help='The users identity'))
2747
option_registry.register(
2748
Option('gpg_signing_command',
2751
Program to use use for creating signatures.
2753
This should support at least the -u and --clearsign options.
2755
option_registry.register(
2756
Option('gpg_signing_key',
2759
GPG key to use for signing.
2761
This defaults to the first key associated with the users email.
2763
option_registry.register(
2764
Option('ignore_missing_extensions', default=False,
2765
from_unicode=bool_from_store,
2767
Control the missing extensions warning display.
2769
The warning will not be emitted if set to True.
2771
option_registry.register(
2773
help='Language to translate messages into.'))
2774
option_registry.register(
2775
Option('locks.steal_dead', default=False, from_unicode=bool_from_store,
2777
Steal locks that appears to be dead.
2779
If set to True, bzr will check if a lock is supposed to be held by an
2780
active process from the same user on the same machine. If the user and
2781
machine match, but no process with the given PID is active, then bzr
2782
will automatically break the stale lock, and create a new lock for
2784
Otherwise, bzr will prompt as normal to break the lock.
2786
option_registry.register(
2787
Option('log_format', default='long',
2789
Log format to use when displaying revisions.
2791
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2792
may be provided by plugins.
2794
option_registry.register_lazy('mail_client', 'bzrlib.mail_client',
2796
option_registry.register(
2797
Option('output_encoding',
2798
help= 'Unicode encoding for output'
2799
' (terminal encoding if not specified).'))
2800
option_registry.register(
2801
Option('parent_location',
2804
The location of the default branch for pull or merge.
2806
This option is normally set when creating a branch, the first ``pull`` or by
2807
``pull --remember``.
2809
option_registry.register(
2810
Option('post_commit', default=None,
2812
Post commit functions.
2814
An ordered list of python functions to call, separated by spaces.
2816
Each function takes branch, rev_id as parameters.
2818
option_registry.register(
2819
Option('public_branch',
2822
A publically-accessible version of this branch.
2824
This implies that the branch setting this option is not publically-accessible.
2825
Used and set by ``bzr send``.
2827
option_registry.register(
2828
Option('push_location',
2831
The location of the default branch for push.
2833
This option is normally set by the first ``push`` or ``push --remember``.
2835
option_registry.register(
2836
Option('push_strict', default=None,
2837
from_unicode=bool_from_store,
2839
The default value for ``push --strict``.
2841
If present, defines the ``--strict`` option default value for checking
2842
uncommitted changes before sending a merge directive.
2844
option_registry.register(
2845
Option('repository.fdatasync', default=True,
2846
from_unicode=bool_from_store,
2848
Flush repository changes onto physical disk?
2850
If true (default), repository changes are flushed through the OS buffers
2851
to physical disk. This is somewhat slower, but means data should not be
2852
lost if the machine crashes. See also dirstate.fdatasync.
2854
option_registry.register_lazy('smtp_server',
2855
'bzrlib.smtp_connection', 'smtp_server')
2856
option_registry.register_lazy('smtp_password',
2857
'bzrlib.smtp_connection', 'smtp_password')
2858
option_registry.register_lazy('smtp_username',
2859
'bzrlib.smtp_connection', 'smtp_username')
2860
option_registry.register(
2861
Option('selftest.timeout',
2863
from_unicode=int_from_store,
2864
help='Abort selftest if one test takes longer than this many seconds',
2867
option_registry.register(
2868
Option('send_strict', default=None,
2869
from_unicode=bool_from_store,
2871
The default value for ``send --strict``.
2873
If present, defines the ``--strict`` option default value for checking
2874
uncommitted changes before sending a bundle.
2877
option_registry.register(
2878
Option('serve.client_timeout',
2879
default=300.0, from_unicode=float_from_store,
2880
help="If we wait for a new request from a client for more than"
2881
" X seconds, consider the client idle, and hangup."))
2882
option_registry.register(
2883
Option('stacked_on_location',
2885
help="""The location where this branch is stacked on."""))
2886
option_registry.register(
2887
Option('submit_branch',
2890
The branch you intend to submit your current work to.
2892
This is automatically set by ``bzr send`` and ``bzr merge``, and is also used
2893
by the ``submit:`` revision spec.
2895
option_registry.register(
2897
help='''Where submissions from this branch are mailed to.'''))
2898
option_registry.register(
2899
ListOption('suppress_warnings',
2901
help="List of warning classes to suppress."))
2902
option_registry.register(
2903
Option('validate_signatures_in_log', default=False,
2904
from_unicode=bool_from_store, invalid='warning',
2905
help='''Whether to validate signatures in bzr log.'''))
2906
option_registry.register_lazy('ssl.ca_certs',
2907
'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2909
option_registry.register_lazy('ssl.cert_reqs',
2910
'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2913
class Section(object):
2914
"""A section defines a dict of option name => value.
2916
This is merely a read-only dict which can add some knowledge about the
2917
options. It is *not* a python dict object though and doesn't try to mimic
2921
def __init__(self, section_id, options):
2922
self.id = section_id
2923
# We re-use the dict-like object received
2924
self.options = options
2926
def get(self, name, default=None, expand=True):
2927
return self.options.get(name, default)
2929
def iter_option_names(self):
2930
for k in self.options.iterkeys():
2934
# Mostly for debugging use
2935
return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
2938
_NewlyCreatedOption = object()
2939
"""Was the option created during the MutableSection lifetime"""
2940
_DeletedOption = object()
2941
"""Was the option deleted during the MutableSection lifetime"""
2944
class MutableSection(Section):
2945
"""A section allowing changes and keeping track of the original values."""
2947
def __init__(self, section_id, options):
2948
super(MutableSection, self).__init__(section_id, options)
2949
self.reset_changes()
2951
def set(self, name, value):
2952
if name not in self.options:
2953
# This is a new option
2954
self.orig[name] = _NewlyCreatedOption
2955
elif name not in self.orig:
2956
self.orig[name] = self.get(name, None)
2957
self.options[name] = value
2959
def remove(self, name):
2960
if name not in self.orig:
2961
self.orig[name] = self.get(name, None)
2962
del self.options[name]
2964
def reset_changes(self):
2967
def apply_changes(self, dirty, store):
2968
"""Apply option value changes.
2970
``self`` has been reloaded from the persistent storage. ``dirty``
2971
contains the changes made since the previous loading.
2973
:param dirty: the mutable section containing the changes.
2975
:param store: the store containing the section
2977
for k, expected in dirty.orig.iteritems():
2978
actual = dirty.get(k, _DeletedOption)
2979
reloaded = self.get(k, _NewlyCreatedOption)
2980
if actual is _DeletedOption:
2981
if k in self.options:
2985
# Report concurrent updates in an ad-hoc way. This should only
2986
# occurs when different processes try to update the same option
2987
# which is not supported (as in: the config framework is not meant
2988
# to be used a sharing mechanism).
2989
if expected != reloaded:
2990
if actual is _DeletedOption:
2991
actual = '<DELETED>'
2992
if reloaded is _NewlyCreatedOption:
2993
reloaded = '<CREATED>'
2994
if expected is _NewlyCreatedOption:
2995
expected = '<CREATED>'
2996
# Someone changed the value since we get it from the persistent
2998
trace.warning(gettext(
2999
"Option {0} in section {1} of {2} was changed"
3000
" from {3} to {4}. The {5} value will be saved.".format(
3001
k, self.id, store.external_url(), expected,
3003
# No need to keep track of these changes
3004
self.reset_changes()
3007
class Store(object):
3008
"""Abstract interface to persistent storage for configuration options."""
3010
readonly_section_class = Section
3011
mutable_section_class = MutableSection
3014
# Which sections need to be saved
3015
self.dirty_sections = []
3017
def is_loaded(self):
3018
"""Returns True if the Store has been loaded.
3020
This is used to implement lazy loading and ensure the persistent
3021
storage is queried only when needed.
3023
raise NotImplementedError(self.is_loaded)
3026
"""Loads the Store from persistent storage."""
3027
raise NotImplementedError(self.load)
3029
def _load_from_string(self, bytes):
3030
"""Create a store from a string in configobj syntax.
3032
:param bytes: A string representing the file content.
3034
raise NotImplementedError(self._load_from_string)
3037
"""Unloads the Store.
3039
This should make is_loaded() return False. This is used when the caller
3040
knows that the persistent storage has changed or may have change since
3043
raise NotImplementedError(self.unload)
3045
def quote(self, value):
3046
"""Quote a configuration option value for storing purposes.
3048
This allows Stacks to present values as they will be stored.
3052
def unquote(self, value):
3053
"""Unquote a configuration option value into unicode.
3055
The received value is quoted as stored.
3060
"""Saves the Store to persistent storage."""
3061
raise NotImplementedError(self.save)
3063
def _need_saving(self):
3064
for s in self.dirty_sections:
3066
# At least one dirty section contains a modification
3070
def apply_changes(self, dirty_sections):
3071
"""Apply changes from dirty sections while checking for coherency.
3073
The Store content is discarded and reloaded from persistent storage to
3074
acquire up-to-date values.
3076
Dirty sections are MutableSection which kept track of the value they
3077
are expected to update.
3079
# We need an up-to-date version from the persistent storage, unload the
3080
# store. The reload will occur when needed (triggered by the first
3081
# get_mutable_section() call below.
3083
# Apply the changes from the preserved dirty sections
3084
for dirty in dirty_sections:
3085
clean = self.get_mutable_section(dirty.id)
3086
clean.apply_changes(dirty, self)
3087
# Everything is clean now
3088
self.dirty_sections = []
3090
def save_changes(self):
3091
"""Saves the Store to persistent storage if changes occurred.
3093
Apply the changes recorded in the mutable sections to a store content
3094
refreshed from persistent storage.
3096
raise NotImplementedError(self.save_changes)
3098
def external_url(self):
3099
raise NotImplementedError(self.external_url)
3101
def get_sections(self):
3102
"""Returns an ordered iterable of existing sections.
3104
:returns: An iterable of (store, section).
3106
raise NotImplementedError(self.get_sections)
3108
def get_mutable_section(self, section_id=None):
3109
"""Returns the specified mutable section.
3111
:param section_id: The section identifier
3113
raise NotImplementedError(self.get_mutable_section)
3116
# Mostly for debugging use
3117
return "<config.%s(%s)>" % (self.__class__.__name__,
3118
self.external_url())
3121
class CommandLineStore(Store):
3122
"A store to carry command line overrides for the config options."""
3124
def __init__(self, opts=None):
3125
super(CommandLineStore, self).__init__()
3132
# The dict should be cleared but not replaced so it can be shared.
3133
self.options.clear()
3135
def _from_cmdline(self, overrides):
3136
# Reset before accepting new definitions
3138
for over in overrides:
3140
name, value = over.split('=', 1)
3142
raise errors.BzrCommandError(
3143
gettext("Invalid '%s', should be of the form 'name=value'")
3145
self.options[name] = value
3147
def external_url(self):
3148
# Not an url but it makes debugging easier and is never needed
3152
def get_sections(self):
3153
yield self, self.readonly_section_class(None, self.options)
3156
class IniFileStore(Store):
3157
"""A config Store using ConfigObj for storage.
3159
:ivar _config_obj: Private member to hold the ConfigObj instance used to
3160
serialize/deserialize the config file.
3164
"""A config Store using ConfigObj for storage.
3166
super(IniFileStore, self).__init__()
3167
self._config_obj = None
3169
def is_loaded(self):
3170
return self._config_obj != None
3173
self._config_obj = None
3174
self.dirty_sections = []
3176
def _load_content(self):
3177
"""Load the config file bytes.
3179
This should be provided by subclasses
3181
:return: Byte string
3183
raise NotImplementedError(self._load_content)
3185
def _save_content(self, content):
3186
"""Save the config file bytes.
3188
This should be provided by subclasses
3190
:param content: Config file bytes to write
3192
raise NotImplementedError(self._save_content)
3195
"""Load the store from the associated file."""
3196
if self.is_loaded():
3198
content = self._load_content()
3199
self._load_from_string(content)
3200
for hook in ConfigHooks['load']:
3203
def _load_from_string(self, bytes):
3204
"""Create a config store from a string.
3206
:param bytes: A string representing the file content.
3208
if self.is_loaded():
3209
raise AssertionError('Already loaded: %r' % (self._config_obj,))
3210
co_input = StringIO(bytes)
3212
# The config files are always stored utf8-encoded
3213
self._config_obj = ConfigObj(co_input, encoding='utf-8',
3215
except configobj.ConfigObjError, e:
3216
self._config_obj = None
3217
raise errors.ParseConfigError(e.errors, self.external_url())
3218
except UnicodeDecodeError:
3219
raise errors.ConfigContentError(self.external_url())
3221
def save_changes(self):
3222
if not self.is_loaded():
3225
if not self._need_saving():
3227
# Preserve the current version
3228
current = self._config_obj
3229
dirty_sections = list(self.dirty_sections)
3230
self.apply_changes(dirty_sections)
3231
# Save to the persistent storage
3235
if not self.is_loaded():
3239
self._config_obj.write(out)
3240
self._save_content(out.getvalue())
3241
for hook in ConfigHooks['save']:
3244
def get_sections(self):
3245
"""Get the configobj section in the file order.
3247
:returns: An iterable of (store, section).
3249
# We need a loaded store
3252
except (errors.NoSuchFile, errors.PermissionDenied):
3253
# If the file can't be read, there is no sections
3255
cobj = self._config_obj
3257
yield self, self.readonly_section_class(None, cobj)
3258
for section_name in cobj.sections:
3260
self.readonly_section_class(section_name,
3261
cobj[section_name]))
3263
def get_mutable_section(self, section_id=None):
3264
# We need a loaded store
3267
except errors.NoSuchFile:
3268
# The file doesn't exist, let's pretend it was empty
3269
self._load_from_string('')
3270
if section_id is None:
3271
section = self._config_obj
3273
section = self._config_obj.setdefault(section_id, {})
3274
mutable_section = self.mutable_section_class(section_id, section)
3275
# All mutable sections can become dirty
3276
self.dirty_sections.append(mutable_section)
3277
return mutable_section
3279
def quote(self, value):
3281
# configobj conflates automagical list values and quoting
3282
self._config_obj.list_values = True
3283
return self._config_obj._quote(value)
3285
self._config_obj.list_values = False
3287
def unquote(self, value):
3288
if value and isinstance(value, basestring):
3289
# _unquote doesn't handle None nor empty strings nor anything that
3290
# is not a string, really.
3291
value = self._config_obj._unquote(value)
3294
def external_url(self):
3295
# Since an IniFileStore can be used without a file (at least in tests),
3296
# it's better to provide something than raising a NotImplementedError.
3297
# All daughter classes are supposed to provide an implementation
3299
return 'In-Process Store, no URL'
3301
class TransportIniFileStore(IniFileStore):
3302
"""IniFileStore that loads files from a transport.
3304
:ivar transport: The transport object where the config file is located.
3306
:ivar file_name: The config file basename in the transport directory.
3309
def __init__(self, transport, file_name):
3310
"""A Store using a ini file on a Transport
3312
:param transport: The transport object where the config file is located.
3313
:param file_name: The config file basename in the transport directory.
3315
super(TransportIniFileStore, self).__init__()
3316
self.transport = transport
3317
self.file_name = file_name
3319
def _load_content(self):
3321
return self.transport.get_bytes(self.file_name)
3322
except errors.PermissionDenied:
3323
trace.warning("Permission denied while trying to load "
3324
"configuration store %s.", self.external_url())
3327
def _save_content(self, content):
3328
self.transport.put_bytes(self.file_name, content)
3330
def external_url(self):
3331
# FIXME: external_url should really accepts an optional relpath
3332
# parameter (bug #750169) :-/ -- vila 2011-04-04
3333
# The following will do in the interim but maybe we don't want to
3334
# expose a path here but rather a config ID and its associated
3335
# object </hand wawe>.
3336
return urlutils.join(self.transport.external_url(), self.file_name)
3339
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
3340
# unlockable stores for use with objects that can already ensure the locking
3341
# (think branches). If different stores (not based on ConfigObj) are created,
3342
# they may face the same issue.
3345
class LockableIniFileStore(TransportIniFileStore):
3346
"""A ConfigObjStore using locks on save to ensure store integrity."""
3348
def __init__(self, transport, file_name, lock_dir_name=None):
3349
"""A config Store using ConfigObj for storage.
3351
:param transport: The transport object where the config file is located.
3353
:param file_name: The config file basename in the transport directory.
3355
if lock_dir_name is None:
3356
lock_dir_name = 'lock'
3357
self.lock_dir_name = lock_dir_name
3358
super(LockableIniFileStore, self).__init__(transport, file_name)
3359
self._lock = lockdir.LockDir(self.transport, self.lock_dir_name)
3361
def lock_write(self, token=None):
3362
"""Takes a write lock in the directory containing the config file.
3364
If the directory doesn't exist it is created.
3366
# FIXME: This doesn't check the ownership of the created directories as
3367
# ensure_config_dir_exists does. It should if the transport is local
3368
# -- vila 2011-04-06
3369
self.transport.create_prefix()
3370
return self._lock.lock_write(token)
3375
def break_lock(self):
3376
self._lock.break_lock()
3380
# We need to be able to override the undecorated implementation
3381
self.save_without_locking()
3383
def save_without_locking(self):
3384
super(LockableIniFileStore, self).save()
3387
# FIXME: global, bazaar, shouldn't that be 'user' instead or even
3388
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
3389
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
3391
# FIXME: Moreover, we shouldn't need classes for these stores either, factory
3392
# functions or a registry will make it easier and clearer for tests, focusing
3393
# on the relevant parts of the API that needs testing -- vila 20110503 (based
3394
# on a poolie's remark)
3395
class GlobalStore(LockableIniFileStore):
3397
def __init__(self, possible_transports=None):
3398
t = transport.get_transport_from_path(
3399
config_dir(), possible_transports=possible_transports)
3400
super(GlobalStore, self).__init__(t, 'bazaar.conf')
3404
class LocationStore(LockableIniFileStore):
3406
def __init__(self, possible_transports=None):
3407
t = transport.get_transport_from_path(
3408
config_dir(), possible_transports=possible_transports)
3409
super(LocationStore, self).__init__(t, 'locations.conf')
3410
self.id = 'locations'
3413
class BranchStore(TransportIniFileStore):
3415
def __init__(self, branch):
3416
super(BranchStore, self).__init__(branch.control_transport,
3418
self.branch = branch
3422
class ControlStore(LockableIniFileStore):
3424
def __init__(self, bzrdir):
3425
super(ControlStore, self).__init__(bzrdir.transport,
3427
lock_dir_name='branch_lock')
3431
class SectionMatcher(object):
3432
"""Select sections into a given Store.
3434
This is intended to be used to postpone getting an iterable of sections
3438
def __init__(self, store):
3441
def get_sections(self):
3442
# This is where we require loading the store so we can see all defined
3444
sections = self.store.get_sections()
3445
# Walk the revisions in the order provided
3446
for store, s in sections:
3450
def match(self, section):
3451
"""Does the proposed section match.
3453
:param section: A Section object.
3455
:returns: True if the section matches, False otherwise.
3457
raise NotImplementedError(self.match)
3460
class NameMatcher(SectionMatcher):
3462
def __init__(self, store, section_id):
3463
super(NameMatcher, self).__init__(store)
3464
self.section_id = section_id
3466
def match(self, section):
3467
return section.id == self.section_id
3470
class LocationSection(Section):
3472
def __init__(self, section, extra_path):
3473
super(LocationSection, self).__init__(section.id, section.options)
3474
self.extra_path = extra_path
3475
self.locals = {'relpath': extra_path,
3476
'basename': urlutils.basename(extra_path)}
3478
def get(self, name, default=None, expand=True):
3479
value = super(LocationSection, self).get(name, default)
3480
if value is not None and expand:
3481
policy_name = self.get(name + ':policy', None)
3482
policy = _policy_value.get(policy_name, POLICY_NONE)
3483
if policy == POLICY_APPENDPATH:
3484
value = urlutils.join(value, self.extra_path)
3485
# expand section local options right now (since POLICY_APPENDPATH
3486
# will never add options references, it's ok to expand after it).
3488
for is_ref, chunk in iter_option_refs(value):
3490
chunks.append(chunk)
3493
if ref in self.locals:
3494
chunks.append(self.locals[ref])
3496
chunks.append(chunk)
3497
value = ''.join(chunks)
3501
class StartingPathMatcher(SectionMatcher):
3502
"""Select sections for a given location respecting the Store order."""
3504
# FIXME: Both local paths and urls can be used for section names as well as
3505
# ``location`` to stay consistent with ``LocationMatcher`` which itself
3506
# inherited the fuzziness from the previous ``LocationConfig``
3507
# implementation. We probably need to revisit which encoding is allowed for
3508
# both ``location`` and section names and how we normalize
3509
# them. http://pad.lv/85479, http://pad.lv/437009 and http://359320 are
3510
# related too. -- vila 2012-01-04
3512
def __init__(self, store, location):
3513
super(StartingPathMatcher, self).__init__(store)
3514
if location.startswith('file://'):
3515
location = urlutils.local_path_from_url(location)
3516
self.location = location
3518
def get_sections(self):
3519
"""Get all sections matching ``location`` in the store.
3521
The most generic sections are described first in the store, then more
3522
specific ones can be provided for reduced scopes.
3524
The returned section are therefore returned in the reversed order so
3525
the most specific ones can be found first.
3527
location_parts = self.location.rstrip('/').split('/')
3530
# Later sections are more specific, they should be returned first
3531
for _, section in reversed(list(store.get_sections())):
3532
if section.id is None:
3533
# The no-name section is always included if present
3534
yield store, LocationSection(section, self.location)
3536
section_path = section.id
3537
if section_path.startswith('file://'):
3538
# the location is already a local path or URL, convert the
3539
# section id to the same format
3540
section_path = urlutils.local_path_from_url(section_path)
3541
if (self.location.startswith(section_path)
3542
or fnmatch.fnmatch(self.location, section_path)):
3543
section_parts = section_path.rstrip('/').split('/')
3544
extra_path = '/'.join(location_parts[len(section_parts):])
3545
yield store, LocationSection(section, extra_path)
3548
class LocationMatcher(SectionMatcher):
3550
def __init__(self, store, location):
3551
super(LocationMatcher, self).__init__(store)
3552
if location.startswith('file://'):
3553
location = urlutils.local_path_from_url(location)
3554
self.location = location
3556
def _get_matching_sections(self):
3557
"""Get all sections matching ``location``."""
3558
# We slightly diverge from LocalConfig here by allowing the no-name
3559
# section as the most generic one and the lower priority.
3560
no_name_section = None
3562
# Filter out the no_name_section so _iter_for_location_by_parts can be
3563
# used (it assumes all sections have a name).
3564
for _, section in self.store.get_sections():
3565
if section.id is None:
3566
no_name_section = section
3568
all_sections.append(section)
3569
# Unfortunately _iter_for_location_by_parts deals with section names so
3570
# we have to resync.
3571
filtered_sections = _iter_for_location_by_parts(
3572
[s.id for s in all_sections], self.location)
3573
iter_all_sections = iter(all_sections)
3574
matching_sections = []
3575
if no_name_section is not None:
3576
matching_sections.append(
3577
(0, LocationSection(no_name_section, self.location)))
3578
for section_id, extra_path, length in filtered_sections:
3579
# a section id is unique for a given store so it's safe to take the
3580
# first matching section while iterating. Also, all filtered
3581
# sections are part of 'all_sections' and will always be found
3584
section = iter_all_sections.next()
3585
if section_id == section.id:
3586
matching_sections.append(
3587
(length, LocationSection(section, extra_path)))
3589
return matching_sections
3591
def get_sections(self):
3592
# Override the default implementation as we want to change the order
3593
matching_sections = self._get_matching_sections()
3594
# We want the longest (aka more specific) locations first
3595
sections = sorted(matching_sections,
3596
key=lambda (length, section): (length, section.id),
3598
# Sections mentioning 'ignore_parents' restrict the selection
3599
for _, section in sections:
3600
# FIXME: We really want to use as_bool below -- vila 2011-04-07
3601
ignore = section.get('ignore_parents', None)
3602
if ignore is not None:
3603
ignore = ui.bool_from_string(ignore)
3606
# Finally, we have a valid section
3607
yield self.store, section
3610
_option_ref_re = lazy_regex.lazy_compile('({[^{}\n]+})')
3611
"""Describes an expandable option reference.
3613
We want to match the most embedded reference first.
3615
I.e. for '{{foo}}' we will get '{foo}',
3616
for '{bar{baz}}' we will get '{baz}'
3619
def iter_option_refs(string):
3620
# Split isolate refs so every other chunk is a ref
3622
for chunk in _option_ref_re.split(string):
3627
class Stack(object):
3628
"""A stack of configurations where an option can be defined"""
3630
def __init__(self, sections_def, store=None, mutable_section_id=None):
3631
"""Creates a stack of sections with an optional store for changes.
3633
:param sections_def: A list of Section or callables that returns an
3634
iterable of Section. This defines the Sections for the Stack and
3635
can be called repeatedly if needed.
3637
:param store: The optional Store where modifications will be
3638
recorded. If none is specified, no modifications can be done.
3640
:param mutable_section_id: The id of the MutableSection where changes
3641
are recorded. This requires the ``store`` parameter to be
3644
self.sections_def = sections_def
3646
self.mutable_section_id = mutable_section_id
3648
def get(self, name, expand=None):
3649
"""Return the *first* option value found in the sections.
3651
This is where we guarantee that sections coming from Store are loaded
3652
lazily: the loading is delayed until we need to either check that an
3653
option exists or get its value, which in turn may require to discover
3654
in which sections it can be defined. Both of these (section and option
3655
existence) require loading the store (even partially).
3657
:param name: The queried option.
3659
:param expand: Whether options references should be expanded.
3661
:returns: The value of the option.
3663
# FIXME: No caching of options nor sections yet -- vila 20110503
3665
expand = _get_expand_default_value()
3667
found_store = None # Where the option value has been found
3668
# If the option is registered, it may provide additional info about
3671
opt = option_registry.get(name)
3676
def expand_and_convert(val):
3677
# This may need to be called in different contexts if the value is
3678
# None or ends up being None during expansion or conversion.
3681
if isinstance(val, basestring):
3682
val = self._expand_options_in_string(val)
3684
trace.warning('Cannot expand "%s":'
3685
' %s does not support option expansion'
3686
% (name, type(val)))
3688
val = found_store.unquote(val)
3690
val = opt.convert_from_unicode(found_store, val)
3693
# First of all, check if the environment can override the configuration
3695
if opt is not None and opt.override_from_env:
3696
value = opt.get_override()
3697
value = expand_and_convert(value)
3699
# Ensuring lazy loading is achieved by delaying section matching
3700
# (which implies querying the persistent storage) until it can't be
3701
# avoided anymore by using callables to describe (possibly empty)
3703
for sections in self.sections_def:
3704
for store, section in sections():
3705
value = section.get(name)
3706
if value is not None:
3709
if value is not None:
3711
value = expand_and_convert(value)
3712
if opt is not None and value is None:
3713
# If the option is registered, it may provide a default value
3714
value = opt.get_default()
3715
value = expand_and_convert(value)
3716
for hook in ConfigHooks['get']:
3717
hook(self, name, value)
3720
def expand_options(self, string, env=None):
3721
"""Expand option references in the string in the configuration context.
3723
:param string: The string containing option(s) to expand.
3725
:param env: An option dict defining additional configuration options or
3726
overriding existing ones.
3728
:returns: The expanded string.
3730
return self._expand_options_in_string(string, env)
3732
def _expand_options_in_string(self, string, env=None, _refs=None):
3733
"""Expand options in the string in the configuration context.
3735
:param string: The string to be expanded.
3737
:param env: An option dict defining additional configuration options or
3738
overriding existing ones.
3740
:param _refs: Private list (FIFO) containing the options being expanded
3743
:returns: The expanded string.
3746
# Not much to expand there
3749
# What references are currently resolved (to detect loops)
3752
# We need to iterate until no more refs appear ({{foo}} will need two
3753
# iterations for example).
3758
for is_ref, chunk in iter_option_refs(result):
3760
chunks.append(chunk)
3765
raise errors.OptionExpansionLoop(string, _refs)
3767
value = self._expand_option(name, env, _refs)
3769
raise errors.ExpandingUnknownOption(name, string)
3770
chunks.append(value)
3772
result = ''.join(chunks)
3775
def _expand_option(self, name, env, _refs):
3776
if env is not None and name in env:
3777
# Special case, values provided in env takes precedence over
3781
value = self.get(name, expand=False)
3782
value = self._expand_options_in_string(value, env, _refs)
3785
def _get_mutable_section(self):
3786
"""Get the MutableSection for the Stack.
3788
This is where we guarantee that the mutable section is lazily loaded:
3789
this means we won't load the corresponding store before setting a value
3790
or deleting an option. In practice the store will often be loaded but
3791
this helps catching some programming errors.
3794
section = store.get_mutable_section(self.mutable_section_id)
3795
return store, section
3797
def set(self, name, value):
3798
"""Set a new value for the option."""
3799
store, section = self._get_mutable_section()
3800
section.set(name, store.quote(value))
3801
for hook in ConfigHooks['set']:
3802
hook(self, name, value)
3804
def remove(self, name):
3805
"""Remove an existing option."""
3806
_, section = self._get_mutable_section()
3807
section.remove(name)
3808
for hook in ConfigHooks['remove']:
3812
# Mostly for debugging use
3813
return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3815
def _get_overrides(self):
3816
# Hack around library_state.initialize never called
3817
if bzrlib.global_state is not None:
3818
return bzrlib.global_state.cmdline_overrides.get_sections()
3822
class MemoryStack(Stack):
3823
"""A configuration stack defined from a string.
3825
This is mainly intended for tests and requires no disk resources.
3828
def __init__(self, content=None):
3829
"""Create an in-memory stack from a given content.
3831
It uses a single store based on configobj and support reading and
3834
:param content: The initial content of the store. If None, the store is
3835
not loaded and ``_load_from_string`` can and should be used if
3838
store = IniFileStore()
3839
if content is not None:
3840
store._load_from_string(content)
3841
super(MemoryStack, self).__init__(
3842
[store.get_sections], store)
3845
class _CompatibleStack(Stack):
3846
"""Place holder for compatibility with previous design.
3848
This is intended to ease the transition from the Config-based design to the
3849
Stack-based design and should not be used nor relied upon by plugins.
3851
One assumption made here is that the daughter classes will all use Stores
3852
derived from LockableIniFileStore).
3854
It implements set() and remove () by re-loading the store before applying
3855
the modification and saving it.
3857
The long term plan being to implement a single write by store to save
3858
all modifications, this class should not be used in the interim.
3861
def set(self, name, value):
3864
super(_CompatibleStack, self).set(name, value)
3865
# Force a write to persistent storage
3868
def remove(self, name):
3871
super(_CompatibleStack, self).remove(name)
3872
# Force a write to persistent storage
3876
class GlobalStack(_CompatibleStack):
3877
"""Global options only stack.
3879
The following sections are queried:
3881
* command-line overrides,
3883
* the 'DEFAULT' section in bazaar.conf
3885
This stack will use the ``DEFAULT`` section in bazaar.conf as its
3890
gstore = GlobalStore()
3891
super(GlobalStack, self).__init__(
3892
[self._get_overrides,
3893
NameMatcher(gstore, 'DEFAULT').get_sections],
3894
gstore, mutable_section_id='DEFAULT')
3897
class LocationStack(_CompatibleStack):
3898
"""Per-location options falling back to global options stack.
3901
The following sections are queried:
3903
* command-line overrides,
3905
* the sections matching ``location`` in ``locations.conf``, the order being
3906
defined by the number of path components in the section glob, higher
3907
numbers first (from most specific section to most generic).
3909
* the 'DEFAULT' section in bazaar.conf
3911
This stack will use the ``location`` section in locations.conf as its
3915
def __init__(self, location):
3916
"""Make a new stack for a location and global configuration.
3918
:param location: A URL prefix to """
3919
lstore = LocationStore()
3920
if location.startswith('file://'):
3921
location = urlutils.local_path_from_url(location)
3922
gstore = GlobalStore()
3923
super(LocationStack, self).__init__(
3924
[self._get_overrides,
3925
LocationMatcher(lstore, location).get_sections,
3926
NameMatcher(gstore, 'DEFAULT').get_sections],
3927
lstore, mutable_section_id=location)
3930
class BranchStack(Stack):
3931
"""Per-location options falling back to branch then global options stack.
3933
The following sections are queried:
3935
* command-line overrides,
3937
* the sections matching ``location`` in ``locations.conf``, the order being
3938
defined by the number of path components in the section glob, higher
3939
numbers first (from most specific section to most generic),
3941
* the no-name section in branch.conf,
3943
* the ``DEFAULT`` section in ``bazaar.conf``.
3945
This stack will use the no-name section in ``branch.conf`` as its
3949
def __init__(self, branch):
3950
lstore = LocationStore()
3951
bstore = branch._get_config_store()
3952
gstore = GlobalStore()
3953
super(BranchStack, self).__init__(
3954
[self._get_overrides,
3955
LocationMatcher(lstore, branch.base).get_sections,
3956
NameMatcher(bstore, None).get_sections,
3957
NameMatcher(gstore, 'DEFAULT').get_sections],
3959
self.branch = branch
3961
def lock_write(self, token=None):
3962
return self.branch.lock_write(token)
3965
return self.branch.unlock()
3968
def set(self, name, value):
3969
super(BranchStack, self).set(name, value)
3970
# Unlocking the branch will trigger a store.save_changes() so the last
3971
# unlock saves all the changes.
3974
def remove(self, name):
3975
super(BranchStack, self).remove(name)
3976
# Unlocking the branch will trigger a store.save_changes() so the last
3977
# unlock saves all the changes.
3980
class RemoteControlStack(_CompatibleStack):
3981
"""Remote control-only options stack."""
3983
# FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
3984
# with the stack used for remote bzr dirs. RemoteControlStack only uses
3985
# control.conf and is used only for stack options.
3987
def __init__(self, bzrdir):
3988
cstore = bzrdir._get_config_store()
3989
super(RemoteControlStack, self).__init__(
3990
[NameMatcher(cstore, None).get_sections],
3992
self.bzrdir = bzrdir
3995
class BranchOnlyStack(Stack):
3996
"""Branch-only options stack."""
3998
# FIXME: _BranchOnlyStack only uses branch.conf and is used only for the
3999
# stacked_on_location options waiting for http://pad.lv/832042 to be fixed.
4000
# -- vila 2011-12-16
4002
def __init__(self, branch):
4003
bstore = branch._get_config_store()
4004
super(BranchOnlyStack, self).__init__(
4005
[NameMatcher(bstore, None).get_sections],
4007
self.branch = branch
4009
def lock_write(self, token=None):
4010
return self.branch.lock_write(token)
4013
return self.branch.unlock()
4016
def set(self, name, value):
4017
super(BranchOnlyStack, self).set(name, value)
4018
# Force a write to persistent storage
4019
self.store.save_changes()
4022
def remove(self, name):
4023
super(BranchOnlyStack, self).remove(name)
4024
# Force a write to persistent storage
4025
self.store.save_changes()
4028
# Use a an empty dict to initialize an empty configobj avoiding all
4029
# parsing and encoding checks
4030
_quoting_config = configobj.ConfigObj(
4031
{}, encoding='utf-8', interpolation=False, list_values=True)
4033
class cmd_config(commands.Command):
4034
__doc__ = """Display, set or remove a configuration option.
4036
Display the active value for a given option.
4038
If --all is specified, NAME is interpreted as a regular expression and all
4039
matching options are displayed mentioning their scope. The active value
4040
that bzr will take into account is the first one displayed for each option.
4042
If no NAME is given, --all .* is implied.
4044
Setting a value is achieved by using name=value without spaces. The value
4045
is set in the most relevant scope and can be checked by displaying the
4049
takes_args = ['name?']
4053
# FIXME: This should be a registry option so that plugins can register
4054
# their own config files (or not) and will also address
4055
# http://pad.lv/788991 -- vila 20101115
4056
commands.Option('scope', help='Reduce the scope to the specified'
4057
' configuration file.',
4059
commands.Option('all',
4060
help='Display all the defined values for the matching options.',
4062
commands.Option('remove', help='Remove the option from'
4063
' the configuration file.'),
4066
_see_also = ['configuration']
4068
@commands.display_command
4069
def run(self, name=None, all=False, directory=None, scope=None,
4071
if directory is None:
4073
directory = urlutils.normalize_url(directory)
4075
raise errors.BzrError(
4076
'--all and --remove are mutually exclusive.')
4078
# Delete the option in the given scope
4079
self._remove_config_option(name, directory, scope)
4081
# Defaults to all options
4082
self._show_matching_options('.*', directory, scope)
4085
name, value = name.split('=', 1)
4087
# Display the option(s) value(s)
4089
self._show_matching_options(name, directory, scope)
4091
self._show_value(name, directory, scope)
4094
raise errors.BzrError(
4095
'Only one option can be set.')
4096
# Set the option value
4097
self._set_config_option(name, value, directory, scope)
4099
def _get_stack(self, directory, scope=None, write_access=False):
4100
"""Get the configuration stack specified by ``directory`` and ``scope``.
4102
:param directory: Where the configurations are derived from.
4104
:param scope: A specific config to start from.
4106
:param write_access: Whether a write access to the stack will be
4109
# FIXME: scope should allow access to plugin-specific stacks (even
4110
# reduced to the plugin-specific store), related to
4111
# http://pad.lv/788991 -- vila 2011-11-15
4112
if scope is not None:
4113
if scope == 'bazaar':
4114
return GlobalStack()
4115
elif scope == 'locations':
4116
return LocationStack(directory)
4117
elif scope == 'branch':
4119
controldir.ControlDir.open_containing_tree_or_branch(
4122
self.add_cleanup(br.lock_write().unlock)
4123
return br.get_config_stack()
4124
raise errors.NoSuchConfig(scope)
4128
controldir.ControlDir.open_containing_tree_or_branch(
4131
self.add_cleanup(br.lock_write().unlock)
4132
return br.get_config_stack()
4133
except errors.NotBranchError:
4134
return LocationStack(directory)
4136
def _show_value(self, name, directory, scope):
4137
conf = self._get_stack(directory, scope)
4138
value = conf.get(name, expand=True)
4139
if value is not None:
4140
# Quote the value appropriately
4141
value = _quoting_config._quote(value)
4142
self.outf.write('%s\n' % (value,))
4144
raise errors.NoSuchConfigOption(name)
4146
def _show_matching_options(self, name, directory, scope):
4147
name = lazy_regex.lazy_compile(name)
4148
# We want any error in the regexp to be raised *now* so we need to
4149
# avoid the delay introduced by the lazy regexp. But, we still do
4150
# want the nicer errors raised by lazy_regex.
4151
name._compile_and_collapse()
4154
conf = self._get_stack(directory, scope)
4155
for sections in conf.sections_def:
4156
for store, section in sections():
4157
for oname in section.iter_option_names():
4158
if name.search(oname):
4159
if cur_store_id != store.id:
4160
# Explain where the options are defined
4161
self.outf.write('%s:\n' % (store.id,))
4162
cur_store_id = store.id
4164
if (section.id is not None
4165
and cur_section != section.id):
4166
# Display the section id as it appears in the store
4167
# (None doesn't appear by definition)
4168
self.outf.write(' [%s]\n' % (section.id,))
4169
cur_section = section.id
4170
value = section.get(oname, expand=False)
4171
# Since we don't use the stack, we need to restore a
4174
opt = option_registry.get(oname)
4175
value = opt.convert_from_unicode(store, value)
4177
value = store.unquote(value)
4178
value = _quoting_config._quote(value)
4179
self.outf.write(' %s = %s\n' % (oname, value))
4181
def _set_config_option(self, name, value, directory, scope):
4182
conf = self._get_stack(directory, scope, write_access=True)
4183
conf.set(name, value)
4185
def _remove_config_option(self, name, directory, scope):
4187
raise errors.BzrCommandError(
4188
'--remove expects an option to remove.')
4189
conf = self._get_stack(directory, scope, write_access=True)
4193
raise errors.NoSuchConfigOption(name)
4198
# We need adapters that can build a Store or a Stack in a test context. Test
4199
# classes, based on TestCaseWithTransport, can use the registry to parametrize
4200
# themselves. The builder will receive a test instance and should return a
4201
# ready-to-use store or stack. Plugins that define new store/stacks can also
4202
# register themselves here to be tested against the tests defined in
4203
# bzrlib.tests.test_config. Note that the builder can be called multiple times
4204
# for the same test.
4206
# The registered object should be a callable receiving a test instance
4207
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Store
4209
test_store_builder_registry = registry.Registry()
4211
# The registered object should be a callable receiving a test instance
4212
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Stack
4214
test_stack_builder_registry = registry.Registry()