147
147
def get_mail_client(self):
148
148
"""Get a mail client to use"""
149
149
selected_client = self.get_user_option('mail_client')
150
_registry = mail_client.mail_client_registry
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,
152
mail_client_class = _registry.get(selected_client)
165
154
raise errors.UnknownMailClient(selected_client)
166
155
return mail_client_class(self)
440
429
def set_user_option(self, option, value):
441
430
"""Save option and its value in the configuration."""
431
self._set_option(option, value, 'DEFAULT')
433
def get_aliases(self):
434
"""Return the aliases section."""
435
if 'ALIASES' in self._get_parser():
436
return self._get_parser()['ALIASES']
440
def set_alias(self, alias_name, alias_command):
441
"""Save the alias in the configuration."""
442
self._set_option(alias_name, alias_command, 'ALIASES')
444
def unset_alias(self, alias_name):
445
"""Unset an existing alias."""
446
aliases = self._get_parser().get('ALIASES')
447
if not aliases or alias_name not in aliases:
448
raise errors.NoSuchAlias(alias_name)
449
del aliases[alias_name]
450
self._write_config_file()
452
def _set_option(self, option, value, section):
442
453
# FIXME: RBC 20051029 This should refresh the parser and also take a
443
454
# file lock on bazaar.conf.
444
455
conf_dir = os.path.dirname(self._get_filename())
445
456
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
457
self._get_parser().setdefault(section, {})[option] = value
458
self._write_config_file()
460
def _write_config_file(self):
449
461
f = open(self._get_filename(), 'wb')
450
462
self._get_parser().write(f)
570
582
def set_user_option(self, option, value, store=STORE_LOCATION):
571
583
"""Save option and its value in the configuration."""
572
assert store in [STORE_LOCATION,
584
if store not in [STORE_LOCATION,
573
585
STORE_LOCATION_NORECURSE,
574
STORE_LOCATION_APPENDPATH], 'bad storage policy'
586
STORE_LOCATION_APPENDPATH]:
587
raise ValueError('bad storage policy %r for %r' %
575
589
# FIXME: RBC 20051029 This should refresh the parser and also take a
576
590
# file lock on locations.conf.
577
591
conf_dir = os.path.dirname(self._get_filename())
760
773
base = os.environ.get('HOME', None)
762
raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
775
raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
763
777
return osutils.pathjoin(base, 'bazaar', '2.0')
765
779
# cygwin, linux, and darwin all have a $HOME directory
861
875
return realname, (username + '@' + socket.gethostname())
878
def parse_username(username):
879
"""Parse e-mail username and return a (name, address) tuple."""
880
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
882
return (username, '')
884
return (match.group(1), match.group(2))
864
887
def extract_email_address(e):
865
888
"""Return just the address part of an email string.
867
890
That is just the user@domain part, nothing else.
868
891
This part is required to contain only ascii characters.
869
892
If it can't be extracted, raises an error.
871
894
>>> extract_email_address('Jane Tester <jane@test.com>')
874
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
897
name, email = parse_username(e)
876
899
raise errors.NoEmailInUsername(e)
880
903
class TreeConfig(IniBasedConfig):
881
904
"""Branch configuration data associated with its contents, not location"""
906
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
883
908
def __init__(self, branch):
909
# XXX: Really this should be asking the branch for its configuration
910
# data, rather than relying on a Transport, so that it can work
911
# more cleanly with a RemoteBranch that has no transport.
912
self._config = TransportConfig(branch._transport, 'branch.conf')
884
913
self.branch = branch
886
915
def _get_parser(self, file=None):
887
916
if file is not None:
888
917
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')
918
return self._config._get_configobj()
899
920
def get_option(self, name, section=None, default=None):
900
921
self.branch.lock_read()
902
obj = self._get_config()
904
if section is not None:
923
return self._config.get_option(name, section, default)
910
925
self.branch.unlock()
1006
1008
credentials = None
1007
1009
for auth_def_name, auth_def in self._get_config().items():
1010
if type(auth_def) is not configobj.Section:
1011
raise ValueError("%s defined outside a section" % auth_def_name)
1008
1013
a_scheme, a_host, a_user, a_path = map(
1009
1014
auth_def.get, ['scheme', 'host', 'user', 'path'])
1042
1047
# Can't find a user
1044
1049
credentials = dict(name=auth_def_name,
1045
user=a_user, password=auth_def['password'],
1051
password=auth_def.get('password', None),
1046
1052
verify_certificates=a_verify_certificates)
1047
1053
self.decode_password(credentials,
1048
1054
auth_def.get('password_encoding', None))
1097
1103
credentials = self.get_credentials(scheme, host, port, user, path)
1098
1104
if credentials is not None:
1099
1105
password = credentials['password']
1106
if password is not None and scheme is 'ssh':
1107
trace.warning('password ignored in section [%s],'
1108
' use an ssh agent instead'
1109
% credentials['name'])
1101
1112
password = None
1102
1113
# Prompt user only if we could't find a password
1103
1114
if password is None:
1104
1115
if prompt is None:
1105
# Create a default prompt suitable for most of the cases
1116
# Create a default prompt suitable for most cases
1106
1117
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1107
1118
# Special handling for optional fields in the prompt
1108
1119
if port is not None:
1116
1127
def decode_password(self, credentials, encoding):
1117
1128
return credentials
1131
class BzrDirConfig(object):
1133
def __init__(self, transport):
1134
self._config = TransportConfig(transport, 'control.conf')
1136
def set_default_stack_on(self, value):
1137
"""Set the default stacking location.
1139
It may be set to a location, or None.
1141
This policy affects all branches contained by this bzrdir, except for
1142
those under repositories.
1145
self._config.set_option('', 'default_stack_on')
1147
self._config.set_option(value, 'default_stack_on')
1149
def get_default_stack_on(self):
1150
"""Return the default stacking location.
1152
This will either be a location, or None.
1154
This policy affects all branches contained by this bzrdir, except for
1155
those under repositories.
1157
value = self._config.get_option('default_stack_on')
1163
class TransportConfig(object):
1164
"""A Config that reads/writes a config file on a Transport.
1166
It is a low-level object that considers config data to be name/value pairs
1167
that may be associated with a section. Assigning meaning to the these
1168
values is done at higher levels like TreeConfig.
1171
def __init__(self, transport, filename):
1172
self._transport = transport
1173
self._filename = filename
1175
def get_option(self, name, section=None, default=None):
1176
"""Return the value associated with a named option.
1178
:param name: The name of the value
1179
:param section: The section the option is in (if any)
1180
:param default: The value to return if the value is not set
1181
:return: The value or default value
1183
configobj = self._get_configobj()
1185
section_obj = configobj
1188
section_obj = configobj[section]
1191
return section_obj.get(name, default)
1193
def set_option(self, value, name, section=None):
1194
"""Set the value associated with a named option.
1196
:param value: The value to set
1197
:param name: The name of the value to set
1198
:param section: The section the option is in (if any)
1200
configobj = self._get_configobj()
1202
configobj[name] = value
1204
configobj.setdefault(section, {})[name] = value
1205
self._set_configobj(configobj)
1207
def _get_configobj(self):
1209
return ConfigObj(self._transport.get(self._filename),
1211
except errors.NoSuchFile:
1212
return ConfigObj(encoding='utf-8')
1214
def _set_configobj(self, configobj):
1215
out_file = StringIO()
1216
configobj.write(out_file)
1218
self._transport.put_file(self._filename, out_file)