506
410
# if section is longer, no match.
507
411
if len(section_names) > len(location_names):
509
matches.append((len(section_names), section,
510
'/'.join(location_names[len(section_names):])))
413
# if path is longer, and recurse is not true, no match
414
if len(section_names) < len(location_names):
416
if not self._get_parser()[section].as_bool('recurse'):
420
matches.append((len(section_names), section))
511
423
matches.sort(reverse=True)
513
for (length, section, extra_path) in matches:
514
sections.append((section, extra_path))
515
# should we stop looking for parent configs here?
517
if self._get_parser()[section].as_bool('ignore_parents'):
523
def _get_option_policy(self, section, option_name):
524
"""Return the policy for the given (section, option_name) pair."""
525
# check for the old 'recurse=False' flag
527
recurse = self._get_parser()[section].as_bool('recurse')
531
return POLICY_NORECURSE
533
policy_key = option_name + ':policy'
535
policy_name = self._get_parser()[section][policy_key]
539
return _policy_value[policy_name]
541
def _set_option_policy(self, section, option_name, option_policy):
542
"""Set the policy for the given option name in the given section."""
543
# The old recurse=False option affects all options in the
544
# section. To handle multiple policies in the section, we
545
# need to convert it to a policy_norecurse key.
547
recurse = self._get_parser()[section].as_bool('recurse')
551
symbol_versioning.warn(
552
'The recurse option is deprecated as of 0.14. '
553
'The section "%s" has been converted to use policies.'
556
del self._get_parser()[section]['recurse']
558
for key in self._get_parser()[section].keys():
559
if not key.endswith(':policy'):
560
self._get_parser()[section][key +
561
':policy'] = 'norecurse'
563
policy_key = option_name + ':policy'
564
policy_name = _policy_name[option_policy]
565
if policy_name is not None:
566
self._get_parser()[section][policy_key] = policy_name
568
if policy_key in self._get_parser()[section]:
569
del self._get_parser()[section][policy_key]
571
def set_user_option(self, option, value, store=STORE_LOCATION):
426
def set_user_option(self, option, value):
572
427
"""Save option and its value in the configuration."""
573
if store not in [STORE_LOCATION,
574
STORE_LOCATION_NORECURSE,
575
STORE_LOCATION_APPENDPATH]:
576
raise ValueError('bad storage policy %r for %r' %
578
428
# FIXME: RBC 20051029 This should refresh the parser and also take a
579
429
# file lock on locations.conf.
580
430
conf_dir = os.path.dirname(self._get_filename())
757
589
base = os.environ.get('BZR_HOME', None)
758
590
if sys.platform == 'win32':
760
base = win32utils.get_appdata_location_unicode()
592
base = os.environ.get('APPDATA', None)
762
594
base = os.environ.get('HOME', None)
764
raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
766
return osutils.pathjoin(base, 'bazaar', '2.0')
596
raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
597
return pathjoin(base, 'bazaar', '2.0')
768
599
# cygwin, linux, and darwin all have a $HOME directory
770
601
base = os.path.expanduser("~")
771
return osutils.pathjoin(base, ".bazaar")
602
return pathjoin(base, ".bazaar")
774
605
def config_filename():
775
606
"""Return per-user configuration ini file filename."""
776
return osutils.pathjoin(config_dir(), 'bazaar.conf')
607
return pathjoin(config_dir(), 'bazaar.conf')
779
610
def branches_config_filename():
780
611
"""Return per-user configuration ini file filename."""
781
return osutils.pathjoin(config_dir(), 'branches.conf')
612
return pathjoin(config_dir(), 'branches.conf')
784
615
def locations_config_filename():
785
616
"""Return per-user configuration ini file filename."""
786
return osutils.pathjoin(config_dir(), 'locations.conf')
789
def authentication_config_filename():
790
"""Return per-user authentication ini file filename."""
791
return osutils.pathjoin(config_dir(), 'authentication.conf')
617
return pathjoin(config_dir(), 'locations.conf')
794
620
def user_ignore_config_filename():
795
621
"""Return the user default ignore filename"""
796
return osutils.pathjoin(config_dir(), 'ignore')
622
return pathjoin(config_dir(), 'ignore')
799
625
def _auto_user_id():
864
681
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
684
def extract_email_address(e):
877
685
"""Return just the address part of an email string.
879
687
That is just the user@domain part, nothing else.
880
688
This part is required to contain only ascii characters.
881
689
If it can't be extracted, raises an error.
883
691
>>> extract_email_address('Jane Tester <jane@test.com>')
886
name, email = parse_username(e)
888
raise errors.NoEmailInUsername(e)
694
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
696
raise errors.BzrError("%r doesn't seem to contain "
697
"a reasonable email address" % e)
892
701
class TreeConfig(IniBasedConfig):
893
702
"""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
703
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
704
self.branch = branch
904
706
def _get_parser(self, file=None):
905
707
if file is not None:
906
708
return IniBasedConfig._get_parser(file)
907
return self._config._get_configobj()
709
return self._get_config()
711
def _get_config(self):
713
obj = ConfigObj(self.branch.control_files.get('branch.conf'),
715
except errors.NoSuchFile:
716
obj = ConfigObj(encoding='utf=8')
909
719
def get_option(self, name, section=None, default=None):
910
720
self.branch.lock_read()
912
return self._config.get_option(name, section, default)
722
obj = self._get_config()
724
if section is not None:
914
730
self.branch.unlock()
918
734
"""Set a per-branch configuration option"""
919
735
self.branch.lock_write()
921
self._config.set_option(value, name, section)
737
cfg_obj = self._get_config()
742
obj = cfg_obj[section]
744
cfg_obj[section] = {}
745
obj = cfg_obj[section]
747
out_file = StringIO()
748
cfg_obj.write(out_file)
750
self.branch.control_files.put('branch.conf', out_file)
923
752
self.branch.unlock()
926
class AuthenticationConfig(object):
927
"""The authentication configuration file based on a ini file.
929
Implements the authentication.conf file described in
930
doc/developers/authentication-ring.txt.
933
def __init__(self, _file=None):
934
self._config = None # The ConfigObj
936
self._filename = authentication_config_filename()
937
self._input = self._filename = authentication_config_filename()
939
# Tests can provide a string as _file
940
self._filename = None
943
def _get_config(self):
944
if self._config is not None:
947
# FIXME: Should we validate something here ? Includes: empty
948
# sections are useless, at least one of
949
# user/password/password_encoding should be defined, etc.
951
# Note: the encoding below declares that the file itself is utf-8
952
# encoded, but the values in the ConfigObj are always Unicode.
953
self._config = ConfigObj(self._input, encoding='utf-8')
954
except configobj.ConfigObjError, e:
955
raise errors.ParseConfigError(e.errors, e.config.filename)
959
"""Save the config file, only tests should use it for now."""
960
conf_dir = os.path.dirname(self._filename)
961
ensure_config_dir_exists(conf_dir)
962
self._get_config().write(file(self._filename, 'wb'))
964
def _set_option(self, section_name, option_name, value):
965
"""Set an authentication configuration option"""
966
conf = self._get_config()
967
section = conf.get(section_name)
970
section = conf[section]
971
section[option_name] = value
974
def get_credentials(self, scheme, host, port=None, user=None, path=None):
975
"""Returns the matching credentials from authentication.conf file.
977
:param scheme: protocol
979
:param host: the server address
981
:param port: the associated port (optional)
983
:param user: login (optional)
985
:param path: the absolute path on the server (optional)
987
:return: A dict containing the matching credentials or None.
989
- name: the section name of the credentials in the
990
authentication.conf file,
991
- user: can't de different from the provided user if any,
992
- password: the decoded password, could be None if the credential
993
defines only the user
994
- verify_certificates: https specific, True if the server
995
certificate should be verified, False otherwise.
998
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
a_scheme, a_host, a_user, a_path = map(
1003
auth_def.get, ['scheme', 'host', 'user', 'path'])
1006
a_port = auth_def.as_int('port')
1010
raise ValueError("'port' not numeric in %s" % auth_def_name)
1012
a_verify_certificates = auth_def.as_bool('verify_certificates')
1014
a_verify_certificates = True
1017
"'verify_certificates' not boolean in %s" % auth_def_name)
1020
if a_scheme is not None and scheme != a_scheme:
1022
if a_host is not None:
1023
if not (host == a_host
1024
or (a_host.startswith('.') and host.endswith(a_host))):
1026
if a_port is not None and port != a_port:
1028
if (a_path is not None and path is not None
1029
and not path.startswith(a_path)):
1031
if (a_user is not None and user is not None
1032
and a_user != user):
1033
# Never contradict the caller about the user to be used
1038
credentials = dict(name=auth_def_name,
1040
password=auth_def.get('password', None),
1041
verify_certificates=a_verify_certificates)
1042
self.decode_password(credentials,
1043
auth_def.get('password_encoding', None))
1044
if 'auth' in debug.debug_flags:
1045
trace.mutter("Using authentication section: %r", auth_def_name)
1050
def get_user(self, scheme, host, port=None,
1051
realm=None, path=None, prompt=None):
1052
"""Get a user from authentication file.
1054
:param scheme: protocol
1056
:param host: the server address
1058
:param port: the associated port (optional)
1060
:param realm: the realm sent by the server (optional)
1062
:param path: the absolute path on the server (optional)
1064
:return: The found user.
1066
credentials = self.get_credentials(scheme, host, port, user=None,
1068
if credentials is not None:
1069
user = credentials['user']
1074
def get_password(self, scheme, host, user, port=None,
1075
realm=None, path=None, prompt=None):
1076
"""Get a password from authentication file or prompt the user for one.
1078
:param scheme: protocol
1080
:param host: the server address
1082
:param port: the associated port (optional)
1086
:param realm: the realm sent by the server (optional)
1088
:param path: the absolute path on the server (optional)
1090
:return: The found password or the one entered by the user.
1092
credentials = self.get_credentials(scheme, host, port, user, path)
1093
if credentials is not None:
1094
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'])
1102
# Prompt user only if we could't find a password
1103
if password is None:
1105
# Create a default prompt suitable for most cases
1106
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1107
# Special handling for optional fields in the prompt
1108
if port is not None:
1109
prompt_host = '%s:%d' % (host, port)
1112
password = ui.ui_factory.get_password(prompt,
1113
host=prompt_host, user=user)
1116
def decode_password(self, credentials, encoding):
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)