~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Martin
  • Date: 2010-05-16 14:42:56 UTC
  • mto: This revision was merged to the branch mainline in revision 5239.
  • Revision ID: gzlist@googlemail.com-20100516144256-mhbrel8ianbe6auu
Use macro to get crc32 result in pyrex _search_key_* functions

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
146
146
class Config(object):
147
147
    """A configuration policy - what username, editor, gpg needs etc."""
148
148
 
 
149
    def __init__(self):
 
150
        super(Config, self).__init__()
 
151
 
149
152
    def get_editor(self):
150
153
        """Get the users pop up editor."""
151
154
        raise NotImplementedError
152
155
 
 
156
    def get_change_editor(self, old_tree, new_tree):
 
157
        from bzrlib import diff
 
158
        cmd = self._get_change_editor()
 
159
        if cmd is None:
 
160
            return None
 
161
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
 
162
                                             sys.stdout)
 
163
 
 
164
 
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)
176
188
 
 
189
    def get_user_option_as_bool(self, option_name):
 
190
        """Get a generic option as a boolean - no special process, no default.
 
191
 
 
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.
 
194
        """
 
195
        s = self._get_user_option(option_name)
 
196
        return ui.bool_from_string(s)
 
197
 
 
198
    def get_user_option_as_list(self, option_name):
 
199
        """Get a generic option as a list - no special process, no default.
 
200
 
 
201
        :return None if the option doesn't exist. Returns the value as a list
 
202
            otherwise.
 
203
        """
 
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 ','
 
207
            l = [l]
 
208
        return l
 
209
 
177
210
    def gpg_signing_command(self):
178
211
        """What program should be used to sign signatures?"""
179
212
        result = self._gpg_signing_command()
196
229
        """See log_format()."""
197
230
        return None
198
231
 
199
 
    def __init__(self):
200
 
        super(Config, self).__init__()
201
 
 
202
232
    def post_commit(self):
203
233
        """An ordered list of python functions to call.
204
234
 
295
325
                path = 'bzr'
296
326
            return path
297
327
 
 
328
    def suppress_warning(self, warning):
 
329
        """Should the warning be suppressed or emitted.
 
330
 
 
331
        :param warning: The name of the warning being tested.
 
332
 
 
333
        :returns: True if the warning should be suppressed, False otherwise.
 
334
        """
 
335
        warnings = self.get_user_option_as_list('suppress_warnings')
 
336
        if warnings is None or warning not in warnings:
 
337
            return False
 
338
        else:
 
339
            return True
 
340
 
298
341
 
299
342
class IniBasedConfig(Config):
300
343
    """A configuration policy that draws from ini files."""
301
344
 
 
345
    def __init__(self, get_filename):
 
346
        super(IniBasedConfig, self).__init__()
 
347
        self._get_filename = get_filename
 
348
        self._parser = None
 
349
 
302
350
    def _get_parser(self, file=None):
303
351
        if self._parser is not None:
304
352
            return self._parser
332
380
        """Return the policy for the given (section, option_name) pair."""
333
381
        return POLICY_NONE
334
382
 
 
383
    def _get_change_editor(self):
 
384
        return self.get_user_option('change_editor')
 
385
 
335
386
    def _get_signature_checking(self):
336
387
        """See Config._get_signature_checking."""
337
388
        policy = self._get_user_option('check_signatures')
381
432
        """See Config.log_format."""
382
433
        return self._get_user_option('log_format')
383
434
 
384
 
    def __init__(self, get_filename):
385
 
        super(IniBasedConfig, self).__init__()
386
 
        self._get_filename = get_filename
387
 
        self._parser = None
388
 
 
389
435
    def _post_commit(self):
390
436
        """See Config.post_commit."""
391
437
        return self._get_user_option('post_commit')
464
510
        self._write_config_file()
465
511
 
466
512
    def _write_config_file(self):
467
 
        f = open(self._get_filename(), 'wb')
 
513
        path = self._get_filename()
 
514
        f = osutils.open_with_ownership(path, 'wb')
468
515
        self._get_parser().write(f)
469
516
        f.close()
470
517
 
670
717
 
671
718
        return self._get_best_value('_get_user_id')
672
719
 
 
720
    def _get_change_editor(self):
 
721
        return self._get_best_value('_get_change_editor')
 
722
 
673
723
    def _get_signature_checking(self):
674
724
        """See Config._get_signature_checking."""
675
725
        return self._get_best_value('_get_signature_checking')
709
759
                        trace.warning('Value "%s" is masked by "%s" from'
710
760
                                      ' branch.conf', value, mask_value)
711
761
 
712
 
 
713
762
    def _gpg_signing_command(self):
714
763
        """See Config.gpg_signing_command."""
715
764
        return self._get_safe_value('_gpg_signing_command')
761
810
                trace.mutter('creating config parent directory: %r', parent_dir)
762
811
            os.mkdir(parent_dir)
763
812
        trace.mutter('creating config directory: %r', path)
764
 
        os.mkdir(path)
 
813
        osutils.mkdir_with_ownership(path)
765
814
 
766
815
 
767
816
def config_dir():
813
862
    return osutils.pathjoin(config_dir(), 'ignore')
814
863
 
815
864
 
 
865
def crash_dir():
 
866
    """Return the directory name to store crash files.
 
