289
432
def __init__(self):
290
433
super(GlobalConfig, self).__init__(config_filename)
435
def set_user_option(self, option, value):
436
"""Save option and its value in the configuration."""
437
self._set_option(option, value, 'DEFAULT')
439
def get_aliases(self):
440
"""Return the aliases section."""
441
if 'ALIASES' in self._get_parser():
442
return self._get_parser()['ALIASES']
446
def set_alias(self, alias_name, alias_command):
447
"""Save the alias in the configuration."""
448
self._set_option(alias_name, alias_command, 'ALIASES')
450
def unset_alias(self, alias_name):
451
"""Unset an existing alias."""
452
aliases = self._get_parser().get('ALIASES')
453
if not aliases or alias_name not in aliases:
454
raise errors.NoSuchAlias(alias_name)
455
del aliases[alias_name]
456
self._write_config_file()
458
def _set_option(self, option, value, section):
459
# FIXME: RBC 20051029 This should refresh the parser and also take a
460
# file lock on bazaar.conf.
461
conf_dir = os.path.dirname(self._get_filename())
462
ensure_config_dir_exists(conf_dir)
463
self._get_parser().setdefault(section, {})[option] = value
464
self._write_config_file()
466
def _write_config_file(self):
467
f = open(self._get_filename(), 'wb')
468
self._get_parser().write(f)
293
472
class LocationConfig(IniBasedConfig):
294
473
"""A configuration object that gives the policy for a location."""
296
475
def __init__(self, location):
297
super(LocationConfig, self).__init__(branches_config_filename)
298
self._global_config = None
476
name_generator = locations_config_filename
477
if (not os.path.exists(name_generator()) and
478
os.path.exists(branches_config_filename())):
479
if sys.platform == 'win32':
480
trace.warning('Please rename %s to %s'
481
% (branches_config_filename(),
482
locations_config_filename()))
484
trace.warning('Please rename ~/.bazaar/branches.conf'
485
' to ~/.bazaar/locations.conf')
486
name_generator = branches_config_filename
487
super(LocationConfig, self).__init__(name_generator)
488
# local file locations are looked up by local path, rather than
489
# by file url. This is because the config file is a user
490
# file, and we would rather not expose the user to file urls.
491
if location.startswith('file://'):
492
location = urlutils.local_path_from_url(location)
299
493
self.location = location
301
def _get_global_config(self):
302
if self._global_config is None:
303
self._global_config = GlobalConfig()
304
return self._global_config
306
def _get_section(self):
307
"""Get the section we should look in for config items.
309
Returns None if none exists.
310
TODO: perhaps return a NullSection that thunks through to the
495
def _get_matching_sections(self):
496
"""Return an ordered list of section names matching this location."""
313
497
sections = self._get_parser()
314
498
location_names = self.location.split('/')
315
499
if self.location.endswith('/'):
316
500
del location_names[-1]
318
502
for section in sections:
319
section_names = section.split('/')
503
# location is a local path if possible, so we need
504
# to convert 'file://' urls to local paths if necessary.
505
# This also avoids having file:///path be a more exact
506
# match than '/path'.
507
if section.startswith('file://'):
508
section_path = urlutils.local_path_from_url(section)
510
section_path = section
511
section_names = section_path.split('/')
320
512
if section.endswith('/'):
321
513
del section_names[-1]
322
514
names = zip(location_names, section_names)
331
523
# if section is longer, no match.
332
524
if len(section_names) > len(location_names):
334
# if path is longer, and recurse is not true, no match
335
if len(section_names) < len(location_names):
337
if not self._get_parser()[section].as_bool('recurse'):
341
matches.append((len(section_names), section))
526
matches.append((len(section_names), section,
527
'/'.join(location_names[len(section_names):])))
344
528
matches.sort(reverse=True)
347
def _gpg_signing_command(self):
348
"""See Config.gpg_signing_command."""
349
command = super(LocationConfig, self)._gpg_signing_command()
350
if command is not None:
352
return self._get_global_config()._gpg_signing_command()
354
def _log_format(self):
355
"""See Config.log_format."""
356
command = super(LocationConfig, self)._log_format()
357
if command is not None:
359
return self._get_global_config()._log_format()
361
def _get_user_id(self):
362
user_id = super(LocationConfig, self)._get_user_id()
363
if user_id is not None:
365
return self._get_global_config()._get_user_id()
367
def _get_user_option(self, option_name):
368
"""See Config._get_user_option."""
369
option_value = super(LocationConfig,
370
self)._get_user_option(option_name)
371
if option_value is not None:
373
return self._get_global_config()._get_user_option(option_name)
375
def _get_signature_checking(self):
376
"""See Config._get_signature_checking."""
377
check = super(LocationConfig, self)._get_signature_checking()
378
if check is not None:
380
return self._get_global_config()._get_signature_checking()
382
def _post_commit(self):
383
"""See Config.post_commit."""
384
hook = self._get_user_option('post_commit')
387
return self._get_global_config()._post_commit()
389
def set_user_option(self, option, value):
530
for (length, section, extra_path) in matches:
531
sections.append((section, extra_path))
532
# should we stop looking for parent configs here?
534
if self._get_parser()[section].as_bool('ignore_parents'):
540
def _get_option_policy(self, section, option_name):
541
"""Return the policy for the given (section, option_name) pair."""
542
# check for the old 'recurse=False' flag
544
recurse = self._get_parser()[section].as_bool('recurse')
548
return POLICY_NORECURSE
550
policy_key = option_name + ':policy'
552
policy_name = self._get_parser()[section][policy_key]
556
return _policy_value[policy_name]
558
def _set_option_policy(self, section, option_name, option_policy):
559
"""Set the policy for the given option name in the given section."""
560
# The old recurse=False option affects all options in the
561
# section. To handle multiple policies in the section, we
562
# need to convert it to a policy_norecurse key.
564
recurse = self._get_parser()[section].as_bool('recurse')
568
symbol_versioning.warn(
569
'The recurse option is deprecated as of 0.14. '
570
'The section "%s" has been converted to use policies.'
573
del self._get_parser()[section]['recurse']
575
for key in self._get_parser()[section].keys():
576
if not key.endswith(':policy'):
577
self._get_parser()[section][key +
578
':policy'] = 'norecurse'
580
policy_key = option_name + ':policy'
581
policy_name = _policy_name[option_policy]
582
if policy_name is not None:
583
self._get_parser()[section][policy_key] = policy_name
585
if policy_key in self._get_parser()[section]:
586
del self._get_parser()[section][policy_key]
588
def set_user_option(self, option, value, store=STORE_LOCATION):
390
589
"""Save option and its value in the configuration."""
590
if store not in [STORE_LOCATION,
591
STORE_LOCATION_NORECURSE,
592
STORE_LOCATION_APPENDPATH]:
593
raise ValueError('bad storage policy %r for %r' %
391
595
# FIXME: RBC 20051029 This should refresh the parser and also take a
392
# file lock on branches.conf.
596
# file lock on locations.conf.
393
597
conf_dir = os.path.dirname(self._get_filename())
394
598
ensure_config_dir_exists(conf_dir)
395
599
location = self.location
401
605
elif location + '/' in self._get_parser():
402
606
location = location + '/'
403
607
self._get_parser()[location][option]=value
608
# the allowed values of store match the config policies
609
self._set_option_policy(location, option, store)
404
610
self._get_parser().write(file(self._get_filename(), 'wb'))
407
613
class BranchConfig(Config):
408
614
"""A configuration object giving the policy for a branch."""
616
def _get_branch_data_config(self):
617
if self._branch_data_config is None:
618
self._branch_data_config = TreeConfig(self.branch)
619
return self._branch_data_config
410
621
def _get_location_config(self):
411
622
if self._location_config is None:
412
623
self._location_config = LocationConfig(self.branch.base)
413
624
return self._location_config
626
def _get_global_config(self):
627
if self._global_config is None:
628
self._global_config = GlobalConfig()
629
return self._global_config
631
def _get_best_value(self, option_name):
632
"""This returns a user option from local, tree or global config.
634
They are tried in that order. Use get_safe_value if trusted values
637
for source in self.option_sources:
638
value = getattr(source(), option_name)()
639
if value is not None:
643
def _get_safe_value(self, option_name):
644
"""This variant of get_best_value never returns untrusted values.
646
It does not return values from the branch data, because the branch may
647
not be controlled by the user.
649
We may wish to allow locations.conf to control whether branches are
650
trusted in the future.
652
for source in (self._get_location_config, self._get_global_config):
653
value = getattr(source(), option_name)()
654
if value is not None:
415
658
def _get_user_id(self):
416
659
"""Return the full user id for the branch.
418
e.g. "John Hacker <jhacker@foo.org>"
661
e.g. "John Hacker <jhacker@example.com>"
419
662
This is looked up in the email controlfile for the branch.
422
return (self.branch.control_files.get_utf8("email")
424
.decode(bzrlib.user_encoding)
665
return (self.branch._transport.get_bytes("email")
666
.decode(osutils.get_user_encoding())
426
668
except errors.NoSuchFile, e:
429
return self._get_location_config()._get_user_id()
671
return self._get_best_value('_get_user_id')
431
673
def _get_signature_checking(self):
432
674
"""See Config._get_signature_checking."""
433
return self._get_location_config()._get_signature_checking()
675
return self._get_best_value('_get_signature_checking')
677
def _get_signing_policy(self):
678
"""See Config._get_signing_policy."""
679
return self._get_best_value('_get_signing_policy')
435
681
def _get_user_option(self, option_name):
436
682
"""See Config._get_user_option."""
437
return self._get_location_config()._get_user_option(option_name)
683
for source in self.option_sources:
684
value = source()._get_user_option(option_name)
685
if value is not None:
689
def set_user_option(self, name, value, store=STORE_BRANCH,
691
if store == STORE_BRANCH:
692
self._get_branch_data_config().set_option(value, name)
693
elif store == STORE_GLOBAL:
694
self._get_global_config().set_user_option(name, value)
696
self._get_location_config().set_user_option(name, value, store)
699
if store in (STORE_GLOBAL, STORE_BRANCH):
700
mask_value = self._get_location_config().get_user_option(name)
701
if mask_value is not None:
702
trace.warning('Value "%s" is masked by "%s" from'
703
' locations.conf', value, mask_value)
705
if store == STORE_GLOBAL:
706
branch_config = self._get_branch_data_config()
707
mask_value = branch_config.get_user_option(name)
708
if mask_value is not None:
709
trace.warning('Value "%s" is masked by "%s" from'
710
' branch.conf', value, mask_value)
439
713
def _gpg_signing_command(self):
440
714
"""See Config.gpg_signing_command."""
441
return self._get_location_config()._gpg_signing_command()
715
return self._get_safe_value('_gpg_signing_command')
443
717
def __init__(self, branch):
444
718
super(BranchConfig, self).__init__()
445
719
self._location_config = None
720
self._branch_data_config = None
721
self._global_config = None
446
722
self.branch = branch
723
self.option_sources = (self._get_location_config,
724
self._get_branch_data_config,
725
self._get_global_config)
448
727
def _post_commit(self):
449
728
"""See Config.post_commit."""
450
return self._get_location_config()._post_commit()
729
return self._get_safe_value('_post_commit')
731
def _get_nickname(self):
732
value = self._get_explicit_nickname()
733
if value is not None:
735
return urlutils.unescape(self.branch.base.split('/')[-2])
737
def has_explicit_nickname(self):
738
"""Return true if a nickname has been explicitly assigned."""
739
return self._get_explicit_nickname() is not None
741
def _get_explicit_nickname(self):
742
return self._get_best_value('_get_nickname')
452
744
def _log_format(self):
453
745
"""See Config.log_format."""
454
return self._get_location_config()._log_format()
746
return self._get_best_value('_log_format')
457
749
def ensure_config_dir_exists(path=None):
599
940
"""Set a per-branch configuration option"""
600
941
self.branch.lock_write()
602
cfg_obj = self._get_config()
607
obj = cfg_obj[section]
609
cfg_obj[section] = {}
610
obj = cfg_obj[section]
612
out_file = StringIO()
613
cfg_obj.write(out_file)
615
self.branch.control_files.put('branch.conf', out_file)
943
self._config.set_option(value, name, section)
617
945
self.branch.unlock()
948
class AuthenticationConfig(object):
949
"""The authentication configuration file based on a ini file.
951
Implements the authentication.conf file described in
952
doc/developers/authentication-ring.txt.
955
def __init__(self, _file=None):
956
self._config = None # The ConfigObj
958
self._filename = authentication_config_filename()
959
self._input = self._filename = authentication_config_filename()
961
# Tests can provide a string as _file
962
self._filename = None
965
def _get_config(self):
966
if self._config is not None:
969
# FIXME: Should we validate something here ? Includes: empty
970
# sections are useless, at least one of
971
# user/password/password_encoding should be defined, etc.
973
# Note: the encoding below declares that the file itself is utf-8
974
# encoded, but the values in the ConfigObj are always Unicode.
975
self._config = ConfigObj(self._input, encoding='utf-8')
976
except configobj.ConfigObjError, e:
977
raise errors.ParseConfigError(e.errors, e.config.filename)
981
"""Save the config file, only tests should use it for now."""
982
conf_dir = os.path.dirname(self._filename)
983
ensure_config_dir_exists(conf_dir)
984
self._get_config().write(file(self._filename, 'wb'))
986
def _set_option(self, section_name, option_name, value):
987
"""Set an authentication configuration option"""
988
conf = self._get_config()
989
section = conf.get(section_name)
992
section = conf[section]
993
section[option_name] = value
996
def get_credentials(self, scheme, host, port=None, user=None, path=None,
998
"""Returns the matching credentials from authentication.conf file.
1000
:param scheme: protocol
1002
:param host: the server address
1004
:param port: the associated port (optional)
1006
:param user: login (optional)
1008
:param path: the absolute path on the server (optional)
1010
:param realm: the http authentication realm (optional)
1012
:return: A dict containing the matching credentials or None.
1014
- name: the section name of the credentials in the
1015
authentication.conf file,
1016
- user: can't be different from the provided user if any,
1017
- scheme: the server protocol,
1018
- host: the server address,
1019
- port: the server port (can be None),
1020
- path: the absolute server path (can be None),
1021
- realm: the http specific authentication realm (can be None),
1022
- password: the decoded password, could be None if the credential
1023
defines only the user
1024
- verify_certificates: https specific, True if the server
1025
certificate should be verified, False otherwise.
1028
for auth_def_name, auth_def in self._get_config().items():
1029
if type(auth_def) is not configobj.Section:
1030
raise ValueError("%s defined outside a section" % auth_def_name)
1032
a_scheme, a_host, a_user, a_path = map(
1033
auth_def.get, ['scheme', 'host', 'user', 'path'])
1036
a_port = auth_def.as_int('port')
1040
raise ValueError("'port' not numeric in %s" % auth_def_name)
1042
a_verify_certificates = auth_def.as_bool('verify_certificates')
1044
a_verify_certificates = True
1047
"'verify_certificates' not boolean in %s" % auth_def_name)
1050
if a_scheme is not None and scheme != a_scheme:
1052
if a_host is not None:
1053
if not (host == a_host
1054
or (a_host.startswith('.') and host.endswith(a_host))):
1056
if a_port is not None and port != a_port:
1058
if (a_path is not None and path is not None
1059
and not path.startswith(a_path)):
1061
if (a_user is not None and user is not None
1062
and a_user != user):
1063
# Never contradict the caller about the user to be used
1068
# Prepare a credentials dictionary with additional keys
1069
# for the credential providers
1070
credentials = dict(name=auth_def_name,
1077
password=auth_def.get('password', None),
1078
verify_certificates=a_verify_certificates)
1079
# Decode the password in the credentials (or get one)
1080
self.decode_password(credentials,
1081
auth_def.get('password_encoding', None))
1082
if 'auth' in debug.debug_flags:
1083
trace.mutter("Using authentication section: %r", auth_def_name)
1088
def set_credentials(self, name, host, user, scheme=None, password=None,
1089
port=None, path=None, verify_certificates=None,
1091
"""Set authentication credentials for a host.
1093
Any existing credentials with matching scheme, host, port and path
1094
will be deleted, regardless of name.
1096
:param name: An arbitrary name to describe this set of credentials.
1097
:param host: Name of the host that accepts these credentials.
1098
:param user: The username portion of these credentials.
1099
:param scheme: The URL scheme (e.g. ssh, http) the credentials apply
1101
:param password: Password portion of these credentials.
1102
:param port: The IP port on the host that these credentials apply to.
1103
:param path: A filesystem path on the host that these credentials
1105
:param verify_certificates: On https, verify server certificates if
1107
:param realm: The http authentication realm (optional).
1109
values = {'host': host, 'user': user}
1110
if password is not None:
1111
values['password'] = password
1112
if scheme is not None:
1113
values['scheme'] = scheme
1114
if port is not None:
1115
values['port'] = '%d' % port
1116
if path is not None:
1117
values['path'] = path
1118
if verify_certificates is not None:
1119
values['verify_certificates'] = str(verify_certificates)
1120
if realm is not None:
1121
values['realm'] = realm
1122
config = self._get_config()
1124
for section, existing_values in config.items():
1125
for key in ('scheme', 'host', 'port', 'path', 'realm'):
1126
if existing_values.get(key) != values.get(key):
1130
config.update({name: values})
1133
def get_user(self, scheme, host, port=None,
1134
realm=None, path=None, prompt=None):
1135
"""Get a user from authentication file.
1137
:param scheme: protocol
1139
:param host: the server address
1141
:param port: the associated port (optional)
1143
:param realm: the realm sent by the server (optional)
1145
:param path: the absolute path on the server (optional)
1147
:return: The found user.
1149
credentials = self.get_credentials(scheme, host, port, user=None,
1150
path=path, realm=realm)
1151
if credentials is not None:
1152
user = credentials['user']
1157
def get_password(self, scheme, host, user, port=None,
1158
realm=None, path=None, prompt=None):
1159
"""Get a password from authentication file or prompt the user for one.
1161
:param scheme: protocol
1163
:param host: the server address
1165
:param port: the associated port (optional)
1169
:param realm: the realm sent by the server (optional)
1171
:param path: the absolute path on the server (optional)
1173
:return: The found password or the one entered by the user.
1175
credentials = self.get_credentials(scheme, host, port, user, path,
1177
if credentials is not None:
1178
password = credentials['password']
1179
if password is not None and scheme is 'ssh':
1180
trace.warning('password ignored in section [%s],'
1181
' use an ssh agent instead'
1182
% credentials['name'])
1186
# Prompt user only if we could't find a password
1187
if password is None:
1189
# Create a default prompt suitable for most cases
1190
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1191
# Special handling for optional fields in the prompt
1192
if port is not None:
1193
prompt_host = '%s:%d' % (host, port)
1196
password = ui.ui_factory.get_password(prompt,
1197
host=prompt_host, user=user)
1200
def decode_password(self, credentials, encoding):
1202
cs = credential_store_registry.get_credential_store(encoding)
1204
raise ValueError('%r is not a known password_encoding' % encoding)
1205
credentials['password'] = cs.decode_password(credentials)
1209
class CredentialStoreRegistry(registry.Registry):
1210
"""A class that registers credential stores.
1212
A credential store provides access to credentials via the password_encoding
1213
field in authentication.conf sections.
1215
Except for stores provided by bzr itself,most stores are expected to be
1216
provided by plugins that will therefore use
1217
register_lazy(password_encoding, module_name, member_name, help=help,
1218
info=info) to install themselves.
1221
def get_credential_store(self, encoding=None):
1222
cs = self.get(encoding)
1228
credential_store_registry = CredentialStoreRegistry()
1231
class CredentialStore(object):
1232
"""An abstract class to implement storage for credentials"""
1234
def decode_password(self, credentials):
1235
"""Returns a password for the provided credentials in clear text."""
1236
raise NotImplementedError(self.decode_password)
1239
class PlainTextCredentialStore(CredentialStore):
1240
"""Plain text credential store for the authentication.conf file."""
1242
def decode_password(self, credentials):
1243
"""See CredentialStore.decode_password."""
1244
return credentials['password']
1247
credential_store_registry.register('plain', PlainTextCredentialStore,
1248
help=PlainTextCredentialStore.__doc__)
1249
credential_store_registry.default_key = 'plain'
1252
class BzrDirConfig(object):
1254
def __init__(self, transport):
1255
self._config = TransportConfig(transport, 'control.conf')
1257
def set_default_stack_on(self, value):
1258
"""Set the default stacking location.
1260
It may be set to a location, or None.
1262
This policy affects all branches contained by this bzrdir, except for
1263
those under repositories.
1266
self._config.set_option('', 'default_stack_on')
1268
self._config.set_option(value, 'default_stack_on')
1270
def get_default_stack_on(self):
1271
"""Return the default stacking location.
1273
This will either be a location, or None.
1275
This policy affects all branches contained by this bzrdir, except for
1276
those under repositories.
1278
value = self._config.get_option('default_stack_on')
1284
class TransportConfig(object):
1285
"""A Config that reads/writes a config file on a Transport.
1287
It is a low-level object that considers config data to be name/value pairs
1288
that may be associated with a section. Assigning meaning to the these
1289
values is done at higher levels like TreeConfig.
1292
def __init__(self, transport, filename):
1293
self._transport = transport
1294
self._filename = filename
1296
def get_option(self, name, section=None, default=None):
1297
"""Return the value associated with a named option.
1299
:param name: The name of the value
1300
:param section: The section the option is in (if any)
1301
:param default: The value to return if the value is not set
1302
:return: The value or default value
1304
configobj = self._get_configobj()
1306
section_obj = configobj
1309
section_obj = configobj[section]
1312
return section_obj.get(name, default)
1314
def set_option(self, value, name, section=None):
1315
"""Set the value associated with a named option.
1317
:param value: The value to set
1318
:param name: The name of the value to set
1319
:param section: The section the option is in (if any)
1321
configobj = self._get_configobj()
1323
configobj[name] = value
1325
configobj.setdefault(section, {})[name] = value
1326
self._set_configobj(configobj)
1328
def _get_configobj(self):
1330
return ConfigObj(self._transport.get(self._filename),
1332
except errors.NoSuchFile:
1333
return ConfigObj(encoding='utf-8')
1335
def _set_configobj(self, configobj):
1336
out_file = StringIO()
1337
configobj.write(out_file)
1339
self._transport.put_file(self._filename, out_file)