150
146
class Config(object):
151
147
"""A configuration policy - what username, editor, gpg needs etc."""
154
super(Config, self).__init__()
156
149
def get_editor(self):
157
150
"""Get the users pop up editor."""
158
151
raise NotImplementedError
160
def get_change_editor(self, old_tree, new_tree):
161
from bzrlib import diff
162
cmd = self._get_change_editor()
165
return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
169
153
def get_mail_client(self):
170
154
"""Get a mail client to use"""
171
155
selected_client = self.get_user_option('mail_client')
190
174
"""Get a generic option - no special process, no default."""
191
175
return self._get_user_option(option_name)
193
def get_user_option_as_bool(self, option_name):
194
"""Get a generic option as a boolean - no special process, no default.
196
:return None if the option doesn't exist or its value can't be
197
interpreted as a boolean. Returns True or False otherwise.
199
s = self._get_user_option(option_name)
201
# The option doesn't exist
203
val = ui.bool_from_string(s)
205
# The value can't be interpreted as a boolean
206
trace.warning('Value "%s" is not a boolean for "%s"',
210
def get_user_option_as_list(self, option_name):
211
"""Get a generic option as a list - no special process, no default.
213
:return None if the option doesn't exist. Returns the value as a list
216
l = self._get_user_option(option_name)
217
if isinstance(l, (str, unicode)):
218
# A single value, most probably the user forgot the final ','
222
177
def gpg_signing_command(self):
223
178
"""What program should be used to sign signatures?"""
224
179
result = self._gpg_signing_command()
341
def suppress_warning(self, warning):
342
"""Should the warning be suppressed or emitted.
344
:param warning: The name of the warning being tested.
346
:returns: True if the warning should be suppressed, False otherwise.
348
warnings = self.get_user_option_as_list('suppress_warnings')
349
if warnings is None or warning not in warnings:
355
299
class IniBasedConfig(Config):
356
300
"""A configuration policy that draws from ini files."""
358
def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
360
"""Base class for configuration files using an ini-like syntax.
362
:param file_name: The configuration file path.
364
super(IniBasedConfig, self).__init__()
365
self.file_name = file_name
366
if symbol_versioning.deprecated_passed(get_filename):
367
symbol_versioning.warn(
368
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
369
' Use file_name instead.',
372
if get_filename is not None:
373
self.file_name = get_filename()
375
self.file_name = file_name
380
def from_string(cls, str_or_unicode, file_name=None, save=False):
381
"""Create a config object from a string.
383
:param str_or_unicode: A string representing the file content. This will
386
:param file_name: The configuration file path.
388
:param _save: Whether the file should be saved upon creation.
390
conf = cls(file_name=file_name)
391
conf._create_from_string(str_or_unicode, save)
394
def _create_from_string(self, str_or_unicode, save):
395
self._content = StringIO(str_or_unicode.encode('utf-8'))
396
# Some tests use in-memory configs, some other always need the config
397
# file to exist on disk.
399
self._write_config_file()
401
def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
302
def _get_parser(self, file=None):
402
303
if self._parser is not None:
403
304
return self._parser
404
if symbol_versioning.deprecated_passed(file):
405
symbol_versioning.warn(
406
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
407
' Use IniBasedConfig(_content=xxx) instead.',
410
if self._content is not None:
411
co_input = self._content
412
elif self.file_name is None:
413
raise AssertionError('We have no content to create the config')
306
input = self._get_filename()
415
co_input = self.file_name
417
self._parser = ConfigObj(co_input, encoding='utf-8')
310
self._parser = ConfigObj(input, encoding='utf-8')
418
311
except configobj.ConfigObjError, e:
419
312
raise errors.ParseConfigError(e.errors, e.config.filename)
420
# Make sure self.reload() will use the right file name
421
self._parser.filename = self.file_name
422
313
return self._parser
425
"""Reload the config file from disk."""
426
if self.file_name is None:
427
raise AssertionError('We need a file name to reload the config')
428
if self._parser is not None:
429
self._parser.reload()
431
315
def _get_matching_sections(self):
432
316
"""Return an ordered list of (section_name, extra_path) pairs.
536
422
def _get_nickname(self):
537
423
return self.get_user_option('nickname')
539
def _write_config_file(self):
540
if self.file_name is None:
541
raise AssertionError('We cannot save, self.file_name is None')
542
conf_dir = os.path.dirname(self.file_name)
543
ensure_config_dir_exists(conf_dir)
544
atomic_file = atomicfile.AtomicFile(self.file_name)
545
self._get_parser().write(atomic_file)
548
osutils.copy_ownership_from_path(self.file_name)
551
class LockableConfig(IniBasedConfig):
552
"""A configuration needing explicit locking for access.
554
If several processes try to write the config file, the accesses need to be
557
Daughter classes should decorate all methods that update a config with the
558
``@needs_write_lock`` decorator (they call, directly or indirectly, the
559
``_write_config_file()`` method. These methods (typically ``set_option()``
560
and variants must reload the config file from disk before calling
561
``_write_config_file()``), this can be achieved by calling the
562
``self.reload()`` method. Note that the lock scope should cover both the
563
reading and the writing of the config file which is why the decorator can't
564
be applied to ``_write_config_file()`` only.
566
This should be enough to implement the following logic:
567
- lock for exclusive write access,
568
- reload the config file from disk,
572
This logic guarantees that a writer can update a value without erasing an
573
update made by another writer.
578
def __init__(self, file_name):
579
super(LockableConfig, self).__init__(file_name=file_name)
580
self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
581
self.transport = transport.get_transport(self.dir)
582
self._lock = lockdir.LockDir(self.transport, 'lock')
584
def _create_from_string(self, unicode_bytes, save):
585
super(LockableConfig, self)._create_from_string(unicode_bytes, False)
587
# We need to handle the saving here (as opposed to IniBasedConfig)
590
self._write_config_file()
593
def lock_write(self, token=None):
594
"""Takes a write lock in the directory containing the config file.
596
If the directory doesn't exist it is created.
598
ensure_config_dir_exists(self.dir)
599
return self._lock.lock_write(token)
604
def break_lock(self):
605
self._lock.break_lock()
607
def _write_config_file(self):
608
if self._lock is None or not self._lock.is_held:
609
# NB: if the following exception is raised it probably means a
610
# missing @needs_write_lock decorator on one of the callers.
611
raise errors.ObjectNotLocked(self)
612
super(LockableConfig, self)._write_config_file()
615
class GlobalConfig(LockableConfig):
426
class GlobalConfig(IniBasedConfig):
616
427
"""The configuration that should be used for a specific location."""
619
super(GlobalConfig, self).__init__(file_name=config_filename())
622
def from_string(cls, str_or_unicode, save=False):
623
"""Create a config object from a string.
625
:param str_or_unicode: A string representing the file content. This
626
will be utf-8 encoded.
628
:param save: Whether the file should be saved upon creation.
631
conf._create_from_string(str_or_unicode, save)
634
429
def get_editor(self):
635
430
return self._get_user_option('editor')
433
super(GlobalConfig, self).__init__(config_filename)
638
435
def set_user_option(self, option, value):
639
436
"""Save option and its value in the configuration."""
640
437
self._set_option(option, value, 'DEFAULT')
662
456
self._write_config_file()
664
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)
666
463
self._get_parser().setdefault(section, {})[option] = value
667
464
self._write_config_file()
670
class LocationConfig(LockableConfig):
466
def _write_config_file(self):
467
f = open(self._get_filename(), 'wb')
468
self._get_parser().write(f)
472
class LocationConfig(IniBasedConfig):
671
473
"""A configuration object that gives the policy for a location."""
673
475
def __init__(self, location):
674
super(LocationConfig, self).__init__(
675
file_name=locations_config_filename())
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)
676
488
# local file locations are looked up by local path, rather than
677
489
# by file url. This is because the config file is a user
678
490
# file, and we would rather not expose the user to file urls.
680
492
location = urlutils.local_path_from_url(location)
681
493
self.location = location
684
def from_string(cls, str_or_unicode, location, save=False):
685
"""Create a config object from a string.
687
:param str_or_unicode: A string representing the file content. This will
690
:param location: The location url to filter the configuration.
692
:param save: Whether the file should be saved upon creation.
695
conf._create_from_string(str_or_unicode, save)
698
495
def _get_matching_sections(self):
699
496
"""Return an ordered list of section names matching this location."""
700
497
sections = self._get_parser()
796
592
STORE_LOCATION_APPENDPATH]:
797
593
raise ValueError('bad storage policy %r for %r' %
595
# FIXME: RBC 20051029 This should refresh the parser and also take a
596
# file lock on locations.conf.
597
conf_dir = os.path.dirname(self._get_filename())
598
ensure_config_dir_exists(conf_dir)
800
599
location = self.location
801
600
if location.endswith('/'):
802
601
location = location[:-1]
803
parser = self._get_parser()
804
if not location in parser and not location + '/' in parser:
805
parser[location] = {}
806
elif location + '/' in parser:
602
if (not location in self._get_parser() and
603
not location + '/' in self._get_parser()):
604
self._get_parser()[location]={}
605
elif location + '/' in self._get_parser():
807
606
location = location + '/'
808
parser[location][option]=value
607
self._get_parser()[location][option]=value
809
608
# the allowed values of store match the config policies
810
609
self._set_option_policy(location, option, store)
811
self._write_config_file()
610
self._get_parser().write(file(self._get_filename(), 'wb'))
814
613
class BranchConfig(Config):
815
614
"""A configuration object giving the policy for a branch."""
817
def __init__(self, branch):
818
super(BranchConfig, self).__init__()
819
self._location_config = None
820
self._branch_data_config = None
821
self._global_config = None
823
self.option_sources = (self._get_location_config,
824
self._get_branch_data_config,
825
self._get_global_config)
827
616
def _get_branch_data_config(self):
828
617
if self._branch_data_config is None:
829
618
self._branch_data_config = TreeConfig(self.branch)
923
709
trace.warning('Value "%s" is masked by "%s" from'
924
710
' branch.conf', value, mask_value)
926
713
def _gpg_signing_command(self):
927
714
"""See Config.gpg_signing_command."""
928
715
return self._get_safe_value('_gpg_signing_command')
717
def __init__(self, branch):
718
super(BranchConfig, self).__init__()
719
self._location_config = None
720
self._branch_data_config = None
721
self._global_config = None
723
self.option_sources = (self._get_location_config,
724
self._get_branch_data_config,
725
self._get_global_config)
930
727
def _post_commit(self):
931
728
"""See Config.post_commit."""
932
729
return self._get_safe_value('_post_commit')
1011
813
return osutils.pathjoin(config_dir(), 'ignore')
1015
"""Return the directory name to store crash files.
1017
This doesn't implicitly create it.
1019
On Windows it's in the config directory; elsewhere it's /var/crash
1020
which may be monitored by apport. It can be overridden by
817
"""Calculate automatic user identification.
819
Returns (realname, email).
821
Only used when none is set in the environment or the id file.
823
This previously used the FQDN as the default domain, but that can
824
be very slow on machines where DNS is broken. So now we simply
1023
829
if sys.platform == 'win32':
1024
return osutils.pathjoin(config_dir(), 'Crash')
1026
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
1028
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
1031
def xdg_cache_dir():
1032
# See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
1033
# Possibly this should be different on Windows?
1034
e = os.environ.get('XDG_CACHE_DIR', None)
1038
return os.path.expanduser('~/.cache')
830
name = win32utils.get_user_name_unicode()
832
raise errors.BzrError("Cannot autodetect user name.\n"
833
"Please, set your name with command like:\n"
834
'bzr whoami "Your Name <name@domain.com>"')
835
host = win32utils.get_host_name_unicode()
837
host = socket.gethostname()
838
return name, (name + '@' + host)
844
w = pwd.getpwuid(uid)
846
raise errors.BzrCommandError('Unable to determine your name. '
847
'Please use "bzr whoami" to set it.')
849
# we try utf-8 first, because on many variants (like Linux),
850
# /etc/passwd "should" be in utf-8, and because it's unlikely to give
851
# false positives. (many users will have their user encoding set to
852
# latin-1, which cannot raise UnicodeError.)
854
gecos = w.pw_gecos.decode('utf-8')
858
encoding = osutils.get_user_encoding()
859
gecos = w.pw_gecos.decode(encoding)
861
raise errors.BzrCommandError('Unable to determine your name. '
862
'Use "bzr whoami" to set it.')
864
username = w.pw_name.decode(encoding)
866
raise errors.BzrCommandError('Unable to determine your name. '
867
'Use "bzr whoami" to set it.')
869
comma = gecos.find(',')
873
realname = gecos[:comma]
880
user_encoding = osutils.get_user_encoding()
881
realname = username = getpass.getuser().decode(user_encoding)
882
except UnicodeDecodeError:
883
raise errors.BzrError("Can't decode username as %s." % \
886
return realname, (username + '@' + socket.gethostname())
1041
889
def parse_username(username):
1158
1005
:param user: login (optional)
1160
1007
:param path: the absolute path on the server (optional)
1162
:param realm: the http authentication realm (optional)
1164
1009
:return: A dict containing the matching credentials or None.
1166
1011
- name: the section name of the credentials in the
1167
1012
authentication.conf file,
1168
- user: can't be different from the provided user if any,
1169
- scheme: the server protocol,
1170
- host: the server address,
1171
- port: the server port (can be None),
1172
- path: the absolute server path (can be None),
1173
- realm: the http specific authentication realm (can be None),
1013
- user: can't de different from the provided user if any,
1174
1014
- password: the decoded password, could be None if the credential
1175
1015
defines only the user
1176
1016
- verify_certificates: https specific, True if the server
1217
1057
if a_user is None:
1218
1058
# Can't find a user
1220
# Prepare a credentials dictionary with additional keys
1221
# for the credential providers
1222
1060
credentials = dict(name=auth_def_name,
1229
1062
password=auth_def.get('password', None),
1230
1063
verify_certificates=a_verify_certificates)
1231
# Decode the password in the credentials (or get one)
1232
1064
self.decode_password(credentials,
1233
1065
auth_def.get('password_encoding', None))
1234
1066
if 'auth' in debug.debug_flags:
1235
1067
trace.mutter("Using authentication section: %r", auth_def_name)
1238
if credentials is None:
1239
# No credentials were found in authentication.conf, try the fallback
1240
# credentials stores.
1241
credentials = credential_store_registry.get_fallback_credentials(
1242
scheme, host, port, user, path, realm)
1244
1070
return credentials
1246
1072
def set_credentials(self, name, host, user, scheme=None, password=None,
1247
port=None, path=None, verify_certificates=None,
1073
port=None, path=None, verify_certificates=None):
1249
1074
"""Set authentication credentials for a host.
1251
1076
Any existing credentials with matching scheme, host, port and path
1288
1110
config.update({name: values})
1291
def get_user(self, scheme, host, port=None, realm=None, path=None,
1292
prompt=None, ask=False, default=None):
1113
def get_user(self, scheme, host, port=None,
1114
realm=None, path=None, prompt=None):
1293
1115
"""Get a user from authentication file.
1295
1117
:param scheme: protocol
1303
1125
:param path: the absolute path on the server (optional)
1305
:param ask: Ask the user if there is no explicitly configured username
1308
:param default: The username returned if none is defined (optional).
1310
1127
:return: The found user.
1312
1129
credentials = self.get_credentials(scheme, host, port, user=None,
1313
path=path, realm=realm)
1314
1131
if credentials is not None:
1315
1132
user = credentials['user']
1321
# Create a default prompt suitable for most cases
1322
prompt = scheme.upper() + ' %(host)s username'
1323
# Special handling for optional fields in the prompt
1324
if port is not None:
1325
prompt_host = '%s:%d' % (host, port)
1328
user = ui.ui_factory.get_username(prompt, host=prompt_host)
1333
1137
def get_password(self, scheme, host, user, port=None,
1388
1191
A credential store provides access to credentials via the password_encoding
1389
1192
field in authentication.conf sections.
1391
Except for stores provided by bzr itself, most stores are expected to be
1194
Except for stores provided by bzr itself,most stores are expected to be
1392
1195
provided by plugins that will therefore use
1393
1196
register_lazy(password_encoding, module_name, member_name, help=help,
1394
fallback=fallback) to install themselves.
1396
A fallback credential store is one that is queried if no credentials can be
1397
found via authentication.conf.
1197
info=info) to install themselves.
1400
1200
def get_credential_store(self, encoding=None):
1406
def is_fallback(self, name):
1407
"""Check if the named credentials store should be used as fallback."""
1408
return self.get_info(name)
1410
def get_fallback_credentials(self, scheme, host, port=None, user=None,
1411
path=None, realm=None):
1412
"""Request credentials from all fallback credentials stores.
1414
The first credentials store that can provide credentials wins.
1417
for name in self.keys():
1418
if not self.is_fallback(name):
1420
cs = self.get_credential_store(name)
1421
credentials = cs.get_credentials(scheme, host, port, user,
1423
if credentials is not None:
1424
# We found some credentials
1428
def register(self, key, obj, help=None, override_existing=False,
1430
"""Register a new object to a name.
1432
:param key: This is the key to use to request the object later.
1433
:param obj: The object to register.
1434
:param help: Help text for this entry. This may be a string or
1435
a callable. If it is a callable, it should take two
1436
parameters (registry, key): this registry and the key that
1437
the help was registered under.
1438
:param override_existing: Raise KeyErorr if False and something has
1439
already been registered for that key. If True, ignore if there
1440
is an existing key (always register the new value).
1441
:param fallback: Whether this credential store should be
1444
return super(CredentialStoreRegistry,
1445
self).register(key, obj, help, info=fallback,
1446
override_existing=override_existing)
1448
def register_lazy(self, key, module_name, member_name,
1449
help=None, override_existing=False,
1451
"""Register a new credential store to be loaded on request.
1453
:param module_name: The python path to the module. Such as 'os.path'.
1454
:param member_name: The member of the module to return. If empty or
1455
None, get() will return the module itself.
1456
:param help: Help text for this entry. This may be a string or
1458
:param override_existing: If True, replace the existing object
1459
with the new one. If False, if there is already something
1460
registered with the same key, raise a KeyError
1461
:param fallback: Whether this credential store should be
1464
return super(CredentialStoreRegistry, self).register_lazy(
1465
key, module_name, member_name, help,
1466
info=fallback, override_existing=override_existing)
1469
1207
credential_store_registry = CredentialStoreRegistry()
1473
1211
"""An abstract class to implement storage for credentials"""
1475
1213
def decode_password(self, credentials):
1476
"""Returns a clear text password for the provided credentials."""
1214
"""Returns a password for the provided credentials in clear text."""
1477
1215
raise NotImplementedError(self.decode_password)
1479
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1481
"""Return the matching credentials from this credential store.
1483
This method is only called on fallback credential stores.
1485
raise NotImplementedError(self.get_credentials)
1489
1218
class PlainTextCredentialStore(CredentialStore):
1490
__doc__ = """Plain text credential store for the authentication.conf file"""
1219
"""Plain text credential store for the authentication.conf file."""
1492
1221
def decode_password(self, credentials):
1493
1222
"""See CredentialStore.decode_password."""
1580
1304
configobj.setdefault(section, {})[name] = value
1581
1305
self._set_configobj(configobj)
1583
def _get_config_file(self):
1307
def _get_configobj(self):
1585
return StringIO(self._transport.get_bytes(self._filename))
1309
return ConfigObj(self._transport.get(self._filename),
1586
1311
except errors.NoSuchFile:
1589
def _get_configobj(self):
1590
f = self._get_config_file()
1592
return ConfigObj(f, encoding='utf-8')
1312
return ConfigObj(encoding='utf-8')
1596
1314
def _set_configobj(self, configobj):
1597
1315
out_file = StringIO()