952
951
If several processes try to write the config file, the accesses need to be
955
Daughter classes should decorate all methods that update a config with the
956
``@needs_write_lock`` decorator (they call, directly or indirectly, the
954
Daughter classes should use the self.lock_write() decorator method when they
955
upate a config (they call, directly or indirectly, the
957
956
``_write_config_file()`` method. These methods (typically ``set_option()``
958
957
and variants must reload the config file from disk before calling
959
958
``_write_config_file()``), this can be achieved by calling the
1008
1007
def break_lock(self):
1009
1008
self._lock.break_lock()
1012
1010
def remove_user_option(self, option_name, section_name=None):
1013
super(LockableConfig, self).remove_user_option(option_name,
1011
with self.lock_write():
1012
super(LockableConfig, self).remove_user_option(
1013
option_name, section_name)
1016
1015
def _write_config_file(self):
1017
1016
if self._lock is None or not self._lock.is_held:
1018
1017
# NB: if the following exception is raised it probably means a
1019
# missing @needs_write_lock decorator on one of the callers.
1018
# missing call to lock_write() by one of the callers.
1020
1019
raise errors.ObjectNotLocked(self)
1021
1020
super(LockableConfig, self)._write_config_file()
1043
1042
conf._create_from_string(str_or_unicode, save)
1047
1045
def set_user_option(self, option, value):
1048
1046
"""Save option and its value in the configuration."""
1049
self._set_option(option, value, 'DEFAULT')
1047
with self.lock_write():
1048
self._set_option(option, value, 'DEFAULT')
1051
1050
def get_aliases(self):
1052
1051
"""Return the aliases section."""
1059
1057
def set_alias(self, alias_name, alias_command):
1060
1058
"""Save the alias in the configuration."""
1061
self._set_option(alias_name, alias_command, 'ALIASES')
1059
with self.lock_write():
1060
self._set_option(alias_name, alias_command, 'ALIASES')
1064
1062
def unset_alias(self, alias_name):
1065
1063
"""Unset an existing alias."""
1067
aliases = self._get_parser().get('ALIASES')
1068
if not aliases or alias_name not in aliases:
1069
raise errors.NoSuchAlias(alias_name)
1070
del aliases[alias_name]
1071
self._write_config_file()
1064
with self.lock_write():
1066
aliases = self._get_parser().get('ALIASES')
1067
if not aliases or alias_name not in aliases:
1068
raise errors.NoSuchAlias(alias_name)
1069
del aliases[alias_name]
1070
self._write_config_file()
1073
1072
def _set_option(self, option, value, section):
1087
1086
# doesn't exist yet. So we force DEFAULT when yielding
1088
1087
name = 'DEFAULT'
1089
1088
if 'DEFAULT' not in parser:
1090
parser['DEFAULT']= {}
1089
parser['DEFAULT'] = {}
1091
1090
yield (name, parser[name], self.config_id())
1094
1092
def remove_user_option(self, option_name, section_name=None):
1095
1093
if section_name is None:
1096
1094
# We need to force the default section.
1097
1095
section_name = 'DEFAULT'
1098
# We need to avoid the LockableConfig implementation or we'll lock
1100
super(LockableConfig, self).remove_user_option(option_name,
1096
with self.lock_write():
1097
# We need to avoid the LockableConfig implementation or we'll lock
1099
super(LockableConfig, self).remove_user_option(
1100
option_name, section_name)
1103
1103
def _iter_for_location_by_parts(sections, location):
1104
1104
"""Keep only the sessions matching the specified location.
1234
1234
if policy_key in self._get_parser()[section]:
1235
1235
del self._get_parser()[section][policy_key]
1238
1237
def set_user_option(self, option, value, store=STORE_LOCATION):
1239
1238
"""Save option and its value in the configuration."""
1240
1239
if store not in [STORE_LOCATION,
1241
1240
STORE_LOCATION_NORECURSE,
1242
1241
STORE_LOCATION_APPENDPATH]:
1243
1242
raise ValueError('bad storage policy %r for %r' %
1246
location = self.location
1247
if location.endswith('/'):
1248
location = location[:-1]
1249
parser = self._get_parser()
1250
if not location in parser and not location + '/' in parser:
1251
parser[location] = {}
1252
elif location + '/' in parser:
1253
location = location + '/'
1254
parser[location][option]=value
1255
# the allowed values of store match the config policies
1256
self._set_option_policy(location, option, store)
1257
self._write_config_file()
1258
for hook in OldConfigHooks['set']:
1259
hook(self, option, value)
1244
with self.lock_write():
1246
location = self.location
1247
if location.endswith('/'):
1248
location = location[:-1]
1249
parser = self._get_parser()
1250
if location not in parser and not location + '/' in parser:
1251
parser[location] = {}
1252
elif location + '/' in parser:
1253
location = location + '/'
1254
parser[location][option] = value
1255
# the allowed values of store match the config policies
1256
self._set_option_policy(location, option, store)
1257
self._write_config_file()
1258
for hook in OldConfigHooks['set']:
1259
hook(self, option, value)
1262
1262
class BranchConfig(Config):
3412
3412
def break_lock(self):
3413
3413
self._lock.break_lock()
3416
3415
def save(self):
3417
# We need to be able to override the undecorated implementation
3418
self.save_without_locking()
3416
with self.lock_write():
3417
# We need to be able to override the undecorated implementation
3418
self.save_without_locking()
3420
3420
def save_without_locking(self):
3421
3421
super(LockableIniFileStore, self).save()
4052
4052
def unlock(self):
4053
4053
return self.branch.unlock()
4056
4055
def set(self, name, value):
4057
super(BranchStack, self).set(name, value)
4058
# Unlocking the branch will trigger a store.save_changes() so the last
4059
# unlock saves all the changes.
4056
with self.lock_write():
4057
super(BranchStack, self).set(name, value)
4058
# Unlocking the branch will trigger a store.save_changes() so the
4059
# last unlock saves all the changes.
4062
4061
def remove(self, name):
4063
super(BranchStack, self).remove(name)
4064
# Unlocking the branch will trigger a store.save_changes() so the last
4065
# unlock saves all the changes.
4062
with self.lock_write():
4063
super(BranchStack, self).remove(name)
4064
# Unlocking the branch will trigger a store.save_changes() so the
4065
# last unlock saves all the changes.
4068
4068
class RemoteControlStack(Stack):
4100
4100
def unlock(self):
4101
4101
return self.branch.unlock()
4104
4103
def set(self, name, value):
4105
super(BranchOnlyStack, self).set(name, value)
4106
# Force a write to persistent storage
4107
self.store.save_changes()
4104
with self.lock_write():
4105
super(BranchOnlyStack, self).set(name, value)
4106
# Force a write to persistent storage
4107
self.store.save_changes()
4110
4109
def remove(self, name):
4111
super(BranchOnlyStack, self).remove(name)
4112
# Force a write to persistent storage
4113
self.store.save_changes()
4110
with self.lock_write():
4111
super(BranchOnlyStack, self).remove(name)
4112
# Force a write to persistent storage
4113
self.store.save_changes()
4116
4116
class cmd_config(commands.Command):