~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-10 15:46:03 UTC
  • mfrom: (4985.3.21 update)
  • mto: This revision was merged to the branch mainline in revision 5021.
  • Revision ID: v.ladeuil+lp@free.fr-20100210154603-k4no1gvfuqpzrw7p
Update performs two merges in a more logical order but stop on conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005, 2007, 2008, 2010 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
14
14
#
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
18
18
 
19
19
"""Configuration that affects the behaviour of Bazaar.
20
20
 
37
37
[/home/robertc/source]
38
38
recurse=False|True(default)
39
39
email= as above
40
 
check_signatures= as above 
 
40
check_signatures= as above
41
41
create_signatures= as above.
42
42
 
43
43
explanation of options
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
49
49
                   present.
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."""
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
 
216
246
 
217
247
    def username(self):
218
248
        """Return email-style username.
219
 
    
 
249
 
220
250
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
221
 
        
 
251
 
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)
227
257
        created.
228
 
    
 
258
 
229
259
        TODO: Check it's reasonably well-formed.
230
260
        """
231
261
        v = os.environ.get('BZR_EMAIL')
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')
414
460
 
415
461
    def _get_alias(self, value):
416
462
        try:
417
 
            return self._get_parser().get_value("ALIASES", 
 
463
            return self._get_parser().get_value("ALIASES",
418
464
                                                value)
419
465
        except KeyError:
420
466
            pass
642
688
 
643
689
    def _get_safe_value(self, option_name):
644
690
        """This variant of get_best_value never returns untrusted values.
645
 
        
 
691
 
646
692
        It does not return values from the branch data, because the branch may
647
693
        not be controlled by the user.
648
694
 
657
703
 
658
704
    def _get_user_id(self):
659
705
        """Return the full user id for the branch.
660
 
    
 
706
 
661
707
        e.g. "John Hacker <jhacker@example.com>"
662
708
        This is looked up in the email controlfile for the branch.
663
709
        """
667
713
                    .rstrip("\r\n"))
668
714
        except errors.NoSuchFile, e:
669
715
            pass
670
 
        
 
716
 
671
717
        return self._get_best_value('_get_user_id')
672
718
 
 
719
    def _get_change_editor(self):
 
720
        return self._get_best_value('_get_change_editor')
 
721
 
673
722
    def _get_signature_checking(self):
674
723
        """See Config._get_signature_checking."""
675
724
        return self._get_best_value('_get_signature_checking')
709
758
                        trace.warning('Value "%s" is masked by "%s" from'
710
759
                                      ' branch.conf', value, mask_value)
711
760
 
712
 
 
713
761
    def _gpg_signing_command(self):
714
762
        """See Config.gpg_signing_command."""
715
763
        return self._get_safe_value('_gpg_signing_command')
716
 
        
 
764
 
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)
726
774
 
768
816
    """Return per-user configuration directory.
769
817
 
770
818
    By default this is ~/.bazaar/
771
 
    
 
819
 
772
820
    TODO: Global option --config-dir to override this.
773
821
    """
774
822
    base = os.environ.get('BZR_HOME', None)
813
861
    return osutils.pathjoin(config_dir(), 'ignore')
814
862
 
815
863
 
 
864
def crash_dir():
 
865
    """Return the directory name to store crash files.
 
866
 
 
867
    This doesn't implicitly create it.
 
868
 
 
869
    On Windows it's in the config directory; elsewhere it's /var/crash
 
870
    which may be monitored by apport.  It can be overridden by
 
871
    $APPORT_CRASH_DIR.
 
872
    """
 
873
    if sys.platform == 'win32':
 
874
        return osutils.pathjoin(config_dir(), 'Crash')
 
875
    else:
 
876
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
877
        # 2010-01-31
 
878
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
879
 
 
880
 
 
881
def xdg_cache_dir():
 
882
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
 
883
    # Possibly this should be different on Windows?
 
884
    e = os.environ.get('XDG_CACHE_DIR', None)
 
885
    if e:
 
886
        return e
 
887
    else:
 
888
        return os.path.expanduser('~/.cache')
 
889
 
 
890
 
816
891
def _auto_user_id():
817
892
    """Calculate automatic user identification.
818
893
 
898
973
def extract_email_address(e):
899
974
    """Return just the address part of an email string.
900
975
 
901
 
    That is just the user@domain part, nothing else. 
 
976
    That is just the user@domain part, nothing else.
902
977
    This part is required to contain only ascii characters.
903
978
    If it can't be extracted, raises an error.
904
979
 
917
992
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
918
993
 
919
994
    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')
 
995
        self._config = branch._get_config()
924
996
        self.branch = branch
925
997
 
926
998
    def _get_parser(self, file=None):
934
1006
            return self._config.get_option(name, section, default)
935
1007
        finally:
936
1008
            self.branch.unlock()
937
 
        return result
938
1009
 
939
1010
    def set_option(self, value, name, section=None):
940
1011
        """Set a per-branch configuration option"""
993
1064
        section[option_name] = value
994
1065
        self._save()
995
1066
 
996
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None):
 
1067
    def get_credentials(self, scheme, host, port=None, user=None, path=None, 
 
1068
                        realm=None):
997
1069
        """Returns the matching credentials from authentication.conf file.
998
1070
 
999
1071
        :param scheme: protocol
1005
1077
        :param user: login (optional)
1006
1078
 
1007
1079
        :param path: the absolute path on the server (optional)
 
1080
        
 
1081
        :param realm: the http authentication realm (optional)
1008
1082
 
1009
1083
        :return: A dict containing the matching credentials or None.
1010
1084
           This includes:
1011
1085
           - name: the section name of the credentials in the
1012
1086
             authentication.conf file,
1013
 
           - user: can't de different from the provided user if any,
 
1087
           - user: can't be different from the provided user if any,
 
1088
           - scheme: the server protocol,
 
1089
           - host: the server address,
 
1090
           - port: the server port (can be None),
 
1091
           - path: the absolute server path (can be None),
 
1092
           - realm: the http specific authentication realm (can be None),
1014
1093
           - password: the decoded password, could be None if the credential
1015
1094
             defines only the user
1016
1095
           - verify_certificates: https specific, True if the server
1057
1136
            if a_user is None:
1058
1137
                # Can't find a user
1059
1138
                continue
 
1139
            # Prepare a credentials dictionary with additional keys
 
1140
            # for the credential providers
1060
1141
            credentials = dict(name=auth_def_name,
1061
1142
                               user=a_user,
 
1143
                               scheme=a_scheme,
 
1144
                               host=host,
 
1145
                               port=port,
 
1146
                               path=path,
 
1147
                               realm=realm,
1062
1148
                               password=auth_def.get('password', None),
1063
1149
                               verify_certificates=a_verify_certificates)
 
1150
            # Decode the password in the credentials (or get one)
1064
1151
            self.decode_password(credentials,
1065
1152
                                 auth_def.get('password_encoding', None))
1066
1153
            if 'auth' in debug.debug_flags:
1067
1154
                trace.mutter("Using authentication section: %r", auth_def_name)
1068
1155
            break
1069
1156
 
 
1157
        if credentials is None:
 
1158
            # No credentials were found in authentication.conf, try the fallback
 
1159
            # credentials stores.
 
1160
            credentials = credential_store_registry.get_fallback_credentials(
 
1161
                scheme, host, port, user, path, realm)
 
1162
 
1070
1163
        return credentials
1071
1164
 
1072
1165
    def set_credentials(self, name, host, user, scheme=None, password=None,
1073
 
                        port=None, path=None, verify_certificates=None):
 
1166
                        port=None, path=None, verify_certificates=None,
 
1167
                        realm=None):
