440
444
def set_user_option(self, option, value):
441
445
"""Save option and its value in the configuration."""
446
self._set_option(option, value, 'DEFAULT')
448
def get_aliases(self):
449
"""Return the aliases section."""
450
if 'ALIASES' in self._get_parser():
451
return self._get_parser()['ALIASES']
455
def set_alias(self, alias_name, alias_command):
456
"""Save the alias in the configuration."""
457
self._set_option(alias_name, alias_command, 'ALIASES')
459
def unset_alias(self, alias_name):
460
"""Unset an existing alias."""
461
aliases = self._get_parser().get('ALIASES')
462
if not aliases or alias_name not in aliases:
463
raise errors.NoSuchAlias(alias_name)
464
del aliases[alias_name]
465
self._write_config_file()
467
def _set_option(self, option, value, section):
442
468
# FIXME: RBC 20051029 This should refresh the parser and also take a
443
469
# file lock on bazaar.conf.
444
470
conf_dir = os.path.dirname(self._get_filename())
445
471
ensure_config_dir_exists(conf_dir)
446
if 'DEFAULT' not in self._get_parser():
447
self._get_parser()['DEFAULT'] = {}
448
self._get_parser()['DEFAULT'][option] = value
472
self._get_parser().setdefault(section, {})[option] = value
473
self._write_config_file()
475
def _write_config_file(self):
449
476
f = open(self._get_filename(), 'wb')
450
477
self._get_parser().write(f)
853
908
except ImportError:
856
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
911
user_encoding = osutils.get_user_encoding()
912
realname = username = getpass.getuser().decode(user_encoding)
857
913
except UnicodeDecodeError:
858
914
raise errors.BzrError("Can't decode username as %s." % \
859
bzrlib.user_encoding)
861
917
return realname, (username + '@' + socket.gethostname())
920
def parse_username(username):
921
"""Parse e-mail username and return a (name, address) tuple."""
922
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
924
return (username, '')
926
return (match.group(1), match.group(2))
864
929
def extract_email_address(e):
865
930
"""Return just the address part of an email string.
867
That is just the user@domain part, nothing else.
932
That is just the user@domain part, nothing else.
868
933
This part is required to contain only ascii characters.
869
934
If it can't be extracted, raises an error.
871
936
>>> extract_email_address('Jane Tester <jane@test.com>')
874
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
939
name, email = parse_username(e)
876
941
raise errors.NoEmailInUsername(e)
880
945
class TreeConfig(IniBasedConfig):
881
946
"""Branch configuration data associated with its contents, not location"""
948
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
883
950
def __init__(self, branch):
951
self._config = branch._get_config()
884
952
self.branch = branch
886
954
def _get_parser(self, file=None):
887
955
if file is not None:
888
956
return IniBasedConfig._get_parser(file)
889
return self._get_config()
891
def _get_config(self):
893
obj = ConfigObj(self.branch.control_files.get('branch.conf'),
895
except errors.NoSuchFile:
896
obj = ConfigObj(encoding='utf=8')
957
return self._config._get_configobj()
899
959
def get_option(self, name, section=None, default=None):
900
960
self.branch.lock_read()
902
obj = self._get_config()
904
if section is not None:
962
return self._config.get_option(name, section, default)
910
964
self.branch.unlock()
913
966
def set_option(self, value, name, section=None):
914
967
"""Set a per-branch configuration option"""
915
968
self.branch.lock_write()
917
cfg_obj = self._get_config()
922
obj = cfg_obj[section]
924
cfg_obj[section] = {}
925
obj = cfg_obj[section]
927
out_file = StringIO()
928
cfg_obj.write(out_file)
930
self.branch.control_files.put('branch.conf', out_file)
970
self._config.set_option(value, name, section)
932
972
self.branch.unlock()
1041
1092
if a_user is None:
1042
1093
# Can't find a user
1095
# Prepare a credentials dictionary with additional keys
1096
# for the credential providers
1044
1097
credentials = dict(name=auth_def_name,
1045
user=a_user, password=auth_def['password'],
1104
password=auth_def.get('password', None),
1046
1105
verify_certificates=a_verify_certificates)
1106
# Decode the password in the credentials (or get one)
1047
1107
self.decode_password(credentials,
1048
1108
auth_def.get('password_encoding', None))
1049
1109
if 'auth' in debug.debug_flags:
1050
1110
trace.mutter("Using authentication section: %r", auth_def_name)
1113
if credentials is None:
1114
# No credentials were found in authentication.conf, try the fallback
1115
# credentials stores.
1116
credentials = credential_store_registry.get_fallback_credentials(
1117
scheme, host, port, user, path, realm)
1053
1119
return credentials
1055
def get_user(self, scheme, host, port=None,
1056
realm=None, path=None, prompt=None):
1121
def set_credentials(self, name, host, user, scheme=None, password=None,
1122
port=None, path=None, verify_certificates=None,
1124
"""Set authentication credentials for a host.
1126
Any existing credentials with matching scheme, host, port and path
1127
will be deleted, regardless of name.
1129
:param name: An arbitrary name to describe this set of credentials.
1130
:param host: Name of the host that accepts these credentials.
1131
:param user: The username portion of these credentials.
1132
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1134
:param password: Password portion of these credentials.
1135
:param port: The IP port on the host that these credentials apply to.
1136
:param path: A filesystem path on the host that these credentials
1138
:param verify_certificates: On https, verify server certificates if
1140
:param realm: The http authentication realm (optional).
1142
values = {'host': host, 'user': user}
1143
if password is not None:
1144
values['password'] = password
1145
if scheme is not None:
1146
values['scheme'] = scheme
1147
if port is not None:
1148
values['port'] = '%d' % port
1149
if path is not None:
1150
values['path'] = path
1151
if verify_certificates is not None:
1152
values['verify_certificates'] = str(verify_certificates)
1153
if realm is not None:
1154
values['realm'] = realm
1155
config = self._get_config()
1157
for section, existing_values in config.items():
1158
for key in ('scheme', 'host', 'port', 'path', 'realm'):
1159
if existing_values.get(key) != values.get(key):
1163
config.update({name: values})
1166
def get_user(self, scheme, host, port=None, realm=None, path=None,
1167
prompt=None, ask=False, default=None):
1057
1168
"""Get a user from authentication file.
1059
1170
:param scheme: protocol
1114
1249
return password
1116
1251
def decode_password(self, credentials, encoding):
1253
cs = credential_store_registry.get_credential_store(encoding)
1255
raise ValueError('%r is not a known password_encoding' % encoding)
1256
credentials['password'] = cs.decode_password(credentials)
1260
class CredentialStoreRegistry(registry.Registry):
1261
"""A class that registers credential stores.
1263
A credential store provides access to credentials via the password_encoding
1264
field in authentication.conf sections.
1266
Except for stores provided by bzr itself, most stores are expected to be
1267
provided by plugins that will therefore use
1268
register_lazy(password_encoding, module_name, member_name, help=help,
1269
fallback=fallback) to install themselves.
1271
A fallback credential store is one that is queried if no credentials can be
1272
found via authentication.conf.
1275
def get_credential_store(self, encoding=None):
1276
cs = self.get(encoding)
1281
def is_fallback(self, name):
1282
"""Check if the named credentials store should be used as fallback."""
1283
return self.get_info(name)
1285
def get_fallback_credentials(self, scheme, host, port=None, user=None,
1286
path=None, realm=None):
1287
"""Request credentials from all fallback credentials stores.
1289
The first credentials store that can provide credentials wins.
1292
for name in self.keys():
1293
if not self.is_fallback(name):
1295
cs = self.get_credential_store(name)
1296
credentials = cs.get_credentials(scheme, host, port, user,
1298
if credentials is not None:
1299
# We found some credentials
1303
def register(self, key, obj, help=None, override_existing=False,
1305
"""Register a new object to a name.
1307
:param key: This is the key to use to request the object later.
1308
:param obj: The object to register.
1309
:param help: Help text for this entry. This may be a string or
1310
a callable. If it is a callable, it should take two
1311
parameters (registry, key): this registry and the key that
1312
the help was registered under.
1313
:param override_existing: Raise KeyErorr if False and something has
1314
already been registered for that key. If True, ignore if there
1315
is an existing key (always register the new value).
1316
:param fallback: Whether this credential store should be
1319
return super(CredentialStoreRegistry,
1320
self).register(key, obj, help, info=fallback,
1321
override_existing=override_existing)
1323
def register_lazy(self, key, module_name, member_name,
1324
help=None, override_existing=False,
1326
"""Register a new credential store to be loaded on request.
1328
:param module_name: The python path to the module. Such as 'os.path'.
1329
:param member_name: The member of the module to return. If empty or
1330
None, get() will return the module itself.
1331
:param help: Help text for this entry. This may be a string or
1333
:param override_existing: If True, replace the existing object
1334
with the new one. If False, if there is already something
1335
registered with the same key, raise a KeyError
1336
:param fallback: Whether this credential store should be
1339
return super(CredentialStoreRegistry, self).register_lazy(
1340
key, module_name, member_name, help,
1341
info=fallback, override_existing=override_existing)
1344
credential_store_registry = CredentialStoreRegistry()
1347
class CredentialStore(object):
1348
"""An abstract class to implement storage for credentials"""
1350
def decode_password(self, credentials):
1351
"""Returns a clear text password for the provided credentials."""
1352
raise NotImplementedError(self.decode_password)
1354
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1356
"""Return the matching credentials from this credential store.
1358
This method is only called on fallback credential stores.
1360
raise NotImplementedError(self.get_credentials)
1364
class PlainTextCredentialStore(CredentialStore):
1365
"""Plain text credential store for the authentication.conf file."""
1367
def decode_password(self, credentials):
1368
"""See CredentialStore.decode_password."""
1369
return credentials['password']
1372
credential_store_registry.register('plain', PlainTextCredentialStore,
1373
help=PlainTextCredentialStore.__doc__)
1374
credential_store_registry.default_key = 'plain'
1377
class BzrDirConfig(object):
1379
def __init__(self, bzrdir):
1380
self._bzrdir = bzrdir
1381
self._config = bzrdir._get_config()
1383
def set_default_stack_on(self, value):
1384
"""Set the default stacking location.
1386
It may be set to a location, or None.
1388
This policy affects all branches contained by this bzrdir, except for
1389
those under repositories.
1391
if self._config is None:
1392
raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1394
self._config.set_option('', 'default_stack_on')
1396
self._config.set_option(value, 'default_stack_on')
1398
def get_default_stack_on(self):
1399
"""Return the default stacking location.
1401
This will either be a location, or None.
1403
This policy affects all branches contained by this bzrdir, except for
1404
those under repositories.
1406
if self._config is None:
1408
value = self._config.get_option('default_stack_on')
1414
class TransportConfig(object):
1415
"""A Config that reads/writes a config file on a Transport.
1417
It is a low-level object that considers config data to be name/value pairs
1418
that may be associated with a section. Assigning meaning to the these
1419
values is done at higher levels like TreeConfig.
1422
def __init__(self, transport, filename):
1423
self._transport = transport
1424
self._filename = filename
1426
def get_option(self, name, section=None, default=None):
1427
"""Return the value associated with a named option.
1429
:param name: The name of the value
1430
:param section: The section the option is in (if any)
1431
:param default: The value to return if the value is not set
1432
:return: The value or default value
1434
configobj = self._get_configobj()
1436
section_obj = configobj
1439
section_obj = configobj[section]
1442
return section_obj.get(name, default)
1444
def set_option(self, value, name, section=None):
1445
"""Set the value associated with a named option.
1447
:param value: The value to set
1448
:param name: The name of the value to set
1449
:param section: The section the option is in (if any)
1451
configobj = self._get_configobj()
1453
configobj[name] = value
1455
configobj.setdefault(section, {})[name] = value
1456
self._set_configobj(configobj)
1458
def _get_config_file(self):
1460
return self._transport.get(self._filename)
1461
except errors.NoSuchFile:
1464
def _get_configobj(self):
1465
return ConfigObj(self._get_config_file(), encoding='utf-8')
1467
def _set_configobj(self, configobj):
1468
out_file = StringIO()
1469
configobj.write(out_file)
1471
self._transport.put_file(self._filename, out_file)