146
146
class Config(object):
147
147
"""A configuration policy - what username, editor, gpg needs etc."""
150
super(Config, self).__init__()
149
152
def get_editor(self):
150
153
"""Get the users pop up editor."""
151
154
raise NotImplementedError
156
def get_change_editor(self, old_tree, new_tree):
157
from bzrlib import diff
158
cmd = self._get_change_editor()
161
return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
153
165
def get_mail_client(self):
154
166
"""Get a mail client to use"""
155
167
selected_client = self.get_user_option('mail_client')
174
186
"""Get a generic option - no special process, no default."""
175
187
return self._get_user_option(option_name)
189
def get_user_option_as_bool(self, option_name):
190
"""Get a generic option as a boolean - no special process, no default.
192
:return None if the option doesn't exist or its value can't be
193
interpreted as a boolean. Returns True or False otherwise.
195
s = self._get_user_option(option_name)
196
return ui.bool_from_string(s)
198
def get_user_option_as_list(self, option_name):
199
"""Get a generic option as a list - no special process, no default.
201
:return None if the option doesn't exist. Returns the value as a list
204
l = self._get_user_option(option_name)
205
if isinstance(l, (str, unicode)):
206
# A single value, most probably the user forgot the final ','
177
210
def gpg_signing_command(self):
178
211
"""What program should be used to sign signatures?"""
179
212
result = self._gpg_signing_command()
328
def suppress_warning(self, warning):
329
"""Should the warning be suppressed or emitted.
331
:param warning: The name of the warning being tested.
333
:returns: True if the warning should be suppressed, False otherwise.
335
warnings = self.get_user_option_as_list('suppress_warnings')
336
if warnings is None or warning not in warnings:
299
342
class IniBasedConfig(Config):
300
343
"""A configuration policy that draws from ini files."""
345
def __init__(self, get_filename):
346
super(IniBasedConfig, self).__init__()
347
self._get_filename = get_filename
302
350
def _get_parser(self, file=None):
303
351
if self._parser is not None:
304
352
return self._parser
813
862
return osutils.pathjoin(config_dir(), 'ignore')
866
"""Return the directory name to store crash files.
868
This doesn't implicitly create it.
870
On Windows it's in the config directory; elsewhere it's /var/crash
871
which may be monitored by apport. It can be overridden by
874
if sys.platform == 'win32':
875
return osutils.pathjoin(config_dir(), 'Crash')
877
# XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
879
return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
883
# See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
884
# Possibly this should be different on Windows?
885
e = os.environ.get('XDG_CACHE_DIR', None)
889
return os.path.expanduser('~/.cache')
816
892
def _auto_user_id():
817
893
"""Calculate automatic user identification.
917
993
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
919
995
def __init__(self, branch):
920
# XXX: Really this should be asking the branch for its configuration
921
# data, rather than relying on a Transport, so that it can work
922
# more cleanly with a RemoteBranch that has no transport.
923
self._config = TransportConfig(branch._transport, 'branch.conf')
996
self._config = branch._get_config()
924
997
self.branch = branch
926
999
def _get_parser(self, file=None):
1083
1155
trace.mutter("Using authentication section: %r", auth_def_name)
1158
if credentials is None:
1159
# No credentials were found in authentication.conf, try the fallback
1160
# credentials stores.
1161
credentials = credential_store_registry.get_fallback_credentials(
1162
scheme, host, port, user, path, realm)
1086
1164
return credentials
1088
1166
def set_credentials(self, name, host, user, scheme=None, password=None,
1130
1208
config.update({name: values})
1133
def get_user(self, scheme, host, port=None,
1134
realm=None, path=None, prompt=None):
1211
def get_user(self, scheme, host, port=None, realm=None, path=None,
1212
prompt=None, ask=False, default=None):
1135
1213
"""Get a user from authentication file.
1137
1215
:param scheme: protocol
1152
1235
user = credentials['user']
1241
# Create a default prompt suitable for most cases
1242
prompt = scheme.upper() + ' %(host)s username'
1243
# Special handling for optional fields in the prompt
1244
if port is not None:
1245
prompt_host = '%s:%d' % (host, port)
1248
user = ui.ui_factory.get_username(prompt, host=prompt_host)
1157
1253
def get_password(self, scheme, host, user, port=None,
1212
1308
A credential store provides access to credentials via the password_encoding
1213
1309
field in authentication.conf sections.
1215
Except for stores provided by bzr itself,most stores are expected to be
1311
Except for stores provided by bzr itself, most stores are expected to be
1216
1312
provided by plugins that will therefore use
1217
1313
register_lazy(password_encoding, module_name, member_name, help=help,
1218
info=info) to install themselves.
1314
fallback=fallback) to install themselves.
1316
A fallback credential store is one that is queried if no credentials can be
1317
found via authentication.conf.
1221
1320
def get_credential_store(self, encoding=None):
1326
def is_fallback(self, name):
1327
"""Check if the named credentials store should be used as fallback."""
1328
return self.get_info(name)
1330
def get_fallback_credentials(self, scheme, host, port=None, user=None,
1331
path=None, realm=None):
1332
"""Request credentials from all fallback credentials stores.
1334
The first credentials store that can provide credentials wins.
1337
for name in self.keys():
1338
if not self.is_fallback(name):
1340
cs = self.get_credential_store(name)
1341
credentials = cs.get_credentials(scheme, host, port, user,
1343
if credentials is not None:
1344
# We found some credentials
1348
def register(self, key, obj, help=None, override_existing=False,
1350
"""Register a new object to a name.
1352
:param key: This is the key to use to request the object later.
1353
:param obj: The object to register.
1354
:param help: Help text for this entry. This may be a string or
1355
a callable. If it is a callable, it should take two
1356
parameters (registry, key): this registry and the key that
1357
the help was registered under.
1358
:param override_existing: Raise KeyErorr if False and something has
1359
already been registered for that key. If True, ignore if there
1360
is an existing key (always register the new value).
1361
:param fallback: Whether this credential store should be
1364
return super(CredentialStoreRegistry,
1365
self).register(key, obj, help, info=fallback,
1366
override_existing=override_existing)
1368
def register_lazy(self, key, module_name, member_name,
1369
help=None, override_existing=False,
1371
"""Register a new credential store to be loaded on request.
1373
:param module_name: The python path to the module. Such as 'os.path'.
1374
:param member_name: The member of the module to return. If empty or
1375
None, get() will return the module itself.
1376
:param help: Help text for this entry. This may be a string or
1378
:param override_existing: If True, replace the existing object
1379
with the new one. If False, if there is already something
1380
registered with the same key, raise a KeyError
1381
:param fallback: Whether this credential store should be
1384
return super(CredentialStoreRegistry, self).register_lazy(
1385
key, module_name, member_name, help,
1386
info=fallback, override_existing=override_existing)
1228
1389
credential_store_registry = CredentialStoreRegistry()
1232
1393
"""An abstract class to implement storage for credentials"""
1234
1395
def decode_password(self, credentials):
1235
"""Returns a password for the provided credentials in clear text."""
1396
"""Returns a clear text password for the provided credentials."""
1236
1397
raise NotImplementedError(self.decode_password)
1399
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1401
"""Return the matching credentials from this credential store.
1403
This method is only called on fallback credential stores.
1405
raise NotImplementedError(self.get_credentials)
1239
1409
class PlainTextCredentialStore(CredentialStore):
1240
1410
"""Plain text credential store for the authentication.conf file."""
1252
1422
class BzrDirConfig(object):
1254
def __init__(self, transport):
1255
self._config = TransportConfig(transport, 'control.conf')
1424
def __init__(self, bzrdir):
1425
self._bzrdir = bzrdir
1426
self._config = bzrdir._get_config()
1257
1428
def set_default_stack_on(self, value):
1258
1429
"""Set the default stacking location.
1325
1500
configobj.setdefault(section, {})[name] = value
1326
1501
self._set_configobj(configobj)
1503
def _get_config_file(self):
1505
return StringIO(self._transport.get_bytes(self._filename))
1506
except errors.NoSuchFile:
1328
1509
def _get_configobj(self):
1330
return ConfigObj(self._transport.get(self._filename),
1332
except errors.NoSuchFile:
1333
return ConfigObj(encoding='utf-8')
1510
return ConfigObj(self._get_config_file(), encoding='utf-8')
1335
1512
def _set_configobj(self, configobj):
1336
1513
out_file = StringIO()