1074
1168
        """Set authentication credentials for a host.
1075
1169
 
1076
1170
        Any existing credentials with matching scheme, host, port and path
1087
1181
            apply to.
1088
1182
        :param verify_certificates: On https, verify server certificates if
1089
1183
            True.
 
1184
        :param realm: The http authentication realm (optional).
1090
1185
        """
1091
1186
        values = {'host': host, 'user': user}
1092
1187
        if password is not None:
1099
1194
            values['path'] = path
1100
1195
        if verify_certificates is not None:
1101
1196
            values['verify_certificates'] = str(verify_certificates)
 
1197
        if realm is not None:
 
1198
            values['realm'] = realm
1102
1199
        config = self._get_config()
1103
1200
        for_deletion = []
1104
1201
        for section, existing_values in config.items():
1105
 
            for key in ('scheme', 'host', 'port', 'path'):
 
1202
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1106
1203
                if existing_values.get(key) != values.get(key):
1107
1204
                    break
1108
1205
            else:
1110
1207
        config.update({name: values})
1111
1208
        self._save()
1112
1209
 
1113
 
    def get_user(self, scheme, host, port=None,
1114
 
                 realm=None, path=None, prompt=None):
 
1210
    def get_user(self, scheme, host, port=None, realm=None, path=None,
 
1211
                 prompt=None, ask=False, default=None):