867
 
 
868
    This doesn't implicitly create it.
 
869
 
 
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
 
872
    $APPORT_CRASH_DIR.
 
873
    """
 
874
    if sys.platform == 'win32':
 
875
        return osutils.pathjoin(config_dir(), 'Crash')
 
876
    else:
 
877
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
878
        # 2010-01-31
 
879
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
880
 
 
881
 
 
882
def xdg_cache_dir():
 
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)
 
886
    if e:
 
887
        return e
 
888
    else:
 
889
        return os.path.expanduser('~/.cache')
 
890
 
 
891
 
816
892
def _auto_user_id():
817
893
    """Calculate automatic user identification.
818
894
 
917
993
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
918
994
 
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
925
998
 
926
999
    def _get_parser(self, file=None):
934
1007
            return self._config.get_option(name, section, default)
935
1008
        finally:
936
1009
            self.branch.unlock()
937
 
        return result
938
1010
 
939
1011
    def set_option(self, value, name, section=None):
940
1012
        """Set a per-branch configuration option"""
1083
1155
                trace.mutter("Using authentication section: %r", auth_def_name)
1084
1156
            break
1085
1157
 
 
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)
 
1163
 
1086
1164
        return credentials
1087
1165
 
1088
1166
    def set_credentials(self, name, host, user, scheme=None, password=None,
1130
1208
        config.update({name: values})
1131
1209
        self._save()
1132
1210
 
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.
1136
1214
 
1137
1215
        :param scheme: protocol
1144
1222
 
1145
1223
        :param path: the absolute path on the server (optional)
1146
1224
 
 
1225
        :param ask: Ask the user if there is no explicitly configured username 
 
1226
                    (optional)
 
1227
 
 
1228
        :param default: The username returned if none is defined (optional).
 
1229
 
1147
1230
        :return: The found user.
1148
1231
        """
1149
1232
        credentials = self.get_credentials(scheme, host, port, user=None,
1152
1235
            user = credentials['user']
1153
1236
        else:
1154
1237
            user = None
 
1238
        if user is None:
 
1239
            if ask:
 
1240
                if prompt is None:
 
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)
 
1246
                else:
 
1247
                    prompt_host = host
 
1248
                user = ui.ui_factory.get_username(prompt, host=prompt_host)
 
1249
            else:
 
1250
                user = default
1155
1251
        return user
1156
1252
 
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.
1214
1310
 
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.
 
1315
 
 
1316
    A fallback credential store is one that is queried if no credentials can be
 
1317
    found via authentication.conf.
1219
1318
    """
1220
1319
 
1221
1320
    def get_credential_store(self, encoding=None):
1224
1323
            cs = cs()
1225
1324
        return cs
1226
1325
 
 
1326
    def is_fallback(self, name):
 
1327
        """Check if the named credentials store should be used as fallback."""
 
1328
        return self.get_info(name)
 
1329
 
 
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.
 
1333
 
 
1334
        The first credentials store that can provide credentials wins.
 
1335
        """
 
1336
        credentials = None
 
1337
        for name in self.keys():
 
1338
            if not self.is_fallback(name):
 
1339
                continue
 
1340
            cs = self.get_credential_store(name)
 
1341
            credentials = cs.get_credentials(scheme, host, port, user,
 
1342
                                             path, realm)
 
1343
            if credentials is not None:
 
1344
                # We found some credentials
 
1345
                break
 
1346
        return credentials
 
1347
 
 
1348
    def register(self, key, obj, help=None, override_existing=False,
 
1349
                 fallback=False):
 
1350
        """Register a new object to a name.
 
1351
 
 
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 
 
1362
                used as fallback.
 
1363
        """
 
1364
        return super(CredentialStoreRegistry,
 
1365
                     self).register(key, obj, help, info=fallback,
 
1366
                                    override_existing=override_existing)
 
1367
 
 
1368
    def register_lazy(self, key, module_name, member_name,
 
1369
                      help=None, override_existing=False,
 
1370
                      fallback=False):
 
1371
        """Register a new credential store to be loaded on request.
 
1372
 
 
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
 
1377
                a callable.
 
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 
 
1382
                used as fallback.
 
1383
        """
 
1384
        return super(CredentialStoreRegistry, self).register_lazy(
 
1385
            key, module_name, member_name, help,
 
1386
            info=fallback, override_existing=override_existing)
 
1387
 
1227
1388
 
1228
1389
credential_store_registry = CredentialStoreRegistry()
1229
1390
 
1232
1393
    """An abstract class to implement storage for credentials"""
1233
1394
 
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)
1237
1398
 
 
1399
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
 
1400
                        realm=None):
 
1401
        """Return the matching credentials from this credential store.
 
1402
 
 
1403
        This method is only called on fallback credential stores.
 
1404
        """
 
1405
        raise NotImplementedError(self.get_credentials)
 
1406
 
 
1407
 
1238
1408
 
1239
1409
class PlainTextCredentialStore(CredentialStore):
1240
1410
    """Plain text credential store for the authentication.conf file."""
1251
1421
 
1252
1422
class BzrDirConfig(object):
1253
1423
 
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()
1256
1427
 
1257
1428
    def set_default_stack_on(self, value):
1258
1429
        """Set the default stacking location.
1262
1433
        This policy affects all branches contained by this bzrdir, except for
1263
1434
        those under repositories.
1264
1435
        """
 
1436
        if self._config is None:
 
1437
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1265
1438
        if value is None:
1266
1439
            self._config.set_option('', 'default_stack_on')
1267
1440
        else:
1275
1448
        This policy affects all branches contained by this bzrdir, except for
1276
1449
        those under repositories.
1277
1450
        """
 
1451
        if self._config is None:
 
1452
            return None
1278
1453
        value = self._config.get_option('default_stack_on')
1279
1454
        if value == '':
1280
1455
            value = None
1325
1500
            configobj.setdefault(section, {})[name] = value
1326
1501
        self._set_configobj(configobj)
1327
1502
 
 
1503
    def _get_config_file(self):
 
1504
        try:
 
1505
            return StringIO(self._transport.get_bytes(self._filename))
 
1506
        except errors.NoSuchFile:
 
1507
            return StringIO()
 
1508
 
1328
1509
    def _get_configobj(self):
1329
 
        try:
1330
 
            return ConfigObj(self._transport.get(self._filename),
1331
 
                             encoding='utf-8')
1332
 
        except errors.NoSuchFile:
1333
 
            return ConfigObj(encoding='utf-8')
 
1510
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1334
1511
 
1335
1512
    def _set_configobj(self, configobj):
1336
1513
        out_file = StringIO()