151
151
mail_client_class = {
152
152
None: mail_client.DefaultMail,
153
153
# Specific clients
154
'emacsclient': mail_client.EmacsMail,
155
154
'evolution': mail_client.Evolution,
156
155
'kmail': mail_client.KMail,
157
156
'mutt': mail_client.Mutt,
571
570
def set_user_option(self, option, value, store=STORE_LOCATION):
572
571
"""Save option and its value in the configuration."""
573
if store not in [STORE_LOCATION,
572
assert store in [STORE_LOCATION,
574
573
STORE_LOCATION_NORECURSE,
575
STORE_LOCATION_APPENDPATH]:
576
raise ValueError('bad storage policy %r for %r' %
574
STORE_LOCATION_APPENDPATH], 'bad storage policy'
578
575
# FIXME: RBC 20051029 This should refresh the parser and also take a
579
576
# file lock on locations.conf.
580
577
conf_dir = os.path.dirname(self._get_filename())
641
638
def _get_user_id(self):
642
639
"""Return the full user id for the branch.
644
e.g. "John Hacker <jhacker@example.com>"
641
e.g. "John Hacker <jhacker@foo.org>"
645
642
This is looked up in the email controlfile for the branch.
648
return (self.branch._transport.get_bytes("email")
645
return (self.branch.control_files.get_utf8("email")
649
647
.decode(bzrlib.user_encoding)
651
649
except errors.NoSuchFile, e:
864
862
return realname, (username + '@' + socket.gethostname())
867
def parse_username(username):
868
"""Parse e-mail username and return a (name, address) tuple."""
869
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
871
return (username, '')
873
return (match.group(1), match.group(2))
876
865
def extract_email_address(e):
877
866
"""Return just the address part of an email string.
879
868
That is just the user@domain part, nothing else.
880
869
This part is required to contain only ascii characters.
881
870
If it can't be extracted, raises an error.
883
872
>>> extract_email_address('Jane Tester <jane@test.com>')
886
name, email = parse_username(e)
875
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
888
877
raise errors.NoEmailInUsername(e)
892
881
class TreeConfig(IniBasedConfig):
893
882
"""Branch configuration data associated with its contents, not location"""
895
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
897
884
def __init__(self, branch):
898
# XXX: Really this should be asking the branch for its configuration
899
# data, rather than relying on a Transport, so that it can work
900
# more cleanly with a RemoteBranch that has no transport.
901
self._config = TransportConfig(branch._transport, 'branch.conf')
902
885
self.branch = branch
904
887
def _get_parser(self, file=None):
905
888
if file is not None:
906
889
return IniBasedConfig._get_parser(file)
907
return self._config._get_configobj()
890
return self._get_config()
892
def _get_config(self):
894
obj = ConfigObj(self.branch.control_files.get('branch.conf'),
896
except errors.NoSuchFile:
897
obj = ConfigObj(encoding='utf=8')
909
900
def get_option(self, name, section=None, default=None):
910
901
self.branch.lock_read()
912
return self._config.get_option(name, section, default)
903
obj = self._get_config()
905
if section is not None:
914
911
self.branch.unlock()
918
915
"""Set a per-branch configuration option"""
919
916
self.branch.lock_write()
921
self._config.set_option(value, name, section)
918
cfg_obj = self._get_config()
923
obj = cfg_obj[section]
925
cfg_obj[section] = {}
926
obj = cfg_obj[section]
928
out_file = StringIO()
929
cfg_obj.write(out_file)
931
self.branch.control_files.put('branch.conf', out_file)
923
933
self.branch.unlock()
997
1007
credentials = None
998
1008
for auth_def_name, auth_def in self._get_config().items():
999
if type(auth_def) is not configobj.Section:
1000
raise ValueError("%s defined outside a section" % auth_def_name)
1002
1009
a_scheme, a_host, a_user, a_path = map(
1003
1010
auth_def.get, ['scheme', 'host', 'user', 'path'])
1036
1043
# Can't find a user
1038
1045
credentials = dict(name=auth_def_name,
1040
password=auth_def.get('password', None),
1046
user=a_user, password=auth_def['password'],
1041
1047
verify_certificates=a_verify_certificates)
1042
1048
self.decode_password(credentials,
1043
1049
auth_def.get('password_encoding', None))
1092
1098
credentials = self.get_credentials(scheme, host, port, user, path)
1093
1099
if credentials is not None:
1094
1100
password = credentials['password']
1095
if password is not None and scheme is 'ssh':
1096
trace.warning('password ignored in section [%s],'
1097
' use an ssh agent instead'
1098
% credentials['name'])
1101
1102
password = None
1102
1103
# Prompt user only if we could't find a password
1103
1104
if password is None:
1104
1105
if prompt is None:
1105
# Create a default prompt suitable for most cases
1106
# Create a default prompt suitable for most of the cases
1106
1107
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1107
1108
# Special handling for optional fields in the prompt
1108
1109
if port is not None:
1116
1117
def decode_password(self, credentials, encoding):
1117
1118
return credentials
1120
class TransportConfig(object):
1121
"""A Config that reads/writes a config file on a Transport.
1123
It is a low-level object that considers config data to be name/value pairs
1124
that may be associated with a section. Assigning meaning to the these
1125
values is done at higher levels like TreeConfig.
1128
def __init__(self, transport, filename):
1129
self._transport = transport
1130
self._filename = filename
1132
def get_option(self, name, section=None, default=None):
1133
"""Return the value associated with a named option.
1135
:param name: The name of the value
1136
:param section: The section the option is in (if any)
1137
:param default: The value to return if the value is not set
1138
:return: The value or default value
1140
configobj = self._get_configobj()
1142
section_obj = configobj
1145
section_obj = configobj[section]
1148
return section_obj.get(name, default)
1150
def set_option(self, value, name, section=None):
1151
"""Set the value associated with a named option.
1153
:param value: The value to set
1154
:param name: The name of the value to set
1155
:param section: The section the option is in (if any)
1157
configobj = self._get_configobj()
1159
configobj[name] = value
1161
configobj.setdefault(section, {})[name] = value
1162
self._set_configobj(configobj)
1164
def _get_configobj(self):
1166
return ConfigObj(self._transport.get(self._filename),
1168
except errors.NoSuchFile:
1169
return ConfigObj(encoding='utf-8')
1171
def _set_configobj(self, configobj):
1172
out_file = StringIO()
1173
configobj.write(out_file)
1175
self._transport.put_file(self._filename, out_file)