1115
1212
        """Get a user from authentication file.
1116
1213
 
1117
1214
        :param scheme: protocol
1124
1221
 
1125
1222
        :param path: the absolute path on the server (optional)
1126
1223
 
 
1224
        :param ask: Ask the user if there is no explicitly configured username 
 
1225
                    (optional)
 
1226
 
 
1227
        :param default: The username returned if none is defined (optional).
 
1228
 
1127
1229
        :return: The found user.
1128
1230
        """
1129
1231
        credentials = self.get_credentials(scheme, host, port, user=None,
1130
 
                                           path=path)
 
1232
                                           path=path, realm=realm)
1131
1233
        if credentials is not None:
1132
1234
            user = credentials['user']
1133
1235
        else:
1134
1236
            user = None
 
1237
        if user is None:
 
1238
            if ask:
 
1239
                if prompt is None:
 
1240
                    # Create a default prompt suitable for most cases
 
1241
                    prompt = scheme.upper() + ' %(host)s username'
 
1242
                # Special handling for optional fields in the prompt
 
1243
                if port is not None:
 
1244
                    prompt_host = '%s:%d' % (host, port)
 
1245
                else:
 
1246
                    prompt_host = host
 
1247
                user = ui.ui_factory.get_username(prompt, host=prompt_host)
 
1248
            else:
 
1249
                user = default
1135
1250
        return user
1136
1251
 
1137
1252
    def get_password(self, scheme, host, user, port=None,
1152
1267
 
1153
1268
        :return: The found password or the one entered by the user.
1154
1269
        """
1155
 
        credentials = self.get_credentials(scheme, host, port, user, path)
 
1270
        credentials = self.get_credentials(scheme, host, port, user, path,
 
1271
                                           realm)
1156
1272
        if credentials is not None:
1157
1273
            password = credentials['password']
1158
1274
            if password is not None and scheme is 'ssh':
1191
1307
    A credential store provides access to credentials via the password_encoding
1192
1308
    field in authentication.conf sections.
1193
1309
 
1194
 
    Except for stores provided by bzr itself,most stores are expected to be
 
1310
    Except for stores provided by bzr itself, most stores are expected to be
1195
1311
    provided by plugins that will therefore use
1196
1312
    register_lazy(password_encoding, module_name, member_name, help=help,
1197
 
    info=info) to install themselves.
 
1313
    fallback=fallback) to install themselves.
 
1314
 
 
1315
    A fallback credential store is one that is queried if no credentials can be
 
1316
    found via authentication.conf.
1198
1317
    """
1199
1318
 
1200
1319
    def get_credential_store(self, encoding=None):
1203
1322
            cs = cs()
1204
1323
        return cs
1205
1324
 
 
1325
    def is_fallback(self, name):
 
1326
        """Check if the named credentials store should be used as fallback."""
 
1327
        return self.get_info(name)
 
1328
 
 
1329
    def get_fallback_credentials(self, scheme, host, port=None, user=None,
 
1330
                                 path=None, realm=None):
 
1331
        """Request credentials from all fallback credentials stores.
 
1332
 
 
1333
        The first credentials store that can provide credentials wins.
 
1334
        """
 
1335
        credentials = None
 
1336
        for name in self.keys():
 
1337
            if not self.is_fallback(name):
 
1338
                continue
 
1339
            cs = self.get_credential_store(name)
 
1340
            credentials = cs.get_credentials(scheme, host, port, user,
 
1341
                                             path, realm)
 
1342
            if credentials is not None:
 
1343
                # We found some credentials
 
1344
                break
 
1345
        return credentials
 
1346
 
 
1347
    def register(self, key, obj, help=None, override_existing=False,
 
1348
                 fallback=False):
 
1349
        """Register a new object to a name.
 
1350
 
 
1351
        :param key: This is the key to use to request the object later.
 
1352
        :param obj: The object to register.
 
1353
        :param help: Help text for this entry. This may be a string or
 
1354
                a callable. If it is a callable, it should take two
 
1355
                parameters (registry, key): this registry and the key that
 
1356
                the help was registered under.
 
1357
        :param override_existing: Raise KeyErorr if False and something has
 
1358
                already been registered for that key. If True, ignore if there
 
1359
                is an existing key (always register the new value).
 
1360
        :param fallback: Whether this credential store should be 
 
1361
                used as fallback.
 
1362
        """
 
1363
        return super(CredentialStoreRegistry,
 
1364
                     self).register(key, obj, help, info=fallback,
 
1365
                                    override_existing=override_existing)
 
1366
 
 
1367
    def register_lazy(self, key, module_name, member_name,
 
1368
                      help=None, override_existing=False,
 
1369
                      fallback=False):
 
1370
        """Register a new credential store to be loaded on request.
 
1371
 
 
1372
        :param module_name: The python path to the module. Such as 'os.path'.
 
1373
        :param member_name: The member of the module to return.  If empty or
 
1374
                None, get() will return the module itself.
 
1375
        :param help: Help text for this entry. This may be a string or
 
1376
                a callable.
 
1377
        :param override_existing: If True, replace the existing object
 
1378
                with the new one. If False, if there is already something
 
1379
                registered with the same key, raise a KeyError
 
1380
        :param fallback: Whether this credential store should be 
 
1381
                used as fallback.
 
1382
        """
 
1383
        return super(CredentialStoreRegistry, self).register_lazy(
 
1384
            key, module_name, member_name, help,
 
1385
            info=fallback, override_existing=override_existing)
 
1386
 
1206
1387
 
1207
1388
credential_store_registry = CredentialStoreRegistry()
1208
1389
 
1211
1392
    """An abstract class to implement storage for credentials"""
1212
1393
 
1213
1394
    def decode_password(self, credentials):
1214
 
        """Returns a password for the provided credentials in clear text."""
 
1395
        """Returns a clear text password for the provided credentials."""
1215
1396
        raise NotImplementedError(self.decode_password)
1216
1397
 
 
1398
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
 
1399
                        realm=None):
 
