126
def ConfigObj(*args, **kwargs):
128
if _ConfigObj is None:
129
class ConfigObj(configobj.ConfigObj):
131
def get_bool(self, section, key):
132
return self[section].as_bool(key)
134
def get_value(self, section, name):
135
# Try [] for the old DEFAULT section.
136
if section == "DEFAULT":
141
return self[section][name]
142
_ConfigObj = ConfigObj
143
return _ConfigObj(*args, **kwargs)
125
class ConfigObj(configobj.ConfigObj):
127
def get_bool(self, section, key):
128
return self[section].as_bool(key)
130
def get_value(self, section, name):
131
# Try [] for the old DEFAULT section.
132
if section == "DEFAULT":
137
return self[section][name]
146
140
class Config(object):
147
141
"""A configuration policy - what username, editor, gpg needs etc."""
150
super(Config, self).__init__()
152
143
def get_editor(self):
153
144
"""Get the users pop up editor."""
154
145
raise NotImplementedError
156
def get_change_editor(self, old_tree, new_tree):
157
from bzrlib import diff
158
cmd = self._get_change_editor()
161
return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
165
147
def get_mail_client(self):
166
148
"""Get a mail client to use"""
167
149
selected_client = self.get_user_option('mail_client')
168
_registry = mail_client.mail_client_registry
170
mail_client_class = _registry.get(selected_client)
151
mail_client_class = {
152
None: mail_client.DefaultMail,
154
'evolution': mail_client.Evolution,
155
'kmail': mail_client.KMail,
156
'mutt': mail_client.Mutt,
157
'thunderbird': mail_client.Thunderbird,
159
'default': mail_client.DefaultMail,
160
'editor': mail_client.Editor,
161
'mapi': mail_client.MAPIClient,
162
'emacs-mailmode': mail_client.EmacsMailMode,
163
'xdg-email': mail_client.XDGEmail,
172
166
raise errors.UnknownMailClient(selected_client)
173
167
return mail_client_class(self)
481
441
def set_user_option(self, option, value):
482
442
"""Save option and its value in the configuration."""
483
self._set_option(option, value, 'DEFAULT')
485
def get_aliases(self):
486
"""Return the aliases section."""
487
if 'ALIASES' in self._get_parser():
488
return self._get_parser()['ALIASES']
492
def set_alias(self, alias_name, alias_command):
493
"""Save the alias in the configuration."""
494
self._set_option(alias_name, alias_command, 'ALIASES')
496
def unset_alias(self, alias_name):
497
"""Unset an existing alias."""
498
aliases = self._get_parser().get('ALIASES')
499
if not aliases or alias_name not in aliases:
500
raise errors.NoSuchAlias(alias_name)
501
del aliases[alias_name]
502
self._write_config_file()
504
def _set_option(self, option, value, section):
505
443
# FIXME: RBC 20051029 This should refresh the parser and also take a
506
444
# file lock on bazaar.conf.
507
445
conf_dir = os.path.dirname(self._get_filename())
508
446
ensure_config_dir_exists(conf_dir)
509
self._get_parser().setdefault(section, {})[option] = value
510
self._write_config_file()
512
def _write_config_file(self):
447
if 'DEFAULT' not in self._get_parser():
448
self._get_parser()['DEFAULT'] = {}
449
self._get_parser()['DEFAULT'][option] = value
513
450
f = open(self._get_filename(), 'wb')
514
451
self._get_parser().write(f)
1132
1052
if a_user is None:
1133
1053
# Can't find a user
1135
# Prepare a credentials dictionary with additional keys
1136
# for the credential providers
1137
1055
credentials = dict(name=auth_def_name,
1144
password=auth_def.get('password', None),
1056
user=a_user, password=auth_def['password'],
1145
1057
verify_certificates=a_verify_certificates)
1146
# Decode the password in the credentials (or get one)
1147
1058
self.decode_password(credentials,
1148
1059
auth_def.get('password_encoding', None))
1149
1060
if 'auth' in debug.debug_flags:
1150
1061
trace.mutter("Using authentication section: %r", auth_def_name)
1153
if credentials is None:
1154
# No credentials were found in authentication.conf, try the fallback
1155
# credentials stores.
1156
credentials = credential_store_registry.get_fallback_credentials(
1157
scheme, host, port, user, path, realm)
1159
1064
return credentials
1161
def set_credentials(self, name, host, user, scheme=None, password=None,
1162
port=None, path=None, verify_certificates=None,
1164
"""Set authentication credentials for a host.
1166
Any existing credentials with matching scheme, host, port and path
1167
will be deleted, regardless of name.
1169
:param name: An arbitrary name to describe this set of credentials.
1170
:param host: Name of the host that accepts these credentials.
1171
:param user: The username portion of these credentials.
1172
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1174
:param password: Password portion of these credentials.
1175
:param port: The IP port on the host that these credentials apply to.
1176
:param path: A filesystem path on the host that these credentials
1178
:param verify_certificates: On https, verify server certificates if
1180
:param realm: The http authentication realm (optional).
1182
values = {'host': host, 'user': user}
1183
if password is not None:
1184
values['password'] = password
1185
if scheme is not None:
1186
values['scheme'] = scheme
1187
if port is not None:
1188
values['port'] = '%d' % port
1189
if path is not None:
1190
values['path'] = path
1191
if verify_certificates is not None:
1192
values['verify_certificates'] = str(verify_certificates)
1193
if realm is not None:
1194
values['realm'] = realm
1195
config = self._get_config()
1197
for section, existing_values in config.items():
1198
for key in ('scheme', 'host', 'port', 'path', 'realm'):
1199
if existing_values.get(key) != values.get(key):
1203
config.update({name: values})
1206
def get_user(self, scheme, host, port=None, realm=None, path=None,
1207
prompt=None, ask=False, default=None):
1066
def get_user(self, scheme, host, port=None,
1067
realm=None, path=None, prompt=None):
1208
1068
"""Get a user from authentication file.
1210
1070
:param scheme: protocol
1289
1125
return password
1291
1127
def decode_password(self, credentials, encoding):
1293
cs = credential_store_registry.get_credential_store(encoding)
1295
raise ValueError('%r is not a known password_encoding' % encoding)
1296
credentials['password'] = cs.decode_password(credentials)
1300
class CredentialStoreRegistry(registry.Registry):
1301
"""A class that registers credential stores.
1303
A credential store provides access to credentials via the password_encoding
1304
field in authentication.conf sections.
1306
Except for stores provided by bzr itself, most stores are expected to be
1307
provided by plugins that will therefore use
1308
register_lazy(password_encoding, module_name, member_name, help=help,
1309
fallback=fallback) to install themselves.
1311
A fallback credential store is one that is queried if no credentials can be
1312
found via authentication.conf.
1315
def get_credential_store(self, encoding=None):
1316
cs = self.get(encoding)
1321
def is_fallback(self, name):
1322
"""Check if the named credentials store should be used as fallback."""
1323
return self.get_info(name)
1325
def get_fallback_credentials(self, scheme, host, port=None, user=None,
1326
path=None, realm=None):
1327
"""Request credentials from all fallback credentials stores.
1329
The first credentials store that can provide credentials wins.
1332
for name in self.keys():
1333
if not self.is_fallback(name):
1335
cs = self.get_credential_store(name)
1336
credentials = cs.get_credentials(scheme, host, port, user,
1338
if credentials is not None:
1339
# We found some credentials
1343
def register(self, key, obj, help=None, override_existing=False,
1345
"""Register a new object to a name.
1347
:param key: This is the key to use to request the object later.
1348
:param obj: The object to register.
1349
:param help: Help text for this entry. This may be a string or
1350
a callable. If it is a callable, it should take two
1351
parameters (registry, key): this registry and the key that
1352
the help was registered under.
1353
:param override_existing: Raise KeyErorr if False and something has
1354
already been registered for that key. If True, ignore if there
1355
is an existing key (always register the new value).
1356
:param fallback: Whether this credential store should be
1359
return super(CredentialStoreRegistry,
1360
self).register(key, obj, help, info=fallback,
1361
override_existing=override_existing)
1363
def register_lazy(self, key, module_name, member_name,
1364
help=None, override_existing=False,
1366
"""Register a new credential store to be loaded on request.
1368
:param module_name: The python path to the module. Such as 'os.path'.
1369
:param member_name: The member of the module to return. If empty or
1370
None, get() will return the module itself.
1371
:param help: Help text for this entry. This may be a string or
1373
:param override_existing: If True, replace the existing object
1374
with the new one. If False, if there is already something
1375
registered with the same key, raise a KeyError
1376
:param fallback: Whether this credential store should be
1379
return super(CredentialStoreRegistry, self).register_lazy(
1380
key, module_name, member_name, help,
1381
info=fallback, override_existing=override_existing)
1384
credential_store_registry = CredentialStoreRegistry()
1387
class CredentialStore(object):
1388
"""An abstract class to implement storage for credentials"""
1390
def decode_password(self, credentials):
1391
"""Returns a clear text password for the provided credentials."""
1392
raise NotImplementedError(self.decode_password)
1394
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1396
"""Return the matching credentials from this credential store.
1398
This method is only called on fallback credential stores.
1400
raise NotImplementedError(self.get_credentials)
1404
class PlainTextCredentialStore(CredentialStore):
1405
"""Plain text credential store for the authentication.conf file."""
1407
def decode_password(self, credentials):
1408
"""See CredentialStore.decode_password."""
1409
return credentials['password']
1412
credential_store_registry.register('plain', PlainTextCredentialStore,
1413
help=PlainTextCredentialStore.__doc__)
1414
credential_store_registry.default_key = 'plain'
1417
class BzrDirConfig(object):
1419
def __init__(self, bzrdir):
1420
self._bzrdir = bzrdir
1421
self._config = bzrdir._get_config()
1423
def set_default_stack_on(self, value):
1424
"""Set the default stacking location.
1426
It may be set to a location, or None.
1428
This policy affects all branches contained by this bzrdir, except for
1429
those under repositories.
1431
if self._config is None:
1432
raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1434
self._config.set_option('', 'default_stack_on')
1436
self._config.set_option(value, 'default_stack_on')
1438
def get_default_stack_on(self):
1439
"""Return the default stacking location.
1441
This will either be a location, or None.
1443
This policy affects all branches contained by this bzrdir, except for
1444
those under repositories.
1446
if self._config is None:
1448
value = self._config.get_option('default_stack_on')
1454
class TransportConfig(object):
1455
"""A Config that reads/writes a config file on a Transport.
1457
It is a low-level object that considers config data to be name/value pairs
1458
that may be associated with a section. Assigning meaning to the these
1459
values is done at higher levels like TreeConfig.
1462
def __init__(self, transport, filename):
1463
self._transport = transport
1464
self._filename = filename
1466
def get_option(self, name, section=None, default=None):
1467
"""Return the value associated with a named option.
1469
:param name: The name of the value
1470
:param section: The section the option is in (if any)
1471
:param default: The value to return if the value is not set
1472
:return: The value or default value
1474
configobj = self._get_configobj()
1476
section_obj = configobj
1479
section_obj = configobj[section]
1482
return section_obj.get(name, default)
1484
def set_option(self, value, name, section=None):
1485
"""Set the value associated with a named option.
1487
:param value: The value to set
1488
:param name: The name of the value to set
1489
:param section: The section the option is in (if any)
1491
configobj = self._get_configobj()
1493
configobj[name] = value
1495
configobj.setdefault(section, {})[name] = value
1496
self._set_configobj(configobj)
1498
def _get_config_file(self):
1500
return StringIO(self._transport.get_bytes(self._filename))
1501
except errors.NoSuchFile:
1504
def _get_configobj(self):
1505
return ConfigObj(self._get_config_file(), encoding='utf-8')
1507
def _set_configobj(self, configobj):
1508
out_file = StringIO()
1509
configobj.write(out_file)
1511
self._transport.put_file(self._filename, out_file)