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):
153
147
def get_mail_client(self):
154
148
"""Get a mail client to use"""
155
149
selected_client = self.get_user_option('mail_client')
156
_registry = mail_client.mail_client_registry
158
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
'xdg-email': mail_client.XDGEmail,
160
165
raise errors.UnknownMailClient(selected_client)
161
166
return mail_client_class(self)
435
440
def set_user_option(self, option, value):
436
441
"""Save option and its value in the configuration."""
437
self._set_option(option, value, 'DEFAULT')
439
def get_aliases(self):
440
"""Return the aliases section."""
441
if 'ALIASES' in self._get_parser():
442
return self._get_parser()['ALIASES']
446
def set_alias(self, alias_name, alias_command):
447
"""Save the alias in the configuration."""
448
self._set_option(alias_name, alias_command, 'ALIASES')
450
def unset_alias(self, alias_name):
451
"""Unset an existing alias."""
452
aliases = self._get_parser().get('ALIASES')
453
if not aliases or alias_name not in aliases:
454
raise errors.NoSuchAlias(alias_name)
455
del aliases[alias_name]
456
self._write_config_file()
458
def _set_option(self, option, value, section):
459
442
# FIXME: RBC 20051029 This should refresh the parser and also take a
460
443
# file lock on bazaar.conf.
461
444
conf_dir = os.path.dirname(self._get_filename())
462
445
ensure_config_dir_exists(conf_dir)
463
self._get_parser().setdefault(section, {})[option] = value
464
self._write_config_file()
466
def _write_config_file(self):
446
if 'DEFAULT' not in self._get_parser():
447
self._get_parser()['DEFAULT'] = {}
448
self._get_parser()['DEFAULT'][option] = value
467
449
f = open(self._get_filename(), 'wb')
468
450
self._get_parser().write(f)
877
853
except ImportError:
880
user_encoding = osutils.get_user_encoding()
881
realname = username = getpass.getuser().decode(user_encoding)
856
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
882
857
except UnicodeDecodeError:
883
858
raise errors.BzrError("Can't decode username as %s." % \
859
bzrlib.user_encoding)
886
861
return realname, (username + '@' + socket.gethostname())
889
def parse_username(username):
890
"""Parse e-mail username and return a (name, address) tuple."""
891
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
893
return (username, '')
895
return (match.group(1), match.group(2))
898
864
def extract_email_address(e):
899
865
"""Return just the address part of an email string.
901
867
That is just the user@domain part, nothing else.
902
868
This part is required to contain only ascii characters.
903
869
If it can't be extracted, raises an error.
905
871
>>> extract_email_address('Jane Tester <jane@test.com>')
908
name, email = parse_username(e)
874
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
910
876
raise errors.NoEmailInUsername(e)
914
880
class TreeConfig(IniBasedConfig):
915
881
"""Branch configuration data associated with its contents, not location"""
917
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
919
883
def __init__(self, branch):
920
# XXX: Really this should be asking the branch for its configuration
921
# data, rather than relying on a Transport, so that it can work
922
# more cleanly with a RemoteBranch that has no transport.
923
self._config = TransportConfig(branch._transport, 'branch.conf')
924
884
self.branch = branch
926
886
def _get_parser(self, file=None):
927
887
if file is not None:
928
888
return IniBasedConfig._get_parser(file)
929
return self._config._get_configobj()
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')
931
899
def get_option(self, name, section=None, default=None):
932
900
self.branch.lock_read()
934
return self._config.get_option(name, section, default)
902
obj = self._get_config()
904
if section is not None:
936
910
self.branch.unlock()
1070
1053
return credentials
1072
def set_credentials(self, name, host, user, scheme=None, password=None,
1073
port=None, path=None, verify_certificates=None):
1074
"""Set authentication credentials for a host.
1076
Any existing credentials with matching scheme, host, port and path
1077
will be deleted, regardless of name.
1079
:param name: An arbitrary name to describe this set of credentials.
1080
:param host: Name of the host that accepts these credentials.
1081
:param user: The username portion of these credentials.
1082
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1084
:param password: Password portion of these credentials.
1085
:param port: The IP port on the host that these credentials apply to.
1086
:param path: A filesystem path on the host that these credentials
1088
:param verify_certificates: On https, verify server certificates if
1091
values = {'host': host, 'user': user}
1092
if password is not None:
1093
values['password'] = password
1094
if scheme is not None:
1095
values['scheme'] = scheme
1096
if port is not None:
1097
values['port'] = '%d' % port
1098
if path is not None:
1099
values['path'] = path
1100
if verify_certificates is not None:
1101
values['verify_certificates'] = str(verify_certificates)
1102
config = self._get_config()
1104
for section, existing_values in config.items():
1105
for key in ('scheme', 'host', 'port', 'path'):
1106
if existing_values.get(key) != values.get(key):
1110
config.update({name: values})
1113
1055
def get_user(self, scheme, host, port=None,
1114
1056
realm=None, path=None, prompt=None):
1115
1057
"""Get a user from authentication file.
1177
1114
return password
1179
1116
def decode_password(self, credentials, encoding):
1181
cs = credential_store_registry.get_credential_store(encoding)
1183
raise ValueError('%r is not a known password_encoding' % encoding)
1184
credentials['password'] = cs.decode_password(credentials)
1185
1117
return credentials
1188
class CredentialStoreRegistry(registry.Registry):
1189
"""A class that registers credential stores.
1191
A credential store provides access to credentials via the password_encoding
1192
field in authentication.conf sections.
1194
Except for stores provided by bzr itself,most stores are expected to be
1195
provided by plugins that will therefore use
1196
register_lazy(password_encoding, module_name, member_name, help=help,
1197
info=info) to install themselves.
1200
def get_credential_store(self, encoding=None):
1201
cs = self.get(encoding)
1207
credential_store_registry = CredentialStoreRegistry()
1210
class CredentialStore(object):
1211
"""An abstract class to implement storage for credentials"""
1213
def decode_password(self, credentials):
1214
"""Returns a password for the provided credentials in clear text."""
1215
raise NotImplementedError(self.decode_password)
1218
class PlainTextCredentialStore(CredentialStore):
1219
"""Plain text credential store for the authentication.conf file."""
1221
def decode_password(self, credentials):
1222
"""See CredentialStore.decode_password."""
1223
return credentials['password']
1226
credential_store_registry.register('plain', PlainTextCredentialStore,
1227
help=PlainTextCredentialStore.__doc__)
1228
credential_store_registry.default_key = 'plain'
1231
class BzrDirConfig(object):
1233
def __init__(self, transport):
1234
self._config = TransportConfig(transport, 'control.conf')
1236
def set_default_stack_on(self, value):
1237
"""Set the default stacking location.
1239
It may be set to a location, or None.
1241
This policy affects all branches contained by this bzrdir, except for
1242
those under repositories.
1245
self._config.set_option('', 'default_stack_on')
1247
self._config.set_option(value, 'default_stack_on')
1249
def get_default_stack_on(self):
1250
"""Return the default stacking location.
1252
This will either be a location, or None.
1254
This policy affects all branches contained by this bzrdir, except for
1255
those under repositories.
1257
value = self._config.get_option('default_stack_on')
1263
class TransportConfig(object):
1264
"""A Config that reads/writes a config file on a Transport.
1266
It is a low-level object that considers config data to be name/value pairs
1267
that may be associated with a section. Assigning meaning to the these
1268
values is done at higher levels like TreeConfig.
1271
def __init__(self, transport, filename):
1272
self._transport = transport
1273
self._filename = filename
1275
def get_option(self, name, section=None, default=None):
1276
"""Return the value associated with a named option.
1278
:param name: The name of the value
1279
:param section: The section the option is in (if any)
1280
:param default: The value to return if the value is not set
1281
:return: The value or default value
1283
configobj = self._get_configobj()
1285
section_obj = configobj
1288
section_obj = configobj[section]
1291
return section_obj.get(name, default)
1293
def set_option(self, value, name, section=None):
1294
"""Set the value associated with a named option.
1296
:param value: The value to set
1297
:param name: The name of the value to set
1298
:param section: The section the option is in (if any)
1300
configobj = self._get_configobj()
1302
configobj[name] = value
1304
configobj.setdefault(section, {})[name] = value
1305
self._set_configobj(configobj)
1307
def _get_configobj(self):
1309
return ConfigObj(self._transport.get(self._filename),
1311
except errors.NoSuchFile:
1312
return ConfigObj(encoding='utf-8')
1314
def _set_configobj(self, configobj):
1315
out_file = StringIO()
1316
configobj.write(out_file)
1318
self._transport.put_file(self._filename, out_file)