1400
        """Return the matching credentials from this credential store.
 
1401
 
 
1402
        This method is only called on fallback credential stores.
 
1403
        """
 
1404
        raise NotImplementedError(self.get_credentials)
 
1405
 
 
1406
 
1217
1407
 
1218
1408
class PlainTextCredentialStore(CredentialStore):
1219
1409
    """Plain text credential store for the authentication.conf file."""
1230
1420
 
1231
1421
class BzrDirConfig(object):
1232
1422
 
1233
 
    def __init__(self, transport):
1234
 
        self._config = TransportConfig(transport, 'control.conf')
 
1423
    def __init__(self, bzrdir):
 
1424
        self._bzrdir = bzrdir
 
1425
        self._config = bzrdir._get_config()
1235
1426
 
1236
1427
    def set_default_stack_on(self, value):
1237
1428
        """Set the default stacking location.
1241
1432
        This policy affects all branches contained by this bzrdir, except for
1242
1433
        those under repositories.
1243
1434
        """
 
1435
        if self._config is None:
 
1436
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1244
1437
        if value is None:
1245
1438
            self._config.set_option('', 'default_stack_on')
1246
1439
        else:
1254
1447
        This policy affects all branches contained by this bzrdir, except for
1255
1448
        those under repositories.
1256
1449
        """
 
1450
        if self._config is None:
 
1451
            return None
1257
1452
        value = self._config.get_option('default_stack_on')
1258
1453
        if value == '':
1259
1454
            value = None
1304
1499
            configobj.setdefault(section, {})[name] = value
1305
1500
        self._set_configobj(configobj)
1306
1501
 
 
1502
    def _get_config_file(self):
 
1503
        try:
 
1504
            return StringIO(self._transport.get_bytes(self._filename))
 
1505
        except errors.NoSuchFile:
 
1506
            return StringIO()
 
1507
 
1307
1508
    def _get_configobj(self):
1308
 
        try:
1309
 
            return ConfigObj(self._transport.get(self._filename),
1310
 
                             encoding='utf-8')
1311
 
        except errors.NoSuchFile:
1312
 
            return ConfigObj(encoding='utf-8')
 
1509
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1313
1510
 
1314
1511
    def _set_configobj(self, configobj):
1315
1512
        out_file = StringIO()