144
108
"""Get the users pop up editor."""
145
109
raise NotImplementedError
147
def get_mail_client(self):
148
"""Get a mail client to use"""
149
selected_client = self.get_user_option('mail_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,
165
raise errors.UnknownMailClient(selected_client)
166
return mail_client_class(self)
168
111
def _get_signature_checking(self):
169
112
"""Template method to override signature checking policy."""
457
362
def __init__(self, location):
458
363
name_generator = locations_config_filename
459
if (not os.path.exists(name_generator()) and
364
if (not os.path.exists(name_generator()) and
460
365
os.path.exists(branches_config_filename())):
461
366
if sys.platform == 'win32':
462
trace.warning('Please rename %s to %s'
463
% (branches_config_filename(),
464
locations_config_filename()))
367
warning('Please rename %s to %s'
368
% (branches_config_filename(),
369
locations_config_filename()))
466
trace.warning('Please rename ~/.bazaar/branches.conf'
467
' to ~/.bazaar/locations.conf')
371
warning('Please rename ~/.bazaar/branches.conf'
372
' to ~/.bazaar/locations.conf')
468
373
name_generator = branches_config_filename
469
374
super(LocationConfig, self).__init__(name_generator)
470
375
# local file locations are looked up by local path, rather than
505
415
# if section is longer, no match.
506
416
if len(section_names) > len(location_names):
508
matches.append((len(section_names), section,
509
'/'.join(location_names[len(section_names):])))
418
# if path is longer, and recurse is not true, no match
419
if len(section_names) < len(location_names):
421
if not self._get_parser()[section].as_bool('recurse'):
425
matches.append((len(section_names), section))
510
428
matches.sort(reverse=True)
512
for (length, section, extra_path) in matches:
513
sections.append((section, extra_path))
514
# should we stop looking for parent configs here?
516
if self._get_parser()[section].as_bool('ignore_parents'):
522
def _get_option_policy(self, section, option_name):
523
"""Return the policy for the given (section, option_name) pair."""
524
# check for the old 'recurse=False' flag
526
recurse = self._get_parser()[section].as_bool('recurse')
530
return POLICY_NORECURSE
532
policy_key = option_name + ':policy'
534
policy_name = self._get_parser()[section][policy_key]
538
return _policy_value[policy_name]
540
def _set_option_policy(self, section, option_name, option_policy):
541
"""Set the policy for the given option name in the given section."""
542
# The old recurse=False option affects all options in the
543
# section. To handle multiple policies in the section, we
544
# need to convert it to a policy_norecurse key.
546
recurse = self._get_parser()[section].as_bool('recurse')
550
symbol_versioning.warn(
551
'The recurse option is deprecated as of 0.14. '
552
'The section "%s" has been converted to use policies.'
555
del self._get_parser()[section]['recurse']
557
for key in self._get_parser()[section].keys():
558
if not key.endswith(':policy'):
559
self._get_parser()[section][key +
560
':policy'] = 'norecurse'
562
policy_key = option_name + ':policy'
563
policy_name = _policy_name[option_policy]
564
if policy_name is not None:
565
self._get_parser()[section][policy_key] = policy_name
567
if policy_key in self._get_parser()[section]:
568
del self._get_parser()[section][policy_key]
570
def set_user_option(self, option, value, store=STORE_LOCATION):
431
def set_user_option(self, option, value):
571
432
"""Save option and its value in the configuration."""
572
assert store in [STORE_LOCATION,
573
STORE_LOCATION_NORECURSE,
574
STORE_LOCATION_APPENDPATH], 'bad storage policy'
575
433
# FIXME: RBC 20051029 This should refresh the parser and also take a
576
434
# file lock on locations.conf.
577
435
conf_dir = os.path.dirname(self._get_filename())
670
def set_user_option(self, name, value, store=STORE_BRANCH,
672
if store == STORE_BRANCH:
526
def set_user_option(self, name, value, local=False):
528
self._get_location_config().set_user_option(name, value)
673
530
self._get_branch_data_config().set_option(value, name)
674
elif store == STORE_GLOBAL:
675
self._get_global_config().set_user_option(name, value)
677
self._get_location_config().set_user_option(name, value, store)
680
if store in (STORE_GLOBAL, STORE_BRANCH):
681
mask_value = self._get_location_config().get_user_option(name)
682
if mask_value is not None:
683
trace.warning('Value "%s" is masked by "%s" from'
684
' locations.conf', value, mask_value)
686
if store == STORE_GLOBAL:
687
branch_config = self._get_branch_data_config()
688
mask_value = branch_config.get_user_option(name)
689
if mask_value is not None:
690
trace.warning('Value "%s" is masked by "%s" from'
691
' branch.conf', value, mask_value)
694
533
def _gpg_signing_command(self):
755
594
base = os.environ.get('BZR_HOME', None)
756
595
if sys.platform == 'win32':
758
base = win32utils.get_appdata_location_unicode()
597
base = os.environ.get('APPDATA', None)
760
599
base = os.environ.get('HOME', None)
762
raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
764
return osutils.pathjoin(base, 'bazaar', '2.0')
601
raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
602
return pathjoin(base, 'bazaar', '2.0')
766
604
# cygwin, linux, and darwin all have a $HOME directory
768
606
base = os.path.expanduser("~")
769
return osutils.pathjoin(base, ".bazaar")
607
return pathjoin(base, ".bazaar")
772
610
def config_filename():
773
611
"""Return per-user configuration ini file filename."""
774
return osutils.pathjoin(config_dir(), 'bazaar.conf')
612
return pathjoin(config_dir(), 'bazaar.conf')
777
615
def branches_config_filename():
778
616
"""Return per-user configuration ini file filename."""
779
return osutils.pathjoin(config_dir(), 'branches.conf')
617
return pathjoin(config_dir(), 'branches.conf')
782
620
def locations_config_filename():
783
621
"""Return per-user configuration ini file filename."""
784
return osutils.pathjoin(config_dir(), 'locations.conf')
787
def authentication_config_filename():
788
"""Return per-user authentication ini file filename."""
789
return osutils.pathjoin(config_dir(), 'authentication.conf')
622
return pathjoin(config_dir(), 'locations.conf')
792
625
def user_ignore_config_filename():
793
626
"""Return the user default ignore filename"""
794
return osutils.pathjoin(config_dir(), 'ignore')
627
return pathjoin(config_dir(), 'ignore')
797
630
def _auto_user_id():
862
686
return realname, (username + '@' + socket.gethostname())
865
def parse_username(username):
866
"""Parse e-mail username and return a (name, address) tuple."""
867
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
869
return (username, '')
871
return (match.group(1), match.group(2))
874
689
def extract_email_address(e):
875
690
"""Return just the address part of an email string.
877
692
That is just the user@domain part, nothing else.
878
693
This part is required to contain only ascii characters.
879
694
If it can't be extracted, raises an error.
881
696
>>> extract_email_address('Jane Tester <jane@test.com>')
884
name, email = parse_username(e)
699
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
886
701
raise errors.NoEmailInUsername(e)
890
705
class TreeConfig(IniBasedConfig):
891
706
"""Branch configuration data associated with its contents, not location"""
893
707
def __init__(self, branch):
894
708
self.branch = branch
940
754
self.branch.control_files.put('branch.conf', out_file)
942
756
self.branch.unlock()
945
class AuthenticationConfig(object):
946
"""The authentication configuration file based on a ini file.
948
Implements the authentication.conf file described in
949
doc/developers/authentication-ring.txt.
952
def __init__(self, _file=None):
953
self._config = None # The ConfigObj
955
self._filename = authentication_config_filename()
956
self._input = self._filename = authentication_config_filename()
958
# Tests can provide a string as _file
959
self._filename = None
962
def _get_config(self):
963
if self._config is not None:
966
# FIXME: Should we validate something here ? Includes: empty
967
# sections are useless, at least one of
968
# user/password/password_encoding should be defined, etc.
970
# Note: the encoding below declares that the file itself is utf-8
971
# encoded, but the values in the ConfigObj are always Unicode.
972
self._config = ConfigObj(self._input, encoding='utf-8')
973
except configobj.ConfigObjError, e:
974
raise errors.ParseConfigError(e.errors, e.config.filename)
978
"""Save the config file, only tests should use it for now."""
979
conf_dir = os.path.dirname(self._filename)
980
ensure_config_dir_exists(conf_dir)
981
self._get_config().write(file(self._filename, 'wb'))
983
def _set_option(self, section_name, option_name, value):
984
"""Set an authentication configuration option"""
985
conf = self._get_config()
986
section = conf.get(section_name)
989
section = conf[section]
990
section[option_name] = value
993
def get_credentials(self, scheme, host, port=None, user=None, path=None):
994
"""Returns the matching credentials from authentication.conf file.
996
:param scheme: protocol
998
:param host: the server address
1000
:param port: the associated port (optional)
1002
:param user: login (optional)
1004
:param path: the absolute path on the server (optional)
1006
:return: A dict containing the matching credentials or None.
1008
- name: the section name of the credentials in the
1009
authentication.conf file,
1010
- user: can't de different from the provided user if any,
1011
- password: the decoded password, could be None if the credential
1012
defines only the user
1013
- verify_certificates: https specific, True if the server
1014
certificate should be verified, False otherwise.
1017
for auth_def_name, auth_def in self._get_config().items():
1018
a_scheme, a_host, a_user, a_path = map(
1019
auth_def.get, ['scheme', 'host', 'user', 'path'])
1022
a_port = auth_def.as_int('port')
1026
raise ValueError("'port' not numeric in %s" % auth_def_name)
1028
a_verify_certificates = auth_def.as_bool('verify_certificates')
1030
a_verify_certificates = True
1033
"'verify_certificates' not boolean in %s" % auth_def_name)
1036
if a_scheme is not None and scheme != a_scheme:
1038
if a_host is not None:
1039
if not (host == a_host
1040
or (a_host.startswith('.') and host.endswith(a_host))):
1042
if a_port is not None and port != a_port:
1044
if (a_path is not None and path is not None
1045
and not path.startswith(a_path)):
1047
if (a_user is not None and user is not None
1048
and a_user != user):
1049
# Never contradict the caller about the user to be used
1054
credentials = dict(name=auth_def_name,
1055
user=a_user, password=auth_def['password'],
1056
verify_certificates=a_verify_certificates)
1057
self.decode_password(credentials,
1058
auth_def.get('password_encoding', None))
1059
if 'auth' in debug.debug_flags:
1060
trace.mutter("Using authentication section: %r", auth_def_name)
1065
def get_user(self, scheme, host, port=None,
1066
realm=None, path=None, prompt=None):
1067
"""Get a user from authentication file.
1069
:param scheme: protocol
1071
:param host: the server address
1073
:param port: the associated port (optional)
1075
:param realm: the realm sent by the server (optional)
1077
:param path: the absolute path on the server (optional)
1079
:return: The found user.
1081
credentials = self.get_credentials(scheme, host, port, user=None,
1083
if credentials is not None:
1084
user = credentials['user']
1089
def get_password(self, scheme, host, user, port=None,
1090
realm=None, path=None, prompt=None):
1091
"""Get a password from authentication file or prompt the user for one.
1093
:param scheme: protocol
1095
:param host: the server address
1097
:param port: the associated port (optional)
1101
:param realm: the realm sent by the server (optional)
1103
:param path: the absolute path on the server (optional)
1105
:return: The found password or the one entered by the user.
1107
credentials = self.get_credentials(scheme, host, port, user, path)
1108
if credentials is not None:
1109
password = credentials['password']
1112
# Prompt user only if we could't find a password
1113
if password is None:
1115
# Create a default prompt suitable for most of the cases
1116
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1117
# Special handling for optional fields in the prompt
1118
if port is not None:
1119
prompt_host = '%s:%d' % (host, port)
1122
password = ui.ui_factory.get_password(prompt,
1123
host=prompt_host, user=user)
1126
def decode_password(self, credentials, encoding):