159
308
def _get_parser(self, file=None):
160
309
if self._parser is not None:
161
310
return self._parser
162
parser = ConfigParser()
166
parser.read([self._get_filename()])
167
self._parser = parser
312
input = self._get_filename()
316
self._parser = ConfigObj(input, encoding='utf-8')
317
except configobj.ConfigObjError, e:
318
raise errors.ParseConfigError(e.errors, e.config.filename)
321
def _get_matching_sections(self):
322
"""Return an ordered list of (section_name, extra_path) pairs.
324
If the section contains inherited configuration, extra_path is
325
a string containing the additional path components.
327
section = self._get_section()
328
if section is not None:
329
return [(section, '')]
170
333
def _get_section(self):
171
334
"""Override this to define the section used by the config."""
337
def _get_option_policy(self, section, option_name):
338
"""Return the policy for the given (section, option_name) pair."""
174
341
def _get_signature_checking(self):
175
342
"""See Config._get_signature_checking."""
176
section = self._get_section()
179
if self._get_parser().has_option(section, 'check_signatures'):
180
return self._string_to_signature_policy(
181
self._get_parser().get(section, 'check_signatures'))
343
policy = self._get_user_option('check_signatures')
345
return self._string_to_signature_policy(policy)
347
def _get_signing_policy(self):
348
"""See Config._get_signing_policy"""
349
policy = self._get_user_option('create_signatures')
351
return self._string_to_signing_policy(policy)
183
353
def _get_user_id(self):
184
354
"""Get the user id from the 'email' key in the current section."""
185
section = self._get_section()
186
if section is not None:
187
if self._get_parser().has_option(section, 'email'):
188
return self._get_parser().get(section, 'email')
355
return self._get_user_option('email')
190
357
def _get_user_option(self, option_name):
191
358
"""See Config._get_user_option."""
192
section = self._get_section()
193
if section is not None:
194
if self._get_parser().has_option(section, option_name):
195
return self._get_parser().get(section, option_name)
359
for (section, extra_path) in self._get_matching_sections():
361
value = self._get_parser().get_value(section, option_name)
364
policy = self._get_option_policy(section, option_name)
365
if policy == POLICY_NONE:
367
elif policy == POLICY_NORECURSE:
368
# norecurse items only apply to the exact path
373
elif policy == POLICY_APPENDPATH:
375
value = urlutils.join(value, extra_path)
378
raise AssertionError('Unexpected config policy %r' % policy)
197
382
def _gpg_signing_command(self):
198
383
"""See Config.gpg_signing_command."""
199
section = self._get_section()
200
if section is not None:
201
if self._get_parser().has_option(section, 'gpg_signing_command'):
202
return self._get_parser().get(section, 'gpg_signing_command')
384
return self._get_user_option('gpg_signing_command')
386
def _log_format(self):
387
"""See Config.log_format."""
388
return self._get_user_option('log_format')
204
390
def __init__(self, get_filename):
205
391
super(IniBasedConfig, self).__init__()
206
392
self._get_filename = get_filename
207
393
self._parser = None
395
def _post_commit(self):
396
"""See Config.post_commit."""
397
return self._get_user_option('post_commit')
209
399
def _string_to_signature_policy(self, signature_string):
210
400
"""Convert a string to a signing policy."""
217
407
raise errors.BzrError("Invalid signatures policy '%s'"
218
408
% signature_string)
410
def _string_to_signing_policy(self, signature_string):
411
"""Convert a string to a signing policy."""
412
if signature_string.lower() == 'when-required':
413
return SIGN_WHEN_REQUIRED
414
if signature_string.lower() == 'never':
416
if signature_string.lower() == 'always':
418
raise errors.BzrError("Invalid signing policy '%s'"
421
def _get_alias(self, value):
423
return self._get_parser().get_value("ALIASES",
428
def _get_nickname(self):
429
return self.get_user_option('nickname')
221
432
class GlobalConfig(IniBasedConfig):
222
433
"""The configuration that should be used for a specific location."""
224
435
def get_editor(self):
225
if self._get_parser().has_option(self._get_section(), 'editor'):
226
return self._get_parser().get(self._get_section(), 'editor')
436
return self._get_user_option('editor')
228
438
def __init__(self):
229
439
super(GlobalConfig, self).__init__(config_filename)
441
def set_user_option(self, option, value):
442
"""Save option and its value in the configuration."""
443
# FIXME: RBC 20051029 This should refresh the parser and also take a
444
# file lock on bazaar.conf.
445
conf_dir = os.path.dirname(self._get_filename())
446
ensure_config_dir_exists(conf_dir)
447
if 'DEFAULT' not in self._get_parser():
448
self._get_parser()['DEFAULT'] = {}
449
self._get_parser()['DEFAULT'][option] = value
450
f = open(self._get_filename(), 'wb')
451
self._get_parser().write(f)
232
455
class LocationConfig(IniBasedConfig):
233
456
"""A configuration object that gives the policy for a location."""
235
458
def __init__(self, location):
236
super(LocationConfig, self).__init__(branches_config_filename)
237
self._global_config = None
459
name_generator = locations_config_filename
460
if (not os.path.exists(name_generator()) and
461
os.path.exists(branches_config_filename())):
462
if sys.platform == 'win32':
463
trace.warning('Please rename %s to %s'
464
% (branches_config_filename(),
465
locations_config_filename()))
467
trace.warning('Please rename ~/.bazaar/branches.conf'
468
' to ~/.bazaar/locations.conf')
469
name_generator = branches_config_filename
470
super(LocationConfig, self).__init__(name_generator)
471
# local file locations are looked up by local path, rather than
472
# by file url. This is because the config file is a user
473
# file, and we would rather not expose the user to file urls.
474
if location.startswith('file://'):
475
location = urlutils.local_path_from_url(location)
238
476
self.location = location
240
def _get_global_config(self):
241
if self._global_config is None:
242
self._global_config = GlobalConfig()
243
return self._global_config
245
def _get_section(self):
246
"""Get the section we should look in for config items.
248
Returns None if none exists.
249
TODO: perhaps return a NullSection that thunks through to the
252
sections = self._get_parser().sections()
478
def _get_matching_sections(self):
479
"""Return an ordered list of section names matching this location."""
480
sections = self._get_parser()
253
481
location_names = self.location.split('/')
254
482
if self.location.endswith('/'):
255
483
del location_names[-1]
257
485
for section in sections:
258
section_names = section.split('/')
486
# location is a local path if possible, so we need
487
# to convert 'file://' urls to local paths if necessary.
488
# This also avoids having file:///path be a more exact
489
# match than '/path'.
490
if section.startswith('file://'):
491
section_path = urlutils.local_path_from_url(section)
493
section_path = section
494
section_names = section_path.split('/')
259
495
if section.endswith('/'):
260
496
del section_names[-1]
261
497
names = zip(location_names, section_names)
270
506
# if section is longer, no match.
271
507
if len(section_names) > len(location_names):
273
# if path is longer, and recurse is not true, no match
274
if len(section_names) < len(location_names):
275
if (self._get_parser().has_option(section, 'recurse')
276
and not self._get_parser().getboolean(section, 'recurse')):
278
matches.append((len(section_names), section))
509
matches.append((len(section_names), section,
510
'/'.join(location_names[len(section_names):])))
281
511
matches.sort(reverse=True)
284
def _gpg_signing_command(self):
285
"""See Config.gpg_signing_command."""
286
command = super(LocationConfig, self)._gpg_signing_command()
287
if command is not None:
289
return self._get_global_config()._gpg_signing_command()
291
def _get_user_id(self):
292
user_id = super(LocationConfig, self)._get_user_id()
293
if user_id is not None:
295
return self._get_global_config()._get_user_id()
297
def _get_user_option(self, option_name):
298
"""See Config._get_user_option."""
299
option_value = super(LocationConfig,
300
self)._get_user_option(option_name)
301
if option_value is not None:
303
return self._get_global_config()._get_user_option(option_name)
305
def _get_signature_checking(self):
306
"""See Config._get_signature_checking."""
307
check = super(LocationConfig, self)._get_signature_checking()
308
if check is not None:
310
return self._get_global_config()._get_signature_checking()
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):
572
"""Save option and its value in the configuration."""
573
assert store in [STORE_LOCATION,
574
STORE_LOCATION_NORECURSE,
575
STORE_LOCATION_APPENDPATH], 'bad storage policy'
576
# FIXME: RBC 20051029 This should refresh the parser and also take a
577
# file lock on locations.conf.
578
conf_dir = os.path.dirname(self._get_filename())
579
ensure_config_dir_exists(conf_dir)
580
location = self.location
581
if location.endswith('/'):
582
location = location[:-1]
583
if (not location in self._get_parser() and
584
not location + '/' in self._get_parser()):
585
self._get_parser()[location]={}
586
elif location + '/' in self._get_parser():
587
location = location + '/'
588
self._get_parser()[location][option]=value
589
# the allowed values of store match the config policies
590
self._set_option_policy(location, option, store)
591
self._get_parser().write(file(self._get_filename(), 'wb'))
313
594
class BranchConfig(Config):
314
595
"""A configuration object giving the policy for a branch."""
597
def _get_branch_data_config(self):
598
if self._branch_data_config is None:
599
self._branch_data_config = TreeConfig(self.branch)
600
return self._branch_data_config
316
602
def _get_location_config(self):
317
603
if self._location_config is None:
318
604
self._location_config = LocationConfig(self.branch.base)
319
605
return self._location_config
607
def _get_global_config(self):
608
if self._global_config is None:
609
self._global_config = GlobalConfig()
610
return self._global_config
612
def _get_best_value(self, option_name):
613
"""This returns a user option from local, tree or global config.
615
They are tried in that order. Use get_safe_value if trusted values
618
for source in self.option_sources:
619
value = getattr(source(), option_name)()
620
if value is not None:
624
def _get_safe_value(self, option_name):
625
"""This variant of get_best_value never returns untrusted values.
627
It does not return values from the branch data, because the branch may
628
not be controlled by the user.
630
We may wish to allow locations.conf to control whether branches are
631
trusted in the future.
633
for source in (self._get_location_config, self._get_global_config):
634
value = getattr(source(), option_name)()
635
if value is not None:
321
639
def _get_user_id(self):
322
640
"""Return the full user id for the branch.
325
643
This is looked up in the email controlfile for the branch.
328
return (self.branch.controlfile("email", "r")
646
return (self.branch.control_files.get_utf8("email")
330
648
.decode(bzrlib.user_encoding)
332
650
except errors.NoSuchFile, e:
335
return self._get_location_config()._get_user_id()
653
return self._get_best_value('_get_user_id')
337
655
def _get_signature_checking(self):
338
656
"""See Config._get_signature_checking."""
339
return self._get_location_config()._get_signature_checking()
657
return self._get_best_value('_get_signature_checking')
659
def _get_signing_policy(self):
660
"""See Config._get_signing_policy."""
661
return self._get_best_value('_get_signing_policy')
341
663
def _get_user_option(self, option_name):
342
664
"""See Config._get_user_option."""
343
return self._get_location_config()._get_user_option(option_name)
665
for source in self.option_sources:
666
value = source()._get_user_option(option_name)
667
if value is not None:
671
def set_user_option(self, name, value, store=STORE_BRANCH,
673
if store == STORE_BRANCH:
674
self._get_branch_data_config().set_option(value, name)
675
elif store == STORE_GLOBAL:
676
self._get_global_config().set_user_option(name, value)
678
self._get_location_config().set_user_option(name, value, store)
681
if store in (STORE_GLOBAL, STORE_BRANCH):
682
mask_value = self._get_location_config().get_user_option(name)
683
if mask_value is not None:
684
trace.warning('Value "%s" is masked by "%s" from'
685
' locations.conf', value, mask_value)
687
if store == STORE_GLOBAL:
688
branch_config = self._get_branch_data_config()
689
mask_value = branch_config.get_user_option(name)
690
if mask_value is not None:
691
trace.warning('Value "%s" is masked by "%s" from'
692
' branch.conf', value, mask_value)
345
695
def _gpg_signing_command(self):
346
696
"""See Config.gpg_signing_command."""
347
return self._get_location_config()._gpg_signing_command()
697
return self._get_safe_value('_gpg_signing_command')
349
699
def __init__(self, branch):
350
700
super(BranchConfig, self).__init__()
351
701
self._location_config = None
702
self._branch_data_config = None
703
self._global_config = None
352
704
self.branch = branch
705
self.option_sources = (self._get_location_config,
706
self._get_branch_data_config,
707
self._get_global_config)
709
def _post_commit(self):
710
"""See Config.post_commit."""
711
return self._get_safe_value('_post_commit')
713
def _get_nickname(self):
714
value = self._get_explicit_nickname()
715
if value is not None:
717
return urlutils.unescape(self.branch.base.split('/')[-2])
719
def has_explicit_nickname(self):
720
"""Return true if a nickname has been explicitly assigned."""
721
return self._get_explicit_nickname() is not None
723
def _get_explicit_nickname(self):
724
return self._get_best_value('_get_nickname')
726
def _log_format(self):
727
"""See Config.log_format."""
728
return self._get_best_value('_log_format')
731
def ensure_config_dir_exists(path=None):
732
"""Make sure a configuration directory exists.
733
This makes sure that the directory exists.
734
On windows, since configuration directories are 2 levels deep,
735
it makes sure both the directory and the parent directory exists.
739
if not os.path.isdir(path):
740
if sys.platform == 'win32':
741
parent_dir = os.path.dirname(path)
742
if not os.path.isdir(parent_dir):
743
trace.mutter('creating config parent directory: %r', parent_dir)
745
trace.mutter('creating config directory: %r', path)
355
749
def config_dir():
404
855
except ImportError:
406
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
858
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
859
except UnicodeDecodeError:
860
raise errors.BzrError("Can't decode username as %s." % \
861
bzrlib.user_encoding)
408
863
return realname, (username + '@' + socket.gethostname())
866
def parse_username(username):
867
"""Parse e-mail username and return a (name, address) tuple."""
868
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
870
return (username, '')
872
return (match.group(1), match.group(2))
411
875
def extract_email_address(e):
412
876
"""Return just the address part of an email string.
414
878
That is just the user@domain part, nothing else.
415
879
This part is required to contain only ascii characters.
416
880
If it can't be extracted, raises an error.
418
882
>>> extract_email_address('Jane Tester <jane@test.com>')
421
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
423
raise BzrError("%r doesn't seem to contain "
424
"a reasonable email address" % e)
885
name, email = parse_username(e)
887
raise errors.NoEmailInUsername(e)
891
class TreeConfig(IniBasedConfig):
892
"""Branch configuration data associated with its contents, not location"""
894
def __init__(self, branch):
895
transport = branch.control_files._transport
896
self._config = TransportConfig(transport, 'branch.conf')
899
def _get_parser(self, file=None):
901
return IniBasedConfig._get_parser(file)
902
return self._config._get_configobj()
904
def get_option(self, name, section=None, default=None):
905
self.branch.lock_read()
907
return self._config.get_option(name, section, default)
912
def set_option(self, value, name, section=None):
913
"""Set a per-branch configuration option"""
914
self.branch.lock_write()
916
self._config.set_option(value, name, section)
921
class AuthenticationConfig(object):
922
"""The authentication configuration file based on a ini file.
924
Implements the authentication.conf file described in
925
doc/developers/authentication-ring.txt.
928
def __init__(self, _file=None):
929
self._config = None # The ConfigObj
931
self._filename = authentication_config_filename()
932
self._input = self._filename = authentication_config_filename()
934
# Tests can provide a string as _file
935
self._filename = None
938
def _get_config(self):
939
if self._config is not None:
942
# FIXME: Should we validate something here ? Includes: empty
943
# sections are useless, at least one of
944
# user/password/password_encoding should be defined, etc.
946
# Note: the encoding below declares that the file itself is utf-8
947
# encoded, but the values in the ConfigObj are always Unicode.
948
self._config = ConfigObj(self._input, encoding='utf-8')
949
except configobj.ConfigObjError, e:
950
raise errors.ParseConfigError(e.errors, e.config.filename)
954
"""Save the config file, only tests should use it for now."""
955
conf_dir = os.path.dirname(self._filename)
956
ensure_config_dir_exists(conf_dir)
957
self._get_config().write(file(self._filename, 'wb'))
959
def _set_option(self, section_name, option_name, value):
960
"""Set an authentication configuration option"""
961
conf = self._get_config()
962
section = conf.get(section_name)
965
section = conf[section]
966
section[option_name] = value
969
def get_credentials(self, scheme, host, port=None, user=None, path=None):
970
"""Returns the matching credentials from authentication.conf file.
972
:param scheme: protocol
974
:param host: the server address
976
:param port: the associated port (optional)
978
:param user: login (optional)
980
:param path: the absolute path on the server (optional)
982
:return: A dict containing the matching credentials or None.
984
- name: the section name of the credentials in the
985
authentication.conf file,
986
- user: can't de different from the provided user if any,
987
- password: the decoded password, could be None if the credential
988
defines only the user
989
- verify_certificates: https specific, True if the server
990
certificate should be verified, False otherwise.
993
for auth_def_name, auth_def in self._get_config().items():
994
a_scheme, a_host, a_user, a_path = map(
995
auth_def.get, ['scheme', 'host', 'user', 'path'])
998
a_port = auth_def.as_int('port')
1002
raise ValueError("'port' not numeric in %s" % auth_def_name)
1004
a_verify_certificates = auth_def.as_bool('verify_certificates')
1006
a_verify_certificates = True
1009
"'verify_certificates' not boolean in %s" % auth_def_name)
1012
if a_scheme is not None and scheme != a_scheme:
1014
if a_host is not None:
1015
if not (host == a_host
1016
or (a_host.startswith('.') and host.endswith(a_host))):
1018
if a_port is not None and port != a_port:
1020
if (a_path is not None and path is not None
1021
and not path.startswith(a_path)):
1023
if (a_user is not None and user is not None
1024
and a_user != user):
1025
# Never contradict the caller about the user to be used
1030
credentials = dict(name=auth_def_name,
1031
user=a_user, password=auth_def['password'],
1032
verify_certificates=a_verify_certificates)
1033
self.decode_password(credentials,
1034
auth_def.get('password_encoding', None))
1035
if 'auth' in debug.debug_flags:
1036
trace.mutter("Using authentication section: %r", auth_def_name)
1041
def get_user(self, scheme, host, port=None,
1042
realm=None, path=None, prompt=None):
1043
"""Get a user from authentication file.
1045
:param scheme: protocol
1047
:param host: the server address
1049
:param port: the associated port (optional)
1051
:param realm: the realm sent by the server (optional)
1053
:param path: the absolute path on the server (optional)
1055
:return: The found user.
1057
credentials = self.get_credentials(scheme, host, port, user=None,
1059
if credentials is not None:
1060
user = credentials['user']
1065
def get_password(self, scheme, host, user, port=None,
1066
realm=None, path=None, prompt=None):
1067
"""Get a password from authentication file or prompt the user for one.
1069
:param scheme: protocol
1071
:param host: the server address
1073
:param port: the associated port (optional)
1077
:param realm: the realm sent by the server (optional)
1079
:param path: the absolute path on the server (optional)
1081
:return: The found password or the one entered by the user.
1083
credentials = self.get_credentials(scheme, host, port, user, path)
1084
if credentials is not None:
1085
password = credentials['password']
1088
# Prompt user only if we could't find a password
1089
if password is None:
1091
# Create a default prompt suitable for most of the cases
1092
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1093
# Special handling for optional fields in the prompt
1094
if port is not None:
1095
prompt_host = '%s:%d' % (host, port)
1098
password = ui.ui_factory.get_password(prompt,
1099
host=prompt_host, user=user)
1102
def decode_password(self, credentials, encoding):
1106
class TransportConfig(object):
1107
"""A Config that reads/writes a config file on a Transport.
1109
It is a low-level object that considers config data to be name/value pairs
1110
that may be associated with a section. Assigning meaning to the these
1111
values is done at higher levels like TreeConfig.
1114
def __init__(self, transport, filename):
1115
self._transport = transport
1116
self._filename = filename
1118
def get_option(self, name, section=None, default=None):
1119
"""Return the value associated with a named option.
1121
:param name: The name of the value
1122
:param section: The section the option is in (if any)
1123
:param default: The value to return if the value is not set
1124
:return: The value or default value
1126
configobj = self._get_configobj()
1128
section_obj = configobj
1131
section_obj = configobj[section]
1134
return section_obj.get(name, default)
1136
def set_option(self, value, name, section=None):
1137
"""Set the value associated with a named option.
1139
:param value: The value to set
1140
:param name: The name of the value to set
1141
:param section: The section the option is in (if any)
1143
configobj = self._get_configobj()
1145
configobj[name] = value
1147
configobj.setdefault(section, {})[name] = value
1148
self._set_configobj(configobj)
1150
def _get_configobj(self):
1152
return ConfigObj(self._transport.get(self._filename),
1154
except errors.NoSuchFile:
1155
return ConfigObj(encoding='utf-8')
1157
def _set_configobj(self, configobj):
1158
out_file = StringIO()
1159
configobj.write(out_file)
1161
self._transport.put_file(self._filename, out_file)