829
215
def _get_user_option(self, option_name):
830
216
"""See Config._get_user_option."""
831
for (section, extra_path) in self._get_matching_sections():
833
value = self._get_parser().get_value(section, option_name)
836
policy = self._get_option_policy(section, option_name)
837
if policy == POLICY_NONE:
839
elif policy == POLICY_NORECURSE:
840
# norecurse items only apply to the exact path
845
elif policy == POLICY_APPENDPATH:
847
value = urlutils.join(value, extra_path)
850
raise AssertionError('Unexpected config policy %r' % policy)
854
def _log_format(self):
855
"""See Config.log_format."""
856
return self._get_user_option('log_format')
858
def _validate_signatures_in_log(self):
859
"""See Config.validate_signatures_in_log."""
860
return self._get_user_option('validate_signatures_in_log')
862
def _acceptable_keys(self):
863
"""See Config.acceptable_keys."""
864
return self._get_user_option('acceptable_keys')
218
return self._get_parser().get_value(self._get_section(),
223
def _gpg_signing_command(self):
224
"""See Config.gpg_signing_command."""
225
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
866
232
def _post_commit(self):
867
233
"""See Config.post_commit."""
868
234
return self._get_user_option('post_commit')
870
def _get_alias(self, value):
872
return self._get_parser().get_value("ALIASES",
877
def _get_nickname(self):
878
return self.get_user_option('nickname')
880
def remove_user_option(self, option_name, section_name=None):
881
"""Remove a user option and save the configuration file.
883
:param option_name: The option to be removed.
885
:param section_name: The section the option is defined in, default to
889
parser = self._get_parser()
890
if section_name is None:
893
section = parser[section_name]
895
del section[option_name]
897
raise NoSuchConfigOption(option_name)
898
self._write_config_file()
899
for hook in OldConfigHooks['remove']:
900
hook(self, option_name)
902
def _write_config_file(self):
903
if self.file_name is None:
904
raise AssertionError('We cannot save, self.file_name is None')
905
from . import atomicfile
906
conf_dir = os.path.dirname(self.file_name)
907
bedding.ensure_config_dir_exists(conf_dir)
908
with atomicfile.AtomicFile(self.file_name) as atomic_file:
909
self._get_parser().write(atomic_file)
910
osutils.copy_ownership_from_path(self.file_name)
911
for hook in OldConfigHooks['save']:
915
class LockableConfig(IniBasedConfig):
916
"""A configuration needing explicit locking for access.
918
If several processes try to write the config file, the accesses need to be
921
Daughter classes should use the self.lock_write() decorator method when
922
they upate a config (they call, directly or indirectly, the
923
``_write_config_file()`` method. These methods (typically ``set_option()``
924
and variants must reload the config file from disk before calling
925
``_write_config_file()``), this can be achieved by calling the
926
``self.reload()`` method. Note that the lock scope should cover both the
927
reading and the writing of the config file which is why the decorator can't
928
be applied to ``_write_config_file()`` only.
930
This should be enough to implement the following logic:
931
- lock for exclusive write access,
932
- reload the config file from disk,
936
This logic guarantees that a writer can update a value without erasing an
937
update made by another writer.
942
def __init__(self, file_name):
943
super(LockableConfig, self).__init__(file_name=file_name)
944
self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
945
# FIXME: It doesn't matter that we don't provide possible_transports
946
# below since this is currently used only for local config files ;
947
# local transports are not shared. But if/when we start using
948
# LockableConfig for other kind of transports, we will need to reuse
949
# whatever connection is already established -- vila 20100929
950
self.transport = transport.get_transport_from_path(self.dir)
951
self._lock = lockdir.LockDir(self.transport, self.lock_name)
953
def _create_from_string(self, unicode_bytes, save):
954
super(LockableConfig, self)._create_from_string(unicode_bytes, False)
956
# We need to handle the saving here (as opposed to IniBasedConfig)
959
self._write_config_file()
962
def lock_write(self, token=None):
963
"""Takes a write lock in the directory containing the config file.
965
If the directory doesn't exist it is created.
967
bedding.ensure_config_dir_exists(self.dir)
968
token = self._lock.lock_write(token)
969
return lock.LogicalLockResult(self.unlock, token)
974
def break_lock(self):
975
self._lock.break_lock()
977
def remove_user_option(self, option_name, section_name=None):
978
with self.lock_write():
979
super(LockableConfig, self).remove_user_option(
980
option_name, section_name)
982
def _write_config_file(self):
983
if self._lock is None or not self._lock.is_held:
984
# NB: if the following exception is raised it probably means a
985
# missing call to lock_write() by one of the callers.
986
raise errors.ObjectNotLocked(self)
987
super(LockableConfig, self)._write_config_file()
990
class GlobalConfig(LockableConfig):
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):
991
249
"""The configuration that should be used for a specific location."""
251
def get_editor(self):
252
return self._get_user_option('editor')
993
254
def __init__(self):
994
super(GlobalConfig, self).__init__(file_name=bedding.config_path())
1000
def from_string(cls, str_or_unicode, save=False):
1001
"""Create a config object from a string.
1003
:param str_or_unicode: A string representing the file content. This
1004
will be utf-8 encoded.
1006
:param save: Whether the file should be saved upon creation.
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
1009
conf._create_from_string(str_or_unicode, save)
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)
290
if not 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()
1012
347
def set_user_option(self, option, value):
1013
348
"""Save option and its value in the configuration."""
1014
with self.lock_write():
1015
self._set_option(option, value, 'DEFAULT')
1017
def get_aliases(self):
1018
"""Return the aliases section."""
1019
if 'ALIASES' in self._get_parser():
1020
return self._get_parser()['ALIASES']
1024
def set_alias(self, alias_name, alias_command):
1025
"""Save the alias in the configuration."""
1026
with self.lock_write():
1027
self._set_option(alias_name, alias_command, 'ALIASES')
1029
def unset_alias(self, alias_name):
1030
"""Unset an existing alias."""
1031
with self.lock_write():
1033
aliases = self._get_parser().get('ALIASES')
1034
if not aliases or alias_name not in aliases:
1035
raise errors.NoSuchAlias(alias_name)
1036
del aliases[alias_name]
1037
self._write_config_file()
1039
def _set_option(self, option, value, section):
1041
self._get_parser().setdefault(section, {})[option] = value
1042
self._write_config_file()
1043
for hook in OldConfigHooks['set']:
1044
hook(self, option, value)
1046
def _get_sections(self, name=None):
1047
"""See IniBasedConfig._get_sections()."""
1048
parser = self._get_parser()
1049
# We don't give access to options defined outside of any section, we
1050
# used the DEFAULT section by... default.
1051
if name in (None, 'DEFAULT'):
1052
# This could happen for an empty file where the DEFAULT section
1053
# doesn't exist yet. So we force DEFAULT when yielding
1055
if 'DEFAULT' not in parser:
1056
parser['DEFAULT'] = {}
1057
yield (name, parser[name], self.config_id())
1059
def remove_user_option(self, option_name, section_name=None):
1060
if section_name is None:
1061
# We need to force the default section.
1062
section_name = 'DEFAULT'
1063
with self.lock_write():
1064
# We need to avoid the LockableConfig implementation or we'll lock
1066
super(LockableConfig, self).remove_user_option(
1067
option_name, section_name)
1070
def _iter_for_location_by_parts(sections, location):
1071
"""Keep only the sessions matching the specified location.
1073
:param sections: An iterable of section names.
1075
:param location: An url or a local path to match against.
1077
:returns: An iterator of (section, extra_path, nb_parts) where nb is the
1078
number of path components in the section name, section is the section
1079
name and extra_path is the difference between location and the section
1082
``location`` will always be a local path and never a 'file://' url but the
1083
section names themselves can be in either form.
1085
location_parts = location.rstrip('/').split('/')
1087
for section in sections:
1088
# location is a local path if possible, so we need to convert 'file://'
1089
# urls in section names to local paths if necessary.
1091
# This also avoids having file:///path be a more exact
1092
# match than '/path'.
1094
# FIXME: This still raises an issue if a user defines both file:///path
1095
# *and* /path. Should we raise an error in this case -- vila 20110505
1097
if section.startswith('file://'):
1098
section_path = urlutils.local_path_from_url(section)
1100
section_path = section
1101
section_parts = section_path.rstrip('/').split('/')
1104
if len(section_parts) > len(location_parts):
1105
# More path components in the section, they can't match
1108
# Rely on zip truncating in length to the length of the shortest
1109
# argument sequence.
1110
for name in zip(location_parts, section_parts):
1111
if not fnmatch.fnmatch(name[0], name[1]):
1116
# build the path difference between the section and the location
1117
extra_path = '/'.join(location_parts[len(section_parts):])
1118
yield section, extra_path, len(section_parts)
1121
class LocationConfig(LockableConfig):
1122
"""A configuration object that gives the policy for a location."""
1124
def __init__(self, location):
1125
super(LocationConfig, self).__init__(
1126
file_name=bedding.locations_config_path())
1127
# local file locations are looked up by local path, rather than
1128
# by file url. This is because the config file is a user
1129
# file, and we would rather not expose the user to file urls.
1130
if location.startswith('file://'):
1131
location = urlutils.local_path_from_url(location)
1132
self.location = location
1134
def config_id(self):
1138
def from_string(cls, str_or_unicode, location, save=False):
1139
"""Create a config object from a string.
1141
:param str_or_unicode: A string representing the file content. This will
1144
:param location: The location url to filter the configuration.
1146
:param save: Whether the file should be saved upon creation.
1148
conf = cls(location)
1149
conf._create_from_string(str_or_unicode, save)
1152
def _get_matching_sections(self):
1153
"""Return an ordered list of section names matching this location."""
1154
# put the longest (aka more specific) locations first
1156
_iter_for_location_by_parts(self._get_parser(), self.location),
1157
key=lambda match: (match[2], match[0]),
1159
for (section, extra_path, length) in matches:
1160
yield section, extra_path
1161
# should we stop looking for parent configs here?
1163
if self._get_parser()[section].as_bool('ignore_parents'):
1168
def _get_sections(self, name=None):
1169
"""See IniBasedConfig._get_sections()."""
1170
# We ignore the name here as the only sections handled are named with
1171
# the location path and we don't expose embedded sections either.
1172
parser = self._get_parser()
1173
for name, extra_path in self._get_matching_sections():
1174
yield (name, parser[name], self.config_id())
1176
def _get_option_policy(self, section, option_name):
1177
"""Return the policy for the given (section, option_name) pair."""
1178
# check for the old 'recurse=False' flag
1180
recurse = self._get_parser()[section].as_bool('recurse')
1184
return POLICY_NORECURSE
1186
policy_key = option_name + ':policy'
1188
policy_name = self._get_parser()[section][policy_key]
1192
return _policy_value[policy_name]
1194
def _set_option_policy(self, section, option_name, option_policy):
1195
"""Set the policy for the given option name in the given section."""
1196
policy_key = option_name + ':policy'
1197
policy_name = _policy_name[option_policy]
1198
if policy_name is not None:
1199
self._get_parser()[section][policy_key] = policy_name
1201
if policy_key in self._get_parser()[section]:
1202
del self._get_parser()[section][policy_key]
1204
def set_user_option(self, option, value, store=STORE_LOCATION):
1205
"""Save option and its value in the configuration."""
1206
if store not in [STORE_LOCATION,
1207
STORE_LOCATION_NORECURSE,
1208
STORE_LOCATION_APPENDPATH]:
1209
raise ValueError('bad storage policy %r for %r' %
1211
with self.lock_write():
1213
location = self.location
1214
if location.endswith('/'):
1215
location = location[:-1]
1216
parser = self._get_parser()
1217
if location not in parser and not location + '/' in parser:
1218
parser[location] = {}
1219
elif location + '/' in parser:
1220
location = location + '/'
1221
parser[location][option] = value
1222
# the allowed values of store match the config policies
1223
self._set_option_policy(location, option, store)
1224
self._write_config_file()
1225
for hook in OldConfigHooks['set']:
1226
hook(self, option, value)
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()))
353
location = self.location
354
if location.endswith('/'):
355
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():
360
location = location + '/'
361
self._get_parser()[location][option]=value
362
self._get_parser().write()
1229
365
class BranchConfig(Config):
1230
366
"""A configuration object giving the policy for a branch."""
1232
def __init__(self, branch):
1233
super(BranchConfig, self).__init__()
1234
self._location_config = None
1235
self._branch_data_config = None
1236
self._global_config = None
1237
self.branch = branch
1238
self.option_sources = (self._get_location_config,
1239
self._get_branch_data_config,
1240
self._get_global_config)
1242
def config_id(self):
1245
def _get_branch_data_config(self):
1246
if self._branch_data_config is None:
1247
self._branch_data_config = TreeConfig(self.branch)
1248
self._branch_data_config.config_id = self.config_id
1249
return self._branch_data_config
1251
368
def _get_location_config(self):
1252
369
if self._location_config is None:
1253
370
self._location_config = LocationConfig(self.branch.base)
1254
371
return self._location_config
1256
def _get_global_config(self):
1257
if self._global_config is None:
1258
self._global_config = GlobalConfig()
1259
return self._global_config
1261
def _get_best_value(self, option_name):
1262
"""This returns a user option from local, tree or global config.
1264
They are tried in that order. Use get_safe_value if trusted values
1267
for source in self.option_sources:
1268
value = getattr(source(), option_name)()
1269
if value is not None:
1273
def _get_safe_value(self, option_name):
1274
"""This variant of get_best_value never returns untrusted values.
1276
It does not return values from the branch data, because the branch may
1277
not be controlled by the user.
1279
We may wish to allow locations.conf to control whether branches are
1280
trusted in the future.
1282
for source in (self._get_location_config, self._get_global_config):
1283
value = getattr(source(), option_name)()
1284
if value is not None:
1288
373
def _get_user_id(self):
1289
374
"""Return the full user id for the branch.
1291
e.g. "John Hacker <jhacker@example.com>"
376
e.g. "John Hacker <jhacker@foo.org>"
1292
377
This is looked up in the email controlfile for the branch.
1294
return self._get_best_value('_get_user_id')
1296
def _get_change_editor(self):
1297
return self._get_best_value('_get_change_editor')
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()
1299
389
def _get_signature_checking(self):
1300
390
"""See Config._get_signature_checking."""
1301
return self._get_best_value('_get_signature_checking')
1303
def _get_signing_policy(self):
1304
"""See Config._get_signing_policy."""
1305
return self._get_best_value('_get_signing_policy')
391
return self._get_location_config()._get_signature_checking()
1307
393
def _get_user_option(self, option_name):
1308
394
"""See Config._get_user_option."""
1309
for source in self.option_sources:
1310
value = source()._get_user_option(option_name)
1311
if value is not None:
1315
def _get_sections(self, name=None):
1316
"""See IniBasedConfig.get_sections()."""
1317
for source in self.option_sources:
1318
for section in source()._get_sections(name):
1321
def _get_options(self, sections=None):
1322
# First the locations options
1323
for option in self._get_location_config()._get_options():
1325
# Then the branch options
1326
branch_config = self._get_branch_data_config()
1327
if sections is None:
1328
sections = [('DEFAULT', branch_config._get_parser())]
1329
# FIXME: We shouldn't have to duplicate the code in IniBasedConfig but
1330
# Config itself has no notion of sections :( -- vila 20101001
1331
config_id = self.config_id()
1332
for (section_name, section) in sections:
1333
for (name, value) in section.iteritems():
1334
yield (name, value, section_name,
1335
config_id, branch_config._get_parser())
1336
# Then the global options
1337
for option in self._get_global_config()._get_options():
1340
def set_user_option(self, name, value, store=STORE_BRANCH,
1342
if store == STORE_BRANCH:
1343
self._get_branch_data_config().set_option(value, name)
1344
elif store == STORE_GLOBAL:
1345
self._get_global_config().set_user_option(name, value)
1347
self._get_location_config().set_user_option(name, value, store)
1350
if store in (STORE_GLOBAL, STORE_BRANCH):
1351
mask_value = self._get_location_config().get_user_option(name)
1352
if mask_value is not None:
1353
trace.warning('Value "%s" is masked by "%s" from'
1354
' locations.conf', value, mask_value)
1356
if store == STORE_GLOBAL:
1357
branch_config = self._get_branch_data_config()
1358
mask_value = branch_config.get_user_option(name)
1359
if mask_value is not None:
1360
trace.warning('Value "%s" is masked by "%s" from'
1361
' branch.conf', value, mask_value)
1363
def remove_user_option(self, option_name, section_name=None):
1364
self._get_branch_data_config().remove_option(option_name, section_name)
395
return self._get_location_config()._get_user_option(option_name)
397
def _gpg_signing_command(self):
398
"""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
1366
406
def _post_commit(self):
1367
407
"""See Config.post_commit."""
1368
return self._get_safe_value('_post_commit')
1370
def _get_nickname(self):
1371
value = self._get_explicit_nickname()
1372
if value is not None:
1374
if self.branch.name:
1375
return self.branch.name
1376
return urlutils.unescape(self.branch.base.split('/')[-2])
1378
def has_explicit_nickname(self):
1379
"""Return true if a nickname has been explicitly assigned."""
1380
return self._get_explicit_nickname() is not None
1382
def _get_explicit_nickname(self):
1383
return self._get_best_value('_get_nickname')
1385
def _log_format(self):
1386
"""See Config.log_format."""
1387
return self._get_best_value('_log_format')
1389
def _validate_signatures_in_log(self):
1390
"""See Config.validate_signatures_in_log."""
1391
return self._get_best_value('_validate_signatures_in_log')
1393
def _acceptable_keys(self):
1394
"""See Config.acceptable_keys."""
1395
return self._get_best_value('_acceptable_keys')
1398
def parse_username(username):
1399
"""Parse e-mail username and return a (name, address) tuple."""
1400
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1402
return (username, '')
1403
return (match.group(1), match.group(2))
408
return self._get_location_config()._post_commit()
412
"""Return per-user configuration directory.
414
By default this is ~/.bazaar/
416
TODO: Global option --config-dir to override this.
418
base = os.environ.get('BZR_HOME', None)
419
if sys.platform == 'win32':
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")
434
def config_filename():
435
"""Return per-user configuration ini file filename."""
436
return os.path.join(config_dir(), 'bazaar.conf')
439
def branches_config_filename():
440
"""Return per-user configuration ini file filename."""
441
return os.path.join(config_dir(), 'branches.conf')
445
"""Calculate automatic user identification.
447
Returns (realname, email).
449
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
457
# XXX: Any good way to get real user name on win32?
462
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())
1406
480
def extract_email_address(e):
1407
481
"""Return just the address part of an email string.
1409
That is just the user@domain part, nothing else.
483
That is just the user@domain part, nothing else.
1410
484
This part is required to contain only ascii characters.
1411
485
If it can't be extracted, raises an error.
1413
487
>>> extract_email_address('Jane Tester <jane@test.com>')
1416
name, email = parse_username(e)
1418
raise NoEmailInUsername(e)
1422
class TreeConfig(IniBasedConfig):
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):
1423
497
"""Branch configuration data associated with its contents, not location"""
1425
# XXX: Really needs a better name, as this is not part of the tree!
1428
498
def __init__(self, branch):
1429
self._config = branch._get_config()
1430
499
self.branch = branch
1432
def _get_parser(self, file=None):
1433
if file is not None:
1434
return IniBasedConfig._get_parser(file)
1435
return self._config._get_configobj()
501
def _get_config(self):
503
obj = ConfigObj(self.branch.controlfile('branch.conf',
506
except errors.NoSuchFile:
1437
510
def get_option(self, name, section=None, default=None):
1438
with self.branch.lock_read():
1439
return self._config.get_option(name, section, default)
511
self.branch.lock_read()
513
obj = self._get_config()
515
if section is not None:
1441
524
def set_option(self, value, name, section=None):
1442
525
"""Set a per-branch configuration option"""
1443
# FIXME: We shouldn't need to lock explicitly here but rather rely on
1444
# higher levels providing the right lock -- vila 20101004
1445
with self.branch.lock_write():
1446
self._config.set_option(value, name, section)
1448
def remove_option(self, option_name, section_name=None):
1449
# FIXME: We shouldn't need to lock explicitly here but rather rely on
1450
# higher levels providing the right lock -- vila 20101004
1451
with self.branch.lock_write():
1452
self._config.remove_option(option_name, section_name)
1455
_authentication_config_permission_errors = set()
1458
class AuthenticationConfig(object):
1459
"""The authentication configuration file based on a ini file.
1461
Implements the authentication.conf file described in
1462
doc/developers/authentication-ring.txt.
1465
def __init__(self, _file=None):
1466
self._config = None # The ConfigObj
1468
self._input = self._filename = bedding.authentication_config_path()
1469
self._check_permissions()
1471
# Tests can provide a string as _file
1472
self._filename = None
1475
def _get_config(self):
1476
if self._config is not None:
1479
# FIXME: Should we validate something here ? Includes: empty
1480
# sections are useless, at least one of
1481
# user/password/password_encoding should be defined, etc.
1483
# Note: the encoding below declares that the file itself is utf-8
1484
# encoded, but the values in the ConfigObj are always Unicode.
1485
self._config = ConfigObj(self._input, encoding='utf-8')
1486
except configobj.ConfigObjError as e:
1487
raise ParseConfigError(e.errors, e.config.filename)
1488
except UnicodeError:
1489
raise ConfigContentError(self._filename)
1492
def _check_permissions(self):
1493
"""Check permission of auth file are user read/write able only."""
1495
st = os.stat(self._filename)
1496
except OSError as e:
1497
if e.errno != errno.ENOENT:
1498
trace.mutter('Unable to stat %r: %r', self._filename, e)
1500
mode = stat.S_IMODE(st.st_mode)
1501
if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP
1502
| stat.S_IWGRP | stat.S_IRGRP) & mode):
1504
if (self._filename not in _authentication_config_permission_errors and
1505
not GlobalConfig().suppress_warning(
1506
'insecure_permissions')):
1507
trace.warning("The file '%s' has insecure "
1508
"file permissions. Saved passwords may be accessible "
1509
"by other users.", self._filename)
1510
_authentication_config_permission_errors.add(self._filename)
1513
"""Save the config file, only tests should use it for now."""
1514
conf_dir = os.path.dirname(self._filename)
1515
bedding.ensure_config_dir_exists(conf_dir)
1516
fd = os.open(self._filename, os.O_RDWR | os.O_CREAT, 0o600)
1518
f = os.fdopen(fd, 'wb')
1519
self._get_config().write(f)
1523
def _set_option(self, section_name, option_name, value):
1524
"""Set an authentication configuration option"""
1525
conf = self._get_config()
1526
section = conf.get(section_name)
1529
section = conf[section]
1530
section[option_name] = value
1533
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1535
"""Returns the matching credentials from authentication.conf file.
1537
:param scheme: protocol
1539
:param host: the server address
1541
:param port: the associated port (optional)
1543
:param user: login (optional)
1545
:param path: the absolute path on the server (optional)
1547
:param realm: the http authentication realm (optional)
1549
:return: A dict containing the matching credentials or None.
1551
- name: the section name of the credentials in the
1552
authentication.conf file,
1553
- user: can't be different from the provided user if any,
1554
- scheme: the server protocol,
1555
- host: the server address,
1556
- port: the server port (can be None),
1557
- path: the absolute server path (can be None),
1558
- realm: the http specific authentication realm (can be None),
1559
- password: the decoded password, could be None if the credential
1560
defines only the user
1561
- verify_certificates: https specific, True if the server
1562
certificate should be verified, False otherwise.
1565
for auth_def_name, auth_def in self._get_config().iteritems():
1566
if not isinstance(auth_def, configobj.Section):
1567
raise ValueError("%s defined outside a section" %
1570
a_scheme, a_host, a_user, a_path = map(
1571
auth_def.get, ['scheme', 'host', 'user', 'path'])
1574
a_port = auth_def.as_int('port')
1578
raise ValueError("'port' not numeric in %s" % auth_def_name)
1580
a_verify_certificates = auth_def.as_bool('verify_certificates')
1582
a_verify_certificates = True
1585
"'verify_certificates' not boolean in %s" % auth_def_name)
1588
if a_scheme is not None and scheme != a_scheme:
1590
if a_host is not None:
1591
if not (host == a_host or
1592
(a_host.startswith('.') and host.endswith(a_host))):
1594
if a_port is not None and port != a_port:
1596
if (a_path is not None and path is not None and
1597
not path.startswith(a_path)):
1599
if (a_user is not None and user is not None and
1601
# Never contradict the caller about the user to be used
1606
# Prepare a credentials dictionary with additional keys
1607
# for the credential providers
1608
credentials = dict(name=auth_def_name,
1615
password=auth_def.get('password', None),
1616
verify_certificates=a_verify_certificates)
1617
# Decode the password in the credentials (or get one)
1618
self.decode_password(credentials,
1619
auth_def.get('password_encoding', None))
1620
if 'auth' in debug.debug_flags:
1621
trace.mutter("Using authentication section: %r", auth_def_name)
1624
if credentials is None:
1625
# No credentials were found in authentication.conf, try the fallback
1626
# credentials stores.
1627
credentials = credential_store_registry.get_fallback_credentials(
1628
scheme, host, port, user, path, realm)
1632
def set_credentials(self, name, host, user, scheme=None, password=None,
1633
port=None, path=None, verify_certificates=None,
1635
"""Set authentication credentials for a host.
1637
Any existing credentials with matching scheme, host, port and path
1638
will be deleted, regardless of name.
1640
:param name: An arbitrary name to describe this set of credentials.
1641
:param host: Name of the host that accepts these credentials.
1642
:param user: The username portion of these credentials.
1643
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1645
:param password: Password portion of these credentials.
1646
:param port: The IP port on the host that these credentials apply to.
1647
:param path: A filesystem path on the host that these credentials
1649
:param verify_certificates: On https, verify server certificates if
1651
:param realm: The http authentication realm (optional).
1653
values = {'host': host, 'user': user}
1654
if password is not None:
1655
values['password'] = password
1656
if scheme is not None:
1657
values['scheme'] = scheme
1658
if port is not None:
1659
values['port'] = '%d' % port
1660
if path is not None:
1661
values['path'] = path
1662
if verify_certificates is not None:
1663
values['verify_certificates'] = str(verify_certificates)
1664
if realm is not None:
1665
values['realm'] = realm
1666
config = self._get_config()
1667
for section, existing_values in config.iteritems():
1668
for key in ('scheme', 'host', 'port', 'path', 'realm'):
1669
if existing_values.get(key) != values.get(key):
1673
config.update({name: values})
1676
def get_user(self, scheme, host, port=None, realm=None, path=None,
1677
prompt=None, ask=False, default=None):
1678
"""Get a user from authentication file.
1680
:param scheme: protocol
1682
:param host: the server address
1684
:param port: the associated port (optional)
1686
:param realm: the realm sent by the server (optional)
1688
:param path: the absolute path on the server (optional)
1690
:param ask: Ask the user if there is no explicitly configured username
1693
:param default: The username returned if none is defined (optional).
1695
:return: The found user.
1697
credentials = self.get_credentials(scheme, host, port, user=None,
1698
path=path, realm=realm)
1699
if credentials is not None:
1700
user = credentials['user']
1706
# Create a default prompt suitable for most cases
1707
prompt = u'%s' % (scheme.upper(),) + u' %(host)s username'
1708
# Special handling for optional fields in the prompt
1709
if port is not None:
1710
prompt_host = '%s:%d' % (host, port)
1713
user = ui.ui_factory.get_username(prompt, host=prompt_host)
1718
def get_password(self, scheme, host, user, port=None,
1719
realm=None, path=None, prompt=None):
1720
"""Get a password from authentication file or prompt the user for one.
1722
:param scheme: protocol
1724
:param host: the server address
1726
:param port: the associated port (optional)
1730
:param realm: the realm sent by the server (optional)
1732
:param path: the absolute path on the server (optional)
1734
:return: The found password or the one entered by the user.
1736
credentials = self.get_credentials(scheme, host, port, user, path,
1738
if credentials is not None:
1739
password = credentials['password']
1740
if password is not None and scheme == 'ssh':
1741
trace.warning('password ignored in section [%s],'
1742
' use an ssh agent instead'
1743
% credentials['name'])
1747
# Prompt user only if we could't find a password
1748
if password is None:
1750
# Create a default prompt suitable for most cases
1752
scheme.upper() + u' %(user)s@%(host)s password')
1753
# Special handling for optional fields in the prompt
1754
if port is not None:
1755
prompt_host = '%s:%d' % (host, port)
1758
password = ui.ui_factory.get_password(prompt,
1759
host=prompt_host, user=user)
1762
def decode_password(self, credentials, encoding):
1764
cs = credential_store_registry.get_credential_store(encoding)
1766
raise ValueError('%r is not a known password_encoding' % encoding)
1767
credentials['password'] = cs.decode_password(credentials)
1771
class CredentialStoreRegistry(registry.Registry):
1772
"""A class that registers credential stores.
1774
A credential store provides access to credentials via the password_encoding
1775
field in authentication.conf sections.
1777
Except for stores provided by brz itself, most stores are expected to be
1778
provided by plugins that will therefore use
1779
register_lazy(password_encoding, module_name, member_name, help=help,
1780
fallback=fallback) to install themselves.
1782
A fallback credential store is one that is queried if no credentials can be
1783
found via authentication.conf.
1786
def get_credential_store(self, encoding=None):
1787
cs = self.get(encoding)
1792
def is_fallback(self, name):
1793
"""Check if the named credentials store should be used as fallback."""
1794
return self.get_info(name)
1796
def get_fallback_credentials(self, scheme, host, port=None, user=None,
1797
path=None, realm=None):
1798
"""Request credentials from all fallback credentials stores.
1800
The first credentials store that can provide credentials wins.
1803
for name in self.keys():
1804
if not self.is_fallback(name):
1806
cs = self.get_credential_store(name)
1807
credentials = cs.get_credentials(scheme, host, port, user,
1809
if credentials is not None:
1810
# We found some credentials
1814
def register(self, key, obj, help=None, override_existing=False,
1816
"""Register a new object to a name.
1818
:param key: This is the key to use to request the object later.
1819
:param obj: The object to register.
1820
:param help: Help text for this entry. This may be a string or
1821
a callable. If it is a callable, it should take two
1822
parameters (registry, key): this registry and the key that
1823
the help was registered under.
1824
:param override_existing: Raise KeyErorr if False and something has
1825
already been registered for that key. If True, ignore if there
1826
is an existing key (always register the new value).
1827
:param fallback: Whether this credential store should be
1830
return super(CredentialStoreRegistry,
1831
self).register(key, obj, help, info=fallback,
1832
override_existing=override_existing)
1834
def register_lazy(self, key, module_name, member_name,
1835
help=None, override_existing=False,
1837
"""Register a new credential store to be loaded on request.
1839
:param module_name: The python path to the module. Such as 'os.path'.
1840
:param member_name: The member of the module to return. If empty or
1841
None, get() will return the module itself.
1842
:param help: Help text for this entry. This may be a string or
1844
:param override_existing: If True, replace the existing object
1845
with the new one. If False, if there is already something
1846
registered with the same key, raise a KeyError
1847
:param fallback: Whether this credential store should be
1850
return super(CredentialStoreRegistry, self).register_lazy(
1851
key, module_name, member_name, help,
1852
info=fallback, override_existing=override_existing)
1855
credential_store_registry = CredentialStoreRegistry()
1858
class CredentialStore(object):
1859
"""An abstract class to implement storage for credentials"""
1861
def decode_password(self, credentials):
1862
"""Returns a clear text password for the provided credentials."""
1863
raise NotImplementedError(self.decode_password)
1865
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1867
"""Return the matching credentials from this credential store.
1869
This method is only called on fallback credential stores.
1871
raise NotImplementedError(self.get_credentials)
1874
class PlainTextCredentialStore(CredentialStore):
1875
__doc__ = """Plain text credential store for the authentication.conf file"""
1877
def decode_password(self, credentials):
1878
"""See CredentialStore.decode_password."""
1879
return credentials['password']
1882
credential_store_registry.register('plain', PlainTextCredentialStore,
1883
help=PlainTextCredentialStore.__doc__)
1884
credential_store_registry.default_key = 'plain'
1887
class Base64CredentialStore(CredentialStore):
1888
__doc__ = """Base64 credential store for the authentication.conf file"""
1890
def decode_password(self, credentials):
1891
"""See CredentialStore.decode_password."""
1892
# GZ 2012-07-28: Will raise binascii.Error if password is not base64,
1893
# should probably propogate as something more useful.
1894
return base64.standard_b64decode(credentials['password'])
1897
credential_store_registry.register('base64', Base64CredentialStore,
1898
help=Base64CredentialStore.__doc__)
1901
class BzrDirConfig(object):
1903
def __init__(self, bzrdir):
1904
self._bzrdir = bzrdir
1905
self._config = bzrdir._get_config()
1907
def set_default_stack_on(self, value):
1908
"""Set the default stacking location.
1910
It may be set to a location, or None.
1912
This policy affects all branches contained by this control dir, except
1913
for those under repositories.
1915
if self._config is None:
1916
raise errors.BzrError("Cannot set configuration in %s"
1919
self._config.set_option('', 'default_stack_on')
1921
self._config.set_option(value, 'default_stack_on')
1923
def get_default_stack_on(self):
1924
"""Return the default stacking location.
1926
This will either be a location, or None.
1928
This policy affects all branches contained by this control dir, except
1929
for those under repositories.
1931
if self._config is None:
1933
value = self._config.get_option('default_stack_on')
1939
class TransportConfig(object):
1940
"""A Config that reads/writes a config file on a Transport.
1942
It is a low-level object that considers config data to be name/value pairs
1943
that may be associated with a section. Assigning meaning to these values
1944
is done at higher levels like TreeConfig.
1947
def __init__(self, transport, filename):
1948
self._transport = transport
1949
self._filename = filename
1951
def get_option(self, name, section=None, default=None):
1952
"""Return the value associated with a named option.
1954
:param name: The name of the value
1955
:param section: The section the option is in (if any)
1956
:param default: The value to return if the value is not set
1957
:return: The value or default value
1959
configobj = self._get_configobj()
1961
section_obj = configobj
1964
section_obj = configobj[section]
1967
value = section_obj.get(name, default)
1968
for hook in OldConfigHooks['get']:
1969
hook(self, name, value)
1972
def set_option(self, value, name, section=None):
1973
"""Set the value associated with a named option.
1975
:param value: The value to set
1976
:param name: The name of the value to set
1977
:param section: The section the option is in (if any)
1979
configobj = self._get_configobj()
1981
configobj[name] = value
1983
configobj.setdefault(section, {})[name] = value
1984
for hook in OldConfigHooks['set']:
1985
hook(self, name, value)
1986
self._set_configobj(configobj)
1988
def remove_option(self, option_name, section_name=None):
1989
configobj = self._get_configobj()
1990
if section_name is None:
1991
del configobj[option_name]
1993
del configobj[section_name][option_name]
1994
for hook in OldConfigHooks['remove']:
1995
hook(self, option_name)
1996
self._set_configobj(configobj)
1998
def _get_config_file(self):
2000
f = BytesIO(self._transport.get_bytes(self._filename))
2001
for hook in OldConfigHooks['load']:
2004
except errors.NoSuchFile:
2006
except errors.PermissionDenied:
2008
"Permission denied while trying to open "
2009
"configuration file %s.",
2010
urlutils.unescape_for_display(
2011
urlutils.join(self._transport.base, self._filename),
2015
def _external_url(self):
2016
return urlutils.join(self._transport.external_url(), self._filename)
2018
def _get_configobj(self):
2019
f = self._get_config_file()
2022
conf = ConfigObj(f, encoding='utf-8')
2023
except configobj.ConfigObjError as e:
2024
raise ParseConfigError(e.errors, self._external_url())
2025
except UnicodeDecodeError:
2026
raise ConfigContentError(self._external_url())
2031
def _set_configobj(self, configobj):
2032
out_file = BytesIO()
2033
configobj.write(out_file)
2035
self._transport.put_file(self._filename, out_file)
2036
for hook in OldConfigHooks['save']:
2040
class Option(object):
2041
"""An option definition.
2043
The option *values* are stored in config files and found in sections.
2045
Here we define various properties about the option itself, its default
2046
value, how to convert it from stores, what to do when invalid values are
2047
encoutered, in which config files it can be stored.
2050
def __init__(self, name, override_from_env=None,
2051
default=None, default_from_env=None,
2052
help=None, from_unicode=None, invalid=None, unquote=True):
2053
"""Build an option definition.
2055
:param name: the name used to refer to the option.
2057
:param override_from_env: A list of environment variables which can
2058
provide override any configuration setting.
2060
:param default: the default value to use when none exist in the config
2061
stores. This is either a string that ``from_unicode`` will convert
2062
into the proper type, a callable returning a unicode string so that
2063
``from_unicode`` can be used on the return value, or a python
2064
object that can be stringified (so only the empty list is supported
2067
:param default_from_env: A list of environment variables which can
2068
provide a default value. 'default' will be used only if none of the
2069
variables specified here are set in the environment.
2071
:param help: a doc string to explain the option to the user.
2073
:param from_unicode: a callable to convert the unicode string
2074
representing the option value in a store or its default value.
2076
:param invalid: the action to be taken when an invalid value is
2077
encountered in a store. This is called only when from_unicode is
2078
invoked to convert a string and returns None or raise ValueError or
2079
TypeError. Accepted values are: None (ignore invalid values),
2080
'warning' (emit a warning), 'error' (emit an error message and
2083
:param unquote: should the unicode value be unquoted before conversion.
2084
This should be used only when the store providing the values cannot
2085
safely unquote them (see http://pad.lv/906897). It is provided so
2086
daughter classes can handle the quoting themselves.
2088
if override_from_env is None:
2089
override_from_env = []
2090
if default_from_env is None:
2091
default_from_env = []
2093
self.override_from_env = override_from_env
2094
# Convert the default value to a unicode string so all values are
2095
# strings internally before conversion (via from_unicode) is attempted.
2098
elif isinstance(default, list):
2099
# Only the empty list is supported
2101
raise AssertionError(
2102
'Only empty lists are supported as default values')
2104
elif isinstance(default, (bytes, str, bool, int, float)):
2105
# Rely on python to convert strings, booleans and integers
2106
self.default = u'%s' % (default,)
2107
elif callable(default):
2108
self.default = default
2110
# other python objects are not expected
2111
raise AssertionError('%r is not supported as a default value'
2113
self.default_from_env = default_from_env
2115
self.from_unicode = from_unicode
2116
self.unquote = unquote
2117
if invalid and invalid not in ('warning', 'error'):
2118
raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2119
self.invalid = invalid
2125
def convert_from_unicode(self, store, unicode_value):
2126
if self.unquote and store is not None and unicode_value is not None:
2127
unicode_value = store.unquote(unicode_value)
2128
if self.from_unicode is None or unicode_value is None:
2129
# Don't convert or nothing to convert
2130
return unicode_value
2132
converted = self.from_unicode(unicode_value)
2133
except (ValueError, TypeError):
2134
# Invalid values are ignored
2136
if converted is None and self.invalid is not None:
2137
# The conversion failed
2138
if self.invalid == 'warning':
2139
trace.warning('Value "%s" is not valid for "%s"',
2140
unicode_value, self.name)
2141
elif self.invalid == 'error':
2142
raise ConfigOptionValueError(self.name, unicode_value)
2145
def get_override(self):
2147
for var in self.override_from_env:
2149
# If the env variable is defined, its value takes precedence
2150
value = os.environ[var]
2156
def get_default(self):
2158
for var in self.default_from_env:
2160
# If the env variable is defined, its value is the default one
2161
value = os.environ[var]
2166
# Otherwise, fallback to the value defined at registration
2167
if callable(self.default):
2168
value = self.default()
2169
if not isinstance(value, str):
2170
raise AssertionError(
2171
"Callable default value for '%s' should be unicode"
2174
value = self.default
2177
def get_help_topic(self):
2180
def get_help_text(self, additional_see_also=None, plain=True):
2182
from breezy import help_topics
2183
result += help_topics._format_see_also(additional_see_also)
2185
result = help_topics.help_as_plain_text(result)
2189
# Predefined converters to get proper values from store
2191
def bool_from_store(unicode_str):
2192
return ui.bool_from_string(unicode_str)
2195
def int_from_store(unicode_str):
2196
return int(unicode_str)
2199
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2202
def int_SI_from_store(unicode_str):
2203
"""Convert a human readable size in SI units, e.g 10MB into an integer.
2205
Accepted suffixes are K,M,G. It is case-insensitive and may be followed
2206
by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2209
:return Integer, expanded to its base-10 value if a proper SI unit is
2210
found, None otherwise.
2212
regexp = "^(\\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2213
p = re.compile(regexp, re.IGNORECASE)
2214
m = p.match(unicode_str)
2217
val, _, unit = m.groups()
2221
coeff = _unit_suffixes[unit.upper()]
2224
gettext('{0} is not an SI unit.').format(unit))
2229
def float_from_store(unicode_str):
2230
return float(unicode_str)
2233
# Use an empty dict to initialize an empty configobj avoiding all parsing and
2235
_list_converter_config = configobj.ConfigObj(
2236
{}, encoding='utf-8', list_values=True, interpolation=False)
2239
class ListOption(Option):
2241
def __init__(self, name, default=None, default_from_env=None,
2242
help=None, invalid=None):
2243
"""A list Option definition.
2245
This overrides the base class so the conversion from a unicode string
2246
can take quoting into account.
2248
super(ListOption, self).__init__(
2249
name, default=default, default_from_env=default_from_env,
2250
from_unicode=self.from_unicode, help=help,
2251
invalid=invalid, unquote=False)
2253
def from_unicode(self, unicode_str):
2254
if not isinstance(unicode_str, str):
2256
# Now inject our string directly as unicode. All callers got their
2257
# value from configobj, so values that need to be quoted are already
2259
_list_converter_config.reset()
2260
_list_converter_config._parse([u"list=%s" % (unicode_str,)])
2261
maybe_list = _list_converter_config['list']
2262
if isinstance(maybe_list, str):
2264
# A single value, most probably the user forgot (or didn't care
2265
# to add) the final ','
2268
# The empty string, convert to empty list
2271
# We rely on ConfigObj providing us with a list already
2276
class RegistryOption(Option):
2277
"""Option for a choice from a registry."""
2279
def __init__(self, name, registry, default_from_env=None,
2280
help=None, invalid=None):
2281
"""A registry based Option definition.
2283
This overrides the base class so the conversion from a unicode string
2284
can take quoting into account.
2286
super(RegistryOption, self).__init__(
2287
name, default=lambda: registry.default_key,
2288
default_from_env=default_from_env,
2289
from_unicode=self.from_unicode, help=help,
2290
invalid=invalid, unquote=False)
2291
self.registry = registry
2293
def from_unicode(self, unicode_str):
2294
if not isinstance(unicode_str, str):
2297
return self.registry.get(unicode_str)
2300
"Invalid value %s for %s."
2301
"See help for a list of possible values." % (unicode_str,
2306
ret = [self._help, "\n\nThe following values are supported:\n"]
2307
for key in self.registry.keys():
2308
ret.append(" %s - %s\n" % (key, self.registry.get_help(key)))
2312
_option_ref_re = lazy_regex.lazy_compile('({[^\\d\\W](?:\\.\\w|-\\w|\\w)*})')
2313
"""Describes an expandable option reference.
2315
We want to match the most embedded reference first.
2317
I.e. for '{{foo}}' we will get '{foo}',
2318
for '{bar{baz}}' we will get '{baz}'
2322
def iter_option_refs(string):
2323
# Split isolate refs so every other chunk is a ref
2325
for chunk in _option_ref_re.split(string):
2330
class OptionRegistry(registry.Registry):
2331
"""Register config options by their name.
2333
This overrides ``registry.Registry`` to simplify registration by acquiring
2334
some information from the option object itself.
2337
def _check_option_name(self, option_name):
2338
"""Ensures an option name is valid.
2340
:param option_name: The name to validate.
2342
if _option_ref_re.match('{%s}' % option_name) is None:
2343
raise IllegalOptionName(option_name)
2345
def register(self, option):
2346
"""Register a new option to its name.
2348
:param option: The option to register. Its name is used as the key.
2350
self._check_option_name(option.name)
2351
super(OptionRegistry, self).register(option.name, option,
2354
def register_lazy(self, key, module_name, member_name):
2355
"""Register a new option to be loaded on request.
2357
:param key: the key to request the option later. Since the registration
2358
is lazy, it should be provided and match the option name.
2360
:param module_name: the python path to the module. Such as 'os.path'.
2362
:param member_name: the member of the module to return. If empty or
2363
None, get() will return the module itself.
2365
self._check_option_name(key)
2366
super(OptionRegistry, self).register_lazy(key,
2367
module_name, member_name)
2369
def get_help(self, key=None):
2370
"""Get the help text associated with the given key"""
2371
option = self.get(key)
2372
the_help = option.help
2373
if callable(the_help):
2374
return the_help(self, key)
2378
option_registry = OptionRegistry()
2381
# Registered options in lexicographical order
2383
option_registry.register(
2384
Option('append_revisions_only',
2385
default=None, from_unicode=bool_from_store, invalid='warning',
2387
Whether to only append revisions to the mainline.
2389
If this is set to true, then it is not possible to change the
2390
existing mainline of the branch.
2392
option_registry.register(
2393
ListOption('acceptable_keys',
2396
List of GPG key patterns which are acceptable for verification.
2398
option_registry.register(
2399
Option('add.maximum_file_size',
2400
default=u'20MB', from_unicode=int_SI_from_store,
2402
Size above which files should be added manually.
2404
Files below this size are added automatically when using ``bzr add`` without
2407
A negative value means disable the size check.
2409
option_registry.register(
2411
default=None, from_unicode=bool_from_store,
2413
Is the branch bound to ``bound_location``.
2415
If set to "True", the branch should act as a checkout, and push each commit to
2416
the bound_location. This option is normally set by ``bind``/``unbind``.
2418
See also: bound_location.
2420
option_registry.register(
2421
Option('bound_location',
2424
The location that commits should go to when acting as a checkout.
2426
This option is normally set by ``bind``.
2430
option_registry.register(
2431
Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
2433
Whether revisions associated with tags should be fetched.
2435
option_registry.register_lazy(
2436
'transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
2437
option_registry.register(
2438
Option('bzr.workingtree.worth_saving_limit', default=10,
2439
from_unicode=int_from_store, invalid='warning',
2441
How many changes before saving the dirstate.
2443
-1 means that we will never rewrite the dirstate file for only
2444
stat-cache changes. Regardless of this setting, we will always rewrite
2445
the dirstate file if a file is added/removed/renamed/etc. This flag only
2446
affects the behavior of updating the dirstate file after we notice that
2447
a file has been touched.
2449
option_registry.register(
2450
Option('bugtracker', default=None,
2452
Default bug tracker to use.
2454
This bug tracker will be used for example when marking bugs
2455
as fixed using ``bzr commit --fixes``, if no explicit
2456
bug tracker was specified.
2458
option_registry.register(
2459
Option('calculate_revnos', default=True,
2460
from_unicode=bool_from_store,
2462
Calculate revision numbers if they are not known.
2464
Always show revision numbers, even for branch formats that don't store them
2465
natively (such as Git). Calculating the revision number requires traversing
2466
the left hand ancestry of the branch and can be slow on very large branches.
2468
option_registry.register(
2469
Option('check_signatures', default=CHECK_IF_POSSIBLE,
2470
from_unicode=signature_policy_from_unicode,
2472
GPG checking policy.
2474
Possible values: require, ignore, check-available (default)
2476
this option will control whether bzr will require good gpg
2477
signatures, ignore them, or check them if they are
2480
option_registry.register(
2481
Option('child_submit_format',
2482
help='''The preferred format of submissions to this branch.'''))
2483
option_registry.register(
2484
Option('child_submit_to',
2485
help='''Where submissions to this branch are mailed to.'''))
2486
option_registry.register(
2487
Option('create_signatures', default=SIGN_WHEN_REQUIRED,
2488
from_unicode=signing_policy_from_unicode,
2492
Possible values: always, never, when-required (default)
2494
This option controls whether bzr will always create
2495
gpg signatures or not on commits.
2497
option_registry.register(
2498
Option('dirstate.fdatasync', default=True,
2499
from_unicode=bool_from_store,
2501
Flush dirstate changes onto physical disk?
2503
If true (default), working tree metadata changes are flushed through the
2504
OS buffers to physical disk. This is somewhat slower, but means data
2505
should not be lost if the machine crashes. See also repository.fdatasync.
2507
option_registry.register(
2508
ListOption('debug_flags', default=[],
2509
help='Debug flags to activate.'))
2510
option_registry.register(
2511
Option('default_format', default='2a',
2512
help='Format used when creating branches.'))
2513
option_registry.register(
2515
help='The command called to launch an editor to enter a message.'))
2516
option_registry.register(
2517
Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
2518
default=bedding.default_email, help='The users identity'))
2519
option_registry.register(
2520
Option('gpg_signing_key',
2523
GPG key to use for signing.
2525
This defaults to the first key associated with the users email.
2527
option_registry.register(
2529
help='Language to translate messages into.'))
2530
option_registry.register(
2531
Option('locks.steal_dead', default=True, from_unicode=bool_from_store,
2533
Steal locks that appears to be dead.
2535
If set to True, bzr will check if a lock is supposed to be held by an
2536
active process from the same user on the same machine. If the user and
2537
machine match, but no process with the given PID is active, then bzr
2538
will automatically break the stale lock, and create a new lock for
2540
Otherwise, bzr will prompt as normal to break the lock.
2542
option_registry.register(
2543
Option('log_format', default='long',
2545
Log format to use when displaying revisions.
2547
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2548
may be provided by plugins.
2550
option_registry.register_lazy('mail_client', 'breezy.mail_client',
2552
option_registry.register(
2553
Option('output_encoding',
2554
help='Unicode encoding for output'
2555
' (terminal encoding if not specified).'))
2556
option_registry.register(
2557
Option('parent_location',
2560
The location of the default branch for pull or merge.
2562
This option is normally set when creating a branch, the first ``pull`` or by
2563
``pull --remember``.
2565
option_registry.register(
2566
Option('post_commit', default=None,
2568
Post commit functions.
2570
An ordered list of python functions to call, separated by spaces.
2572
Each function takes branch, rev_id as parameters.
2574
option_registry.register_lazy('progress_bar', 'breezy.ui.text',
2576
option_registry.register(
2577
Option('public_branch',
2580
A publically-accessible version of this branch.
2582
This implies that the branch setting this option is not publically-accessible.
2583
Used and set by ``bzr send``.
2585
option_registry.register(
2586
Option('push_location',
2589
The location of the default branch for push.
2591
This option is normally set by the first ``push`` or ``push --remember``.
2593
option_registry.register(
2594
Option('push_strict', default=None,
2595
from_unicode=bool_from_store,
2597
The default value for ``push --strict``.
2599
If present, defines the ``--strict`` option default value for checking
2600
uncommitted changes before sending a merge directive.
2602
option_registry.register(
2603
Option('repository.fdatasync', default=True,
2604
from_unicode=bool_from_store,
2606
Flush repository changes onto physical disk?
2608
If true (default), repository changes are flushed through the OS buffers
2609
to physical disk. This is somewhat slower, but means data should not be
2610
lost if the machine crashes. See also dirstate.fdatasync.
2612
option_registry.register_lazy('smtp_server',
2613
'breezy.smtp_connection', 'smtp_server')
2614
option_registry.register_lazy('smtp_password',
2615
'breezy.smtp_connection', 'smtp_password')
2616
option_registry.register_lazy('smtp_username',
2617
'breezy.smtp_connection', 'smtp_username')
2618
option_registry.register(
2619
Option('selftest.timeout',
2621
from_unicode=int_from_store,
2622
help='Abort selftest if one test takes longer than this many seconds',
2625
option_registry.register(
2626
Option('send_strict', default=None,
2627
from_unicode=bool_from_store,
2629
The default value for ``send --strict``.
2631
If present, defines the ``--strict`` option default value for checking
2632
uncommitted changes before sending a bundle.
2635
option_registry.register(
2636
Option('serve.client_timeout',
2637
default=300.0, from_unicode=float_from_store,
2638
help="If we wait for a new request from a client for more than"
2639
" X seconds, consider the client idle, and hangup."))
2640
option_registry.register(
2642
default=None, override_from_env=['BRZ_SSH'],
2643
help='SSH vendor to use.'))
2644
option_registry.register(
2645
Option('stacked_on_location',
2647
help="""The location where this branch is stacked on."""))
2648
option_registry.register(
2649
Option('submit_branch',
2652
The branch you intend to submit your current work to.
2654
This is automatically set by ``bzr send`` and ``bzr merge``, and is also used
2655
by the ``submit:`` revision spec.
2657
option_registry.register(
2659
help='''Where submissions from this branch are mailed to.'''))
2660
option_registry.register(
2661
ListOption('suppress_warnings',
2663
help="List of warning classes to suppress."))
2664
option_registry.register(
2665
Option('validate_signatures_in_log', default=False,
2666
from_unicode=bool_from_store, invalid='warning',
2667
help='''Whether to validate signatures in brz log.'''))
2668
option_registry.register_lazy('ssl.ca_certs',
2669
'breezy.transport.http', 'opt_ssl_ca_certs')
2671
option_registry.register_lazy('ssl.cert_reqs',
2672
'breezy.transport.http', 'opt_ssl_cert_reqs')
2675
class Section(object):
2676
"""A section defines a dict of option name => value.
2678
This is merely a read-only dict which can add some knowledge about the
2679
options. It is *not* a python dict object though and doesn't try to mimic
2683
def __init__(self, section_id, options):
2684
self.id = section_id
2685
# We re-use the dict-like object received
2686
self.options = options
2688
def get(self, name, default=None, expand=True):
2689
return self.options.get(name, default)
2691
def iter_option_names(self):
2692
for k in self.options.keys():
2696
# Mostly for debugging use
2697
return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
2700
_NewlyCreatedOption = object()
2701
"""Was the option created during the MutableSection lifetime"""
2702
_DeletedOption = object()
2703
"""Was the option deleted during the MutableSection lifetime"""
2706
class MutableSection(Section):
2707
"""A section allowing changes and keeping track of the original values."""
2709
def __init__(self, section_id, options):
2710
super(MutableSection, self).__init__(section_id, options)
2711
self.reset_changes()
2713
def set(self, name, value):
2714
if name not in self.options:
2715
# This is a new option
2716
self.orig[name] = _NewlyCreatedOption
2717
elif name not in self.orig:
2718
self.orig[name] = self.get(name, None)
2719
self.options[name] = value
2721
def remove(self, name):
2722
if name not in self.orig and name in self.options:
2723
self.orig[name] = self.get(name, None)
2724
del self.options[name]
2726
def reset_changes(self):
2729
def apply_changes(self, dirty, store):
2730
"""Apply option value changes.
2732
``self`` has been reloaded from the persistent storage. ``dirty``
2733
contains the changes made since the previous loading.
2735
:param dirty: the mutable section containing the changes.
2737
:param store: the store containing the section
2739
for k, expected in dirty.orig.items():
2740
actual = dirty.get(k, _DeletedOption)
2741
reloaded = self.get(k, _NewlyCreatedOption)
2742
if actual is _DeletedOption:
2743
if k in self.options:
2747
# Report concurrent updates in an ad-hoc way. This should only
2748
# occurs when different processes try to update the same option
2749
# which is not supported (as in: the config framework is not meant
2750
# to be used as a sharing mechanism).
2751
if expected != reloaded:
2752
if actual is _DeletedOption:
2753
actual = '<DELETED>'
2754
if reloaded is _NewlyCreatedOption:
2755
reloaded = '<CREATED>'
2756
if expected is _NewlyCreatedOption:
2757
expected = '<CREATED>'
2758
# Someone changed the value since we get it from the persistent
2760
trace.warning(gettext(
2761
"Option {0} in section {1} of {2} was changed"
2762
" from {3} to {4}. The {5} value will be saved.".format(
2763
k, self.id, store.external_url(), expected,
2765
# No need to keep track of these changes
2766
self.reset_changes()
2769
class Store(object):
2770
"""Abstract interface to persistent storage for configuration options."""
2772
readonly_section_class = Section
2773
mutable_section_class = MutableSection
2776
# Which sections need to be saved (by section id). We use a dict here
2777
# so the dirty sections can be shared by multiple callers.
2778
self.dirty_sections = {}
2780
def is_loaded(self):
2781
"""Returns True if the Store has been loaded.
2783
This is used to implement lazy loading and ensure the persistent
2784
storage is queried only when needed.
2786
raise NotImplementedError(self.is_loaded)
2789
"""Loads the Store from persistent storage."""
2790
raise NotImplementedError(self.load)
2792
def _load_from_string(self, bytes):
2793
"""Create a store from a string in configobj syntax.
2795
:param bytes: A string representing the file content.
2797
raise NotImplementedError(self._load_from_string)
2800
"""Unloads the Store.
2802
This should make is_loaded() return False. This is used when the caller
2803
knows that the persistent storage has changed or may have change since
2806
raise NotImplementedError(self.unload)
2808
def quote(self, value):
2809
"""Quote a configuration option value for storing purposes.
2811
This allows Stacks to present values as they will be stored.
2815
def unquote(self, value):
2816
"""Unquote a configuration option value into unicode.
2818
The received value is quoted as stored.
2823
"""Saves the Store to persistent storage."""
2824
raise NotImplementedError(self.save)
2826
def _need_saving(self):
2827
for s in self.dirty_sections.values():
2829
# At least one dirty section contains a modification
2833
def apply_changes(self, dirty_sections):
2834
"""Apply changes from dirty sections while checking for coherency.
2836
The Store content is discarded and reloaded from persistent storage to
2837
acquire up-to-date values.
2839
Dirty sections are MutableSection which kept track of the value they
2840
are expected to update.
2842
# We need an up-to-date version from the persistent storage, unload the
2843
# store. The reload will occur when needed (triggered by the first
2844
# get_mutable_section() call below.
2846
# Apply the changes from the preserved dirty sections
2847
for section_id, dirty in dirty_sections.items():
2848
clean = self.get_mutable_section(section_id)
2849
clean.apply_changes(dirty, self)
2850
# Everything is clean now
2851
self.dirty_sections = {}
2853
def save_changes(self):
2854
"""Saves the Store to persistent storage if changes occurred.
2856
Apply the changes recorded in the mutable sections to a store content
2857
refreshed from persistent storage.
2859
raise NotImplementedError(self.save_changes)
2861
def external_url(self):
2862
raise NotImplementedError(self.external_url)
2864
def get_sections(self):
2865
"""Returns an ordered iterable of existing sections.
2867
:returns: An iterable of (store, section).
2869
raise NotImplementedError(self.get_sections)
2871
def get_mutable_section(self, section_id=None):
2872
"""Returns the specified mutable section.
2874
:param section_id: The section identifier
2876
raise NotImplementedError(self.get_mutable_section)
2879
# Mostly for debugging use
2880
return "<config.%s(%s)>" % (self.__class__.__name__,
2881
self.external_url())
2884
class CommandLineStore(Store):
2885
"A store to carry command line overrides for the config options."""
2887
def __init__(self, opts=None):
2888
super(CommandLineStore, self).__init__()
2895
# The dict should be cleared but not replaced so it can be shared.
2896
self.options.clear()
2898
def _from_cmdline(self, overrides):
2899
# Reset before accepting new definitions
2901
for over in overrides:
2903
name, value = over.split('=', 1)
2905
raise errors.CommandError(
2906
gettext("Invalid '%s', should be of the form 'name=value'")
2908
self.options[name] = value
2910
def external_url(self):
2911
# Not an url but it makes debugging easier and is never needed
2915
def get_sections(self):
2916
yield self, self.readonly_section_class(None, self.options)
2919
class IniFileStore(Store):
2920
"""A config Store using ConfigObj for storage.
2922
:ivar _config_obj: Private member to hold the ConfigObj instance used to
2923
serialize/deserialize the config file.
2927
"""A config Store using ConfigObj for storage.
2929
super(IniFileStore, self).__init__()
2930
self._config_obj = None
2932
def is_loaded(self):
2933
return self._config_obj is not None
2936
self._config_obj = None
2937
self.dirty_sections = {}
2939
def _load_content(self):
2940
"""Load the config file bytes.
2942
This should be provided by subclasses
2944
:return: Byte string
2946
raise NotImplementedError(self._load_content)
2948
def _save_content(self, content):
2949
"""Save the config file bytes.
2951
This should be provided by subclasses
2953
:param content: Config file bytes to write
2955
raise NotImplementedError(self._save_content)
2958
"""Load the store from the associated file."""
2959
if self.is_loaded():
2961
content = self._load_content()
2962
self._load_from_string(content)
2963
for hook in ConfigHooks['load']:
2966
def _load_from_string(self, bytes):
2967
"""Create a config store from a string.
2969
:param bytes: A string representing the file content.
2971
if self.is_loaded():
2972
raise AssertionError('Already loaded: %r' % (self._config_obj,))
2973
co_input = BytesIO(bytes)
2975
# The config files are always stored utf8-encoded
2976
self._config_obj = ConfigObj(co_input, encoding='utf-8',
2978
except configobj.ConfigObjError as e:
2979
self._config_obj = None
2980
raise ParseConfigError(e.errors, self.external_url())
2981
except UnicodeDecodeError:
2982
raise ConfigContentError(self.external_url())
2984
def save_changes(self):
2985
if not self.is_loaded():
2988
if not self._need_saving():
2990
# Preserve the current version
2991
dirty_sections = self.dirty_sections.copy()
2992
self.apply_changes(dirty_sections)
2993
# Save to the persistent storage
2997
if not self.is_loaded():
3001
self._config_obj.write(out)
3002
self._save_content(out.getvalue())
3003
for hook in ConfigHooks['save']:
3006
def get_sections(self):
3007
"""Get the configobj section in the file order.
3009
:returns: An iterable of (store, section).
3011
# We need a loaded store
3014
except (errors.NoSuchFile, errors.PermissionDenied):
3015
# If the file can't be read, there is no sections
3017
cobj = self._config_obj
3019
yield self, self.readonly_section_class(None, cobj)
3020
for section_name in cobj.sections:
3022
self.readonly_section_class(section_name,
3023
cobj[section_name]))
3025
def get_mutable_section(self, section_id=None):
3026
# We need a loaded store
3029
except errors.NoSuchFile:
3030
# The file doesn't exist, let's pretend it was empty
3031
self._load_from_string(b'')
3032
if section_id in self.dirty_sections:
3033
# We already created a mutable section for this id
3034
return self.dirty_sections[section_id]
3035
if section_id is None:
3036
section = self._config_obj
3038
section = self._config_obj.setdefault(section_id, {})
3039
mutable_section = self.mutable_section_class(section_id, section)
3040
# All mutable sections can become dirty
3041
self.dirty_sections[section_id] = mutable_section
3042
return mutable_section
3044
def quote(self, value):
3046
# configobj conflates automagical list values and quoting
3047
self._config_obj.list_values = True
3048
return self._config_obj._quote(value)
3050
self._config_obj.list_values = False
3052
def unquote(self, value):
3053
if value and isinstance(value, str):
3054
# _unquote doesn't handle None nor empty strings nor anything that
3055
# is not a string, really.
3056
value = self._config_obj._unquote(value)
3059
def external_url(self):
3060
# Since an IniFileStore can be used without a file (at least in tests),
3061
# it's better to provide something than raising a NotImplementedError.
3062
# All daughter classes are supposed to provide an implementation
3064
return 'In-Process Store, no URL'
3067
class TransportIniFileStore(IniFileStore):
3068
"""IniFileStore that loads files from a transport.
3070
:ivar transport: The transport object where the config file is located.
3072
:ivar file_name: The config file basename in the transport directory.
3075
def __init__(self, transport, file_name):
3076
"""A Store using a ini file on a Transport
3078
:param transport: The transport object where the config file is located.
3079
:param file_name: The config file basename in the transport directory.
3081
super(TransportIniFileStore, self).__init__()
3082
self.transport = transport
3083
self.file_name = file_name
3085
def _load_content(self):
3087
return self.transport.get_bytes(self.file_name)
3088
except errors.PermissionDenied:
3089
trace.warning("Permission denied while trying to load "
3090
"configuration store %s.", self.external_url())
3093
def _save_content(self, content):
3094
self.transport.put_bytes(self.file_name, content)
3096
def external_url(self):
3097
# FIXME: external_url should really accepts an optional relpath
3098
# parameter (bug #750169) :-/ -- vila 2011-04-04
3099
# The following will do in the interim but maybe we don't want to
3100
# expose a path here but rather a config ID and its associated
3101
# object </hand wawe>.
3102
return urlutils.join(
3103
self.transport.external_url(), urlutils.escape(self.file_name))
3106
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
3107
# unlockable stores for use with objects that can already ensure the locking
3108
# (think branches). If different stores (not based on ConfigObj) are created,
3109
# they may face the same issue.
3112
class LockableIniFileStore(TransportIniFileStore):
3113
"""A ConfigObjStore using locks on save to ensure store integrity."""
3115
def __init__(self, transport, file_name, lock_dir_name=None):
3116
"""A config Store using ConfigObj for storage.
3118
:param transport: The transport object where the config file is located.
3120
:param file_name: The config file basename in the transport directory.
3122
if lock_dir_name is None:
3123
lock_dir_name = 'lock'
3124
self.lock_dir_name = lock_dir_name
3125
super(LockableIniFileStore, self).__init__(transport, file_name)
3126
self._lock = lockdir.LockDir(self.transport, self.lock_dir_name)
3128
def lock_write(self, token=None):
3129
"""Takes a write lock in the directory containing the config file.
3131
If the directory doesn't exist it is created.
3133
# FIXME: This doesn't check the ownership of the created directories as
3134
# ensure_config_dir_exists does. It should if the transport is local
3135
# -- vila 2011-04-06
3136
self.transport.create_prefix()
3137
token = self._lock.lock_write(token)
3138
return lock.LogicalLockResult(self.unlock, token)
3143
def break_lock(self):
3144
self._lock.break_lock()
3147
with self.lock_write():
3148
# We need to be able to override the undecorated implementation
3149
self.save_without_locking()
3151
def save_without_locking(self):
3152
super(LockableIniFileStore, self).save()
3155
# FIXME: global, breezy, shouldn't that be 'user' instead or even
3156
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
3157
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
3159
# FIXME: Moreover, we shouldn't need classes for these stores either, factory
3160
# functions or a registry will make it easier and clearer for tests, focusing
3161
# on the relevant parts of the API that needs testing -- vila 20110503 (based
3162
# on a poolie's remark)
3163
class GlobalStore(LockableIniFileStore):
3164
"""A config store for global options.
3166
There is a single GlobalStore for a given process.
3169
def __init__(self, possible_transports=None):
3170
path, kind = bedding._config_dir()
3171
t = transport.get_transport_from_path(
3172
path, possible_transports=possible_transports)
3173
super(GlobalStore, self).__init__(t, kind + '.conf')
3177
class LocationStore(LockableIniFileStore):
3178
"""A config store for options specific to a location.
3180
There is a single LocationStore for a given process.
3183
def __init__(self, possible_transports=None):
3184
t = transport.get_transport_from_path(
3185
bedding.config_dir(), possible_transports=possible_transports)
3186
super(LocationStore, self).__init__(t, 'locations.conf')
3187
self.id = 'locations'
3190
class BranchStore(TransportIniFileStore):
3191
"""A config store for branch options.
3193
There is a single BranchStore for a given branch.
3196
def __init__(self, branch):
3197
super(BranchStore, self).__init__(branch.control_transport,
3199
self.branch = branch
3203
class ControlStore(LockableIniFileStore):
3205
def __init__(self, bzrdir):
3206
super(ControlStore, self).__init__(bzrdir.transport,
3208
lock_dir_name='branch_lock')
3212
class SectionMatcher(object):
3213
"""Select sections into a given Store.
3215
This is intended to be used to postpone getting an iterable of sections
3219
def __init__(self, store):
3222
def get_sections(self):
3223
# This is where we require loading the store so we can see all defined
3225
sections = self.store.get_sections()
3226
# Walk the revisions in the order provided
3227
for store, s in sections:
3231
def match(self, section):
3232
"""Does the proposed section match.
3234
:param section: A Section object.
3236
:returns: True if the section matches, False otherwise.
3238
raise NotImplementedError(self.match)
3241
class NameMatcher(SectionMatcher):
3243
def __init__(self, store, section_id):
3244
super(NameMatcher, self).__init__(store)
3245
self.section_id = section_id
3247
def match(self, section):
3248
return section.id == self.section_id
3251
class LocationSection(Section):
3253
def __init__(self, section, extra_path, branch_name=None):
3254
super(LocationSection, self).__init__(section.id, section.options)
3255
self.extra_path = extra_path
3256
if branch_name is None:
3258
self.locals = {'relpath': extra_path,
3259
'basename': urlutils.basename(extra_path),
3260
'branchname': branch_name}
3262
def get(self, name, default=None, expand=True):
3263
value = super(LocationSection, self).get(name, default)
3264
if value is not None and expand:
3265
policy_name = self.get(name + ':policy', None)
3266
policy = _policy_value.get(policy_name, POLICY_NONE)
3267
if policy == POLICY_APPENDPATH:
3268
value = urlutils.join(value, self.extra_path)
3269
# expand section local options right now (since POLICY_APPENDPATH
3270
# will never add options references, it's ok to expand after it).
3272
for is_ref, chunk in iter_option_refs(value):
3274
chunks.append(chunk)
3277
if ref in self.locals:
3278
chunks.append(self.locals[ref])
3280
chunks.append(chunk)
3281
value = ''.join(chunks)
3285
class StartingPathMatcher(SectionMatcher):
3286
"""Select sections for a given location respecting the Store order."""
3288
# FIXME: Both local paths and urls can be used for section names as well as
3289
# ``location`` to stay consistent with ``LocationMatcher`` which itself
3290
# inherited the fuzziness from the previous ``LocationConfig``
3291
# implementation. We probably need to revisit which encoding is allowed for
3292
# both ``location`` and section names and how we normalize
3293
# them. http://pad.lv/85479, http://pad.lv/437009 and http://359320 are
3294
# related too. -- vila 2012-01-04
3296
def __init__(self, store, location):
3297
super(StartingPathMatcher, self).__init__(store)
3298
if location.startswith('file://'):
3299
location = urlutils.local_path_from_url(location)
3300
self.location = location
3302
def get_sections(self):
3303
"""Get all sections matching ``location`` in the store.
3305
The most generic sections are described first in the store, then more
3306
specific ones can be provided for reduced scopes.
3308
The returned section are therefore returned in the reversed order so
3309
the most specific ones can be found first.
3311
location_parts = self.location.rstrip('/').split('/')
3313
# Later sections are more specific, they should be returned first
3314
for _, section in reversed(list(store.get_sections())):
3315
if section.id is None:
3316
# The no-name section is always included if present
3317
yield store, LocationSection(section, self.location)
3319
section_path = section.id
3320
if section_path.startswith('file://'):
3321
# the location is already a local path or URL, convert the
3322
# section id to the same format
3323
section_path = urlutils.local_path_from_url(section_path)
3324
if (self.location.startswith(section_path) or
3325
fnmatch.fnmatch(self.location, section_path)):
3326
section_parts = section_path.rstrip('/').split('/')
3327
extra_path = '/'.join(location_parts[len(section_parts):])
3328
yield store, LocationSection(section, extra_path)
3331
class LocationMatcher(SectionMatcher):
3333
def __init__(self, store, location):
3334
super(LocationMatcher, self).__init__(store)
3335
url, params = urlutils.split_segment_parameters(location)
3336
if location.startswith('file://'):
3337
location = urlutils.local_path_from_url(location)
3338
self.location = location
3339
branch_name = params.get('branch')
3340
if branch_name is None:
3341
self.branch_name = urlutils.basename(self.location)
3343
self.branch_name = urlutils.unescape(branch_name)
3345
def _get_matching_sections(self):
3346
"""Get all sections matching ``location``."""
3347
# We slightly diverge from LocalConfig here by allowing the no-name
3348
# section as the most generic one and the lower priority.
3349
no_name_section = None
3351
# Filter out the no_name_section so _iter_for_location_by_parts can be
3352
# used (it assumes all sections have a name).
3353
for _, section in self.store.get_sections():
3354
if section.id is None:
3355
no_name_section = section
3357
all_sections.append(section)
3358
# Unfortunately _iter_for_location_by_parts deals with section names so
3359
# we have to resync.
3360
filtered_sections = _iter_for_location_by_parts(
3361
[s.id for s in all_sections], self.location)
3362
iter_all_sections = iter(all_sections)
3363
matching_sections = []
3364
if no_name_section is not None:
3365
matching_sections.append(
3366
(0, LocationSection(no_name_section, self.location)))
3367
for section_id, extra_path, length in filtered_sections:
3368
# a section id is unique for a given store so it's safe to take the
3369
# first matching section while iterating. Also, all filtered
3370
# sections are part of 'all_sections' and will always be found
3373
section = next(iter_all_sections)
3374
if section_id == section.id:
3375
section = LocationSection(section, extra_path,
3377
matching_sections.append((length, section))
3379
return matching_sections
3381
def get_sections(self):
3382
# Override the default implementation as we want to change the order
3383
# We want the longest (aka more specific) locations first
3384
sections = sorted(self._get_matching_sections(),
3385
key=lambda match: (match[0], match[1].id),
3387
# Sections mentioning 'ignore_parents' restrict the selection
3388
for _, section in sections:
3389
# FIXME: We really want to use as_bool below -- vila 2011-04-07
3390
ignore = section.get('ignore_parents', None)
3391
if ignore is not None:
3392
ignore = ui.bool_from_string(ignore)
3395
# Finally, we have a valid section
3396
yield self.store, section
3399
# FIXME: _shared_stores should be an attribute of a library state once a
3400
# library_state object is always available.
3402
_shared_stores_at_exit_installed = False
3405
class Stack(object):
3406
"""A stack of configurations where an option can be defined"""
3408
def __init__(self, sections_def, store=None, mutable_section_id=None):
3409
"""Creates a stack of sections with an optional store for changes.
3411
:param sections_def: A list of Section or callables that returns an
3412
iterable of Section. This defines the Sections for the Stack and
3413
can be called repeatedly if needed.
3415
:param store: The optional Store where modifications will be
3416
recorded. If none is specified, no modifications can be done.
3418
:param mutable_section_id: The id of the MutableSection where changes
3419
are recorded. This requires the ``store`` parameter to be
3422
self.sections_def = sections_def
3424
self.mutable_section_id = mutable_section_id
3426
def iter_sections(self):
3427
"""Iterate all the defined sections."""
3428
# Ensuring lazy loading is achieved by delaying section matching (which
3429
# implies querying the persistent storage) until it can't be avoided
3430
# anymore by using callables to describe (possibly empty) section
3432
for sections in self.sections_def:
3433
for store, section in sections():
3434
yield store, section
3436
def get(self, name, expand=True, convert=True):
3437
"""Return the *first* option value found in the sections.
3439
This is where we guarantee that sections coming from Store are loaded
3440
lazily: the loading is delayed until we need to either check that an
3441
option exists or get its value, which in turn may require to discover
3442
in which sections it can be defined. Both of these (section and option
3443
existence) require loading the store (even partially).
3445
:param name: The queried option.
3447
:param expand: Whether options references should be expanded.
3449
:param convert: Whether the option value should be converted from
3450
unicode (do nothing for non-registered options).
3452
:returns: The value of the option.
3454
# FIXME: No caching of options nor sections yet -- vila 20110503
3456
found_store = None # Where the option value has been found
3457
# If the option is registered, it may provide additional info about
3460
opt = option_registry.get(name)
3465
def expand_and_convert(val):
3466
# This may need to be called in different contexts if the value is
3467
# None or ends up being None during expansion or conversion.
3470
if isinstance(val, str):
3471
val = self._expand_options_in_string(val)
3473
trace.warning('Cannot expand "%s":'
3474
' %s does not support option expansion'
3475
% (name, type(val)))
3477
val = found_store.unquote(val)
3479
val = opt.convert_from_unicode(found_store, val)
3482
# First of all, check if the environment can override the configuration
3484
if opt is not None and opt.override_from_env:
3485
value = opt.get_override()
3486
value = expand_and_convert(value)
3488
for store, section in self.iter_sections():
3489
value = section.get(name)
3490
if value is not None:
3493
value = expand_and_convert(value)
3494
if opt is not None and value is None:
3495
# If the option is registered, it may provide a default value
3496
value = opt.get_default()
3497
value = expand_and_convert(value)
3498
for hook in ConfigHooks['get']:
3499
hook(self, name, value)
3502
def expand_options(self, string, env=None):
3503
"""Expand option references in the string in the configuration context.
3505
:param string: The string containing option(s) to expand.
3507
:param env: An option dict defining additional configuration options or
3508
overriding existing ones.
3510
:returns: The expanded string.
3512
return self._expand_options_in_string(string, env)
3514
def _expand_options_in_string(self, string, env=None, _refs=None):
3515
"""Expand options in the string in the configuration context.
3517
:param string: The string to be expanded.
3519
:param env: An option dict defining additional configuration options or
3520
overriding existing ones.
3522
:param _refs: Private list (FIFO) containing the options being expanded
3525
:returns: The expanded string.
3528
# Not much to expand there
3531
# What references are currently resolved (to detect loops)
3534
# We need to iterate until no more refs appear ({{foo}} will need two
3535
# iterations for example).
3540
for is_ref, chunk in iter_option_refs(result):
3542
chunks.append(chunk)
3547
raise OptionExpansionLoop(string, _refs)
3549
value = self._expand_option(name, env, _refs)
3551
raise ExpandingUnknownOption(name, string)
3552
chunks.append(value)
3554
result = ''.join(chunks)
3557
def _expand_option(self, name, env, _refs):
3558
if env is not None and name in env:
3559
# Special case, values provided in env takes precedence over
3563
value = self.get(name, expand=False, convert=False)
3564
value = self._expand_options_in_string(value, env, _refs)
3567
def _get_mutable_section(self):
3568
"""Get the MutableSection for the Stack.
3570
This is where we guarantee that the mutable section is lazily loaded:
3571
this means we won't load the corresponding store before setting a value
3572
or deleting an option. In practice the store will often be loaded but
3573
this helps catching some programming errors.
3576
section = store.get_mutable_section(self.mutable_section_id)
3577
return store, section
3579
def set(self, name, value):
3580
"""Set a new value for the option."""
3581
store, section = self._get_mutable_section()
3582
section.set(name, store.quote(value))
3583
for hook in ConfigHooks['set']:
3584
hook(self, name, value)
3586
def remove(self, name):
3587
"""Remove an existing option."""
3588
_, section = self._get_mutable_section()
3589
section.remove(name)
3590
for hook in ConfigHooks['remove']:
3594
# Mostly for debugging use
3595
return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3597
def _get_overrides(self):
3598
if breezy._global_state is not None:
3599
# TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3600
return breezy._global_state.cmdline_overrides.get_sections()
3603
def get_shared_store(self, store, state=None):
3604
"""Get a known shared store.
3606
Store urls uniquely identify them and are used to ensure a single copy
3607
is shared across all users.
3609
:param store: The store known to the caller.
3611
:param state: The library state where the known stores are kept.
3613
:returns: The store received if it's not a known one, an already known
3617
# TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3618
state = breezy._global_state
3620
global _shared_stores_at_exit_installed
3621
stores = _shared_stores
3623
def save_config_changes():
3624
for k, store in stores.items():
3625
store.save_changes()
3626
if not _shared_stores_at_exit_installed:
3627
# FIXME: Ugly hack waiting for library_state to always be
3628
# available. -- vila 20120731
3630
atexit.register(save_config_changes)
3631
_shared_stores_at_exit_installed = True
3633
stores = state.config_stores
3634
url = store.external_url()
3642
class MemoryStack(Stack):
3643
"""A configuration stack defined from a string.
3645
This is mainly intended for tests and requires no disk resources.
3648
def __init__(self, content=None):
3649
"""Create an in-memory stack from a given content.
3651
It uses a single store based on configobj and support reading and
3654
:param content: The initial content of the store. If None, the store is
3655
not loaded and ``_load_from_string`` can and should be used if
3658
store = IniFileStore()
3659
if content is not None:
3660
store._load_from_string(content)
3661
super(MemoryStack, self).__init__(
3662
[store.get_sections], store)
3665
class _CompatibleStack(Stack):
3666
"""Place holder for compatibility with previous design.
3668
This is intended to ease the transition from the Config-based design to the
3669
Stack-based design and should not be used nor relied upon by plugins.
3671
One assumption made here is that the daughter classes will all use Stores
3672
derived from LockableIniFileStore).
3674
It implements set() and remove () by re-loading the store before applying
3675
the modification and saving it.
3677
The long term plan being to implement a single write by store to save
3678
all modifications, this class should not be used in the interim.
3681
def set(self, name, value):
3684
super(_CompatibleStack, self).set(name, value)
3685
# Force a write to persistent storage
3688
def remove(self, name):
3691
super(_CompatibleStack, self).remove(name)
3692
# Force a write to persistent storage
3696
class GlobalStack(Stack):
3697
"""Global options only stack.
3699
The following sections are queried:
3701
* command-line overrides,
3703
* the 'DEFAULT' section in bazaar.conf
3705
This stack will use the ``DEFAULT`` section in bazaar.conf as its
3710
gstore = self.get_shared_store(GlobalStore())
3711
super(GlobalStack, self).__init__(
3712
[self._get_overrides,
3713
NameMatcher(gstore, 'DEFAULT').get_sections],
3714
gstore, mutable_section_id='DEFAULT')
3717
class LocationStack(Stack):
3718
"""Per-location options falling back to global options stack.
3721
The following sections are queried:
3723
* command-line overrides,
3725
* the sections matching ``location`` in ``locations.conf``, the order being
3726
defined by the number of path components in the section glob, higher
3727
numbers first (from most specific section to most generic).
3729
* the 'DEFAULT' section in bazaar.conf
3731
This stack will use the ``location`` section in locations.conf as its
3735
def __init__(self, location):
3736
"""Make a new stack for a location and global configuration.
3738
:param location: A URL prefix to """
3739
lstore = self.get_shared_store(LocationStore())
3740
if location.startswith('file://'):
3741
location = urlutils.local_path_from_url(location)
3742
gstore = self.get_shared_store(GlobalStore())
3743
super(LocationStack, self).__init__(
3744
[self._get_overrides,
3745
LocationMatcher(lstore, location).get_sections,
3746
NameMatcher(gstore, 'DEFAULT').get_sections],
3747
lstore, mutable_section_id=location)
3750
class BranchStack(Stack):
3751
"""Per-location options falling back to branch then global options stack.
3753
The following sections are queried:
3755
* command-line overrides,
3757
* the sections matching ``location`` in ``locations.conf``, the order being
3758
defined by the number of path components in the section glob, higher
3759
numbers first (from most specific section to most generic),
3761
* the no-name section in branch.conf,
3763
* the ``DEFAULT`` section in ``bazaar.conf``.
3765
This stack will use the no-name section in ``branch.conf`` as its
3769
def __init__(self, branch):
3770
lstore = self.get_shared_store(LocationStore())
3771
bstore = branch._get_config_store()
3772
gstore = self.get_shared_store(GlobalStore())
3773
super(BranchStack, self).__init__(
3774
[self._get_overrides,
3775
LocationMatcher(lstore, branch.base).get_sections,
3776
NameMatcher(bstore, None).get_sections,
3777
NameMatcher(gstore, 'DEFAULT').get_sections],
3779
self.branch = branch
3781
def lock_write(self, token=None):
3782
return self.branch.lock_write(token)
3785
return self.branch.unlock()
3787
def set(self, name, value):
3788
with self.lock_write():
3789
super(BranchStack, self).set(name, value)
3790
# Unlocking the branch will trigger a store.save_changes() so the
3791
# last unlock saves all the changes.
3793
def remove(self, name):
3794
with self.lock_write():
3795
super(BranchStack, self).remove(name)
3796
# Unlocking the branch will trigger a store.save_changes() so the
3797
# last unlock saves all the changes.
3800
class RemoteControlStack(Stack):
3801
"""Remote control-only options stack."""
3803
# FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
3804
# with the stack used for remote bzr dirs. RemoteControlStack only uses
3805
# control.conf and is used only for stack options.
3807
def __init__(self, bzrdir):
3808
cstore = bzrdir._get_config_store()
3809
super(RemoteControlStack, self).__init__(
3810
[NameMatcher(cstore, None).get_sections],
3812
self.controldir = bzrdir
3815
class BranchOnlyStack(Stack):
3816
"""Branch-only options stack."""
3818
# FIXME: _BranchOnlyStack only uses branch.conf and is used only for the
3819
# stacked_on_location options waiting for http://pad.lv/832042 to be fixed.
3820
# -- vila 2011-12-16
3822
def __init__(self, branch):
3823
bstore = branch._get_config_store()
3824
super(BranchOnlyStack, self).__init__(
3825
[NameMatcher(bstore, None).get_sections],
3827
self.branch = branch
3829
def lock_write(self, token=None):
3830
return self.branch.lock_write(token)
3833
return self.branch.unlock()
3835
def set(self, name, value):
3836
with self.lock_write():
3837
super(BranchOnlyStack, self).set(name, value)
3838
# Force a write to persistent storage
3839
self.store.save_changes()
3841
def remove(self, name):
3842
with self.lock_write():
3843
super(BranchOnlyStack, self).remove(name)
3844
# Force a write to persistent storage
3845
self.store.save_changes()
3848
class cmd_config(commands.Command):
3849
__doc__ = """Display, set or remove a configuration option.
3851
Display the active value for option NAME.
3853
If --all is specified, NAME is interpreted as a regular expression and all
3854
matching options are displayed mentioning their scope and without resolving
3855
option references in the value). The active value that bzr will take into
3856
account is the first one displayed for each option.
3858
If NAME is not given, --all .* is implied (all options are displayed for the
3861
Setting a value is achieved by using NAME=value without spaces. The value
3862
is set in the most relevant scope and can be checked by displaying the
3865
Removing a value is achieved by using --remove NAME.
3868
takes_args = ['name?']
3872
# FIXME: This should be a registry option so that plugins can register
3873
# their own config files (or not) and will also address
3874
# http://pad.lv/788991 -- vila 20101115
3875
commands.Option('scope', help='Reduce the scope to the specified'
3876
' configuration file.',
3878
commands.Option('all',
3879
help='Display all the defined values for the matching options.',
3881
commands.Option('remove', help='Remove the option from'
3882
' the configuration file.'),
3885
_see_also = ['configuration']
3887
@commands.display_command
3888
def run(self, name=None, all=False, directory=None, scope=None,
3890
if directory is None:
3892
directory = directory_service.directories.dereference(directory)
3893
directory = urlutils.normalize_url(directory)
3895
raise errors.BzrError(
3896
'--all and --remove are mutually exclusive.')
3898
# Delete the option in the given scope
3899
self._remove_config_option(name, directory, scope)
3901
# Defaults to all options
3902
self._show_matching_options('.*', directory, scope)
3905
name, value = name.split('=', 1)
3907
# Display the option(s) value(s)
3909
self._show_matching_options(name, directory, scope)
3911
self._show_value(name, directory, scope)
3914
raise errors.BzrError(
3915
'Only one option can be set.')
3916
# Set the option value
3917
self._set_config_option(name, value, directory, scope)
3919
def _get_stack(self, directory, scope=None, write_access=False):
3920
"""Get the configuration stack specified by ``directory`` and ``scope``.
3922
:param directory: Where the configurations are derived from.
3924
:param scope: A specific config to start from.
3926
:param write_access: Whether a write access to the stack will be
3929
# FIXME: scope should allow access to plugin-specific stacks (even
3930
# reduced to the plugin-specific store), related to
3931
# http://pad.lv/788991 -- vila 2011-11-15
3932
if scope is not None:
3933
if scope == 'breezy':
3934
return GlobalStack()
3935
elif scope == 'locations':
3936
return LocationStack(directory)
3937
elif scope == 'branch':
3939
controldir.ControlDir.open_containing_tree_or_branch(
3942
self.add_cleanup(br.lock_write().unlock)
3943
return br.get_config_stack()
3944
raise NoSuchConfig(scope)
3948
controldir.ControlDir.open_containing_tree_or_branch(
3951
self.add_cleanup(br.lock_write().unlock)
3952
return br.get_config_stack()
3953
except errors.NotBranchError:
3954
return LocationStack(directory)
3956
def _quote_multiline(self, value):
3958
value = '"""' + value + '"""'
3961
def _show_value(self, name, directory, scope):
3962
conf = self._get_stack(directory, scope)
3963
value = conf.get(name, expand=True, convert=False)
3964
if value is not None:
3965
# Quote the value appropriately
3966
value = self._quote_multiline(value)
3967
self.outf.write('%s\n' % (value,))
3969
raise NoSuchConfigOption(name)
3971
def _show_matching_options(self, name, directory, scope):
3972
name = lazy_regex.lazy_compile(name)
3973
# We want any error in the regexp to be raised *now* so we need to
3974
# avoid the delay introduced by the lazy regexp. But, we still do
3975
# want the nicer errors raised by lazy_regex.
3976
name._compile_and_collapse()
3979
conf = self._get_stack(directory, scope)
3980
for store, section in conf.iter_sections():
3981
for oname in section.iter_option_names():
3982
if name.search(oname):
3983
if cur_store_id != store.id:
3984
# Explain where the options are defined
3985
self.outf.write('%s:\n' % (store.id,))
3986
cur_store_id = store.id
3988
if (section.id is not None and cur_section != section.id):
3989
# Display the section id as it appears in the store
3990
# (None doesn't appear by definition)
3991
self.outf.write(' [%s]\n' % (section.id,))
3992
cur_section = section.id
3993
value = section.get(oname, expand=False)
3994
# Quote the value appropriately
3995
value = self._quote_multiline(value)
3996
self.outf.write(' %s = %s\n' % (oname, value))
3998
def _set_config_option(self, name, value, directory, scope):
3999
conf = self._get_stack(directory, scope, write_access=True)
4000
conf.set(name, value)
4001
# Explicitly save the changes
4002
conf.store.save_changes()
4004
def _remove_config_option(self, name, directory, scope):
4006
raise errors.CommandError(
4007
'--remove expects an option to remove.')
4008
conf = self._get_stack(directory, scope, write_access=True)
4011
# Explicitly save the changes
4012
conf.store.save_changes()
4014
raise NoSuchConfigOption(name)
4019
# We need adapters that can build a Store or a Stack in a test context. Test
4020
# classes, based on TestCaseWithTransport, can use the registry to parametrize
4021
# themselves. The builder will receive a test instance and should return a
4022
# ready-to-use store or stack. Plugins that define new store/stacks can also
4023
# register themselves here to be tested against the tests defined in
4024
# breezy.tests.test_config. Note that the builder can be called multiple times
4025
# for the same test.
4027
# The registered object should be a callable receiving a test instance
4028
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Store
4030
test_store_builder_registry = registry.Registry()
4032
# The registered object should be a callable receiving a test instance
4033
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Stack
4035
test_stack_builder_registry = registry.Registry()
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)