15
15
# You should have received a copy of the GNU General Public License
16
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
19
"""Configuration that affects the behaviour of Bazaar.
45
45
editor - this option sets the pop up editor to use during commits.
46
46
email - this option sets the user id bzr will use when committing.
47
47
check_signatures - this option controls whether bzr will require good gpg
48
signatures, ignore them, or check them if they are
48
signatures, ignore them, or check them if they are
50
create_signatures - this option controls whether bzr will always create
50
create_signatures - this option controls whether bzr will always create
51
51
gpg signatures, never create them, or create them if the
52
52
branch is configured to require them.
53
53
log_format - this option sets the default log format. Possible values are
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()
217
247
def username(self):
218
248
"""Return email-style username.
220
250
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
222
252
$BZR_EMAIL can be set to override this (as well as the
223
253
deprecated $BZREMAIL), then
224
254
the concrete policy type is checked, and finally
225
255
$EMAIL is examined.
226
256
If none is found, a reasonable default is (hopefully)
229
259
TODO: Check it's reasonably well-formed.
231
261
v = os.environ.get('BZR_EMAIL')
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
709
758
trace.warning('Value "%s" is masked by "%s" from'
710
759
' branch.conf', value, mask_value)
713
761
def _gpg_signing_command(self):
714
762
"""See Config.gpg_signing_command."""
715
763
return self._get_safe_value('_gpg_signing_command')
717
765
def __init__(self, branch):
718
766
super(BranchConfig, self).__init__()
719
767
self._location_config = None
720
768
self._branch_data_config = None
721
769
self._global_config = None
722
770
self.branch = branch
723
self.option_sources = (self._get_location_config,
771
self.option_sources = (self._get_location_config,
724
772
self._get_branch_data_config,
725
773
self._get_global_config)
813
861
return osutils.pathjoin(config_dir(), 'ignore')
865
"""Return the directory name to store crash files.
867
This doesn't implicitly create it.
869
On Windows it's in the config directory; elsewhere in the XDG cache directory.
871
if sys.platform == 'win32':
872
return osutils.pathjoin(config_dir(), 'Crash')
874
return osutils.pathjoin(xdg_cache_dir(), 'crash')
878
# See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
879
# Possibly this should be different on Windows?
880
e = os.environ.get('XDG_CACHE_DIR', None)
884
return os.path.expanduser('~/.cache')
816
887
def _auto_user_id():
817
888
"""Calculate automatic user identification.
917
988
# XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
919
990
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')
991
self._config = branch._get_config()
924
992
self.branch = branch
926
994
def _get_parser(self, file=None):
993
1060
section[option_name] = value
996
def get_credentials(self, scheme, host, port=None, user=None, path=None):
1063
def get_credentials(self, scheme, host, port=None, user=None, path=None,
997
1065
"""Returns the matching credentials from authentication.conf file.
999
1067
:param scheme: protocol
1005
1073
:param user: login (optional)
1007
1075
:param path: the absolute path on the server (optional)
1077
:param realm: the http authentication realm (optional)
1009
1079
:return: A dict containing the matching credentials or None.
1011
1081
- name: the section name of the credentials in the
1012
1082
authentication.conf file,
1013
- user: can't de different from the provided user if any,
1083
- user: can't be different from the provided user if any,
1084
- scheme: the server protocol,
1085
- host: the server address,
1086
- port: the server port (can be None),
1087
- path: the absolute server path (can be None),
1088
- realm: the http specific authentication realm (can be None),
1014
1089
- password: the decoded password, could be None if the credential
1015
1090
defines only the user
1016
1091
- verify_certificates: https specific, True if the server
1057
1132
if a_user is None:
1058
1133
# Can't find a user
1135
# Prepare a credentials dictionary with additional keys
1136
# for the credential providers
1060
1137
credentials = dict(name=auth_def_name,
1062
1144
password=auth_def.get('password', None),
1063
1145
verify_certificates=a_verify_certificates)
1146
# Decode the password in the credentials (or get one)
1064
1147
self.decode_password(credentials,
1065
1148
auth_def.get('password_encoding', None))
1066
1149
if 'auth' in debug.debug_flags:
1067
1150
trace.mutter("Using authentication section: %r", auth_def_name)
1153
if credentials is None:
1154
# No credentials were found in authentication.conf, try the fallback
1155
# credentials stores.
1156
credentials = credential_store_registry.get_fallback_credentials(
1157
scheme, host, port, user, path, realm)
1070
1159
return credentials
1072
1161
def set_credentials(self, name, host, user, scheme=None, password=None,
1073
port=None, path=None, verify_certificates=None):
1162
port=None, path=None, verify_certificates=None,
1074
1164
"""Set authentication credentials for a host.
1076
1166
Any existing credentials with matching scheme, host, port and path
1099
1190
values['path'] = path
1100
1191
if verify_certificates is not None:
1101
1192
values['verify_certificates'] = str(verify_certificates)
1193
if realm is not None:
1194
values['realm'] = realm
1102
1195
config = self._get_config()
1103
1196
for_deletion = []
1104
1197
for section, existing_values in config.items():
1105
for key in ('scheme', 'host', 'port', 'path'):
1198
for key in ('scheme', 'host', 'port', 'path', 'realm'):
1106
1199
if existing_values.get(key) != values.get(key):
1110
1203
config.update({name: values})
1113
def get_user(self, scheme, host, port=None,
1114
realm=None, path=None, prompt=None):
1206
def get_user(self, scheme, host, port=None, realm=None, path=None,
1207
prompt=None, ask=False, default=None):
1115
1208
"""Get a user from authentication file.
1117
1210
:param scheme: protocol
1125
1218
:param path: the absolute path on the server (optional)
1220
:param ask: Ask the user if there is no explicitly configured username
1223
:param default: The username returned if none is defined (optional).
1127
1225
:return: The found user.
1129
1227
credentials = self.get_credentials(scheme, host, port, user=None,
1228
path=path, realm=realm)
1131
1229
if credentials is not None:
1132
1230
user = credentials['user']
1236
# Create a default prompt suitable for most cases
1237
prompt = scheme.upper() + ' %(host)s username'
1238
# Special handling for optional fields in the prompt
1239
if port is not None:
1240
prompt_host = '%s:%d' % (host, port)
1243
user = ui.ui_factory.get_username(prompt, host=prompt_host)
1137
1248
def get_password(self, scheme, host, user, port=None,
1153
1264
:return: The found password or the one entered by the user.
1155
credentials = self.get_credentials(scheme, host, port, user, path)
1266
credentials = self.get_credentials(scheme, host, port, user, path,
1156
1268
if credentials is not None:
1157
1269
password = credentials['password']
1158
1270
if password is not None and scheme is 'ssh':
1191
1303
A credential store provides access to credentials via the password_encoding
1192
1304
field in authentication.conf sections.
1194
Except for stores provided by bzr itself,most stores are expected to be
1306
Except for stores provided by bzr itself, most stores are expected to be
1195
1307
provided by plugins that will therefore use
1196
1308
register_lazy(password_encoding, module_name, member_name, help=help,
1197
info=info) to install themselves.
1309
fallback=fallback) to install themselves.
1311
A fallback credential store is one that is queried if no credentials can be
1312
found via authentication.conf.
1200
1315
def get_credential_store(self, encoding=None):
1321
def is_fallback(self, name):
1322
"""Check if the named credentials store should be used as fallback."""
1323
return self.get_info(name)
1325
def get_fallback_credentials(self, scheme, host, port=None, user=None,
1326
path=None, realm=None):
1327
"""Request credentials from all fallback credentials stores.
1329
The first credentials store that can provide credentials wins.
1332
for name in self.keys():
1333
if not self.is_fallback(name):
1335
cs = self.get_credential_store(name)
1336
credentials = cs.get_credentials(scheme, host, port, user,
1338
if credentials is not None:
1339
# We found some credentials
1343
def register(self, key, obj, help=None, override_existing=False,
1345
"""Register a new object to a name.
1347
:param key: This is the key to use to request the object later.
1348
:param obj: The object to register.
1349
:param help: Help text for this entry. This may be a string or
1350
a callable. If it is a callable, it should take two
1351
parameters (registry, key): this registry and the key that
1352
the help was registered under.
1353
:param override_existing: Raise KeyErorr if False and something has
1354
already been registered for that key. If True, ignore if there
1355
is an existing key (always register the new value).
1356
:param fallback: Whether this credential store should be
1359
return super(CredentialStoreRegistry,
1360
self).register(key, obj, help, info=fallback,
1361
override_existing=override_existing)
1363
def register_lazy(self, key, module_name, member_name,
1364
help=None, override_existing=False,
1366
"""Register a new credential store to be loaded on request.
1368
:param module_name: The python path to the module. Such as 'os.path'.
1369
:param member_name: The member of the module to return. If empty or
1370
None, get() will return the module itself.
1371
:param help: Help text for this entry. This may be a string or
1373
:param override_existing: If True, replace the existing object
1374
with the new one. If False, if there is already something
1375
registered with the same key, raise a KeyError
1376
:param fallback: Whether this credential store should be
1379
return super(CredentialStoreRegistry, self).register_lazy(
1380
key, module_name, member_name, help,
1381
info=fallback, override_existing=override_existing)
1207
1384
credential_store_registry = CredentialStoreRegistry()
1211
1388
"""An abstract class to implement storage for credentials"""
1213
1390
def decode_password(self, credentials):
1214
"""Returns a password for the provided credentials in clear text."""
1391
"""Returns a clear text password for the provided credentials."""
1215
1392
raise NotImplementedError(self.decode_password)
1394
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1396
"""Return the matching credentials from this credential store.
1398
This method is only called on fallback credential stores.
1400
raise NotImplementedError(self.get_credentials)
1218
1404
class PlainTextCredentialStore(CredentialStore):
1219
1405
"""Plain text credential store for the authentication.conf file."""
1231
1417
class BzrDirConfig(object):
1233
def __init__(self, transport):
1234
self._config = TransportConfig(transport, 'control.conf')
1419
def __init__(self, bzrdir):
1420
self._bzrdir = bzrdir
1421
self._config = bzrdir._get_config()
1236
1423
def set_default_stack_on(self, value):
1237
1424
"""Set the default stacking location.
1304
1495
configobj.setdefault(section, {})[name] = value
1305
1496
self._set_configobj(configobj)
1498
def _get_config_file(self):
1500
return StringIO(self._transport.get_bytes(self._filename))
1501
except errors.NoSuchFile:
1307
1504
def _get_configobj(self):
1309
return ConfigObj(self._transport.get(self._filename),
1311
except errors.NoSuchFile:
1312
return ConfigObj(encoding='utf-8')
1505
return ConfigObj(self._get_config_file(), encoding='utf-8')
1314
1507
def _set_configobj(self, configobj):
1315
1508
out_file = StringIO()