~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Andrew Bennetts
  • Date: 2010-01-15 05:30:30 UTC
  • mto: (4973.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4975.
  • Revision ID: andrew.bennetts@canonical.com-20100115053030-1d6qd89pnj8hmb55
Pass kinds (not pairs) to MergeHookParams.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 in the XDG cache directory.
 
870
    """
 
871
    if sys.platform == 'win32':
 
872
        return osutils.pathjoin(config_dir(), 'Crash')
 
873
    else:
 
874
        return osutils.pathjoin(xdg_cache_dir(), 'crash')
 
875
 
 
876
 
 
877
def xdg_cache_dir():
 
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)
 
881
    if e:
 
882
        return e
 
883
    else:
 
884
        return os.path.expanduser('~/.cache')
 
885
 
 
886
 
816
887
def _auto_user_id():
817
888
    """Calculate automatic user identification.
818
889
 
898
969
def extract_email_address(e):
899
970
    """Return just the address part of an email string.
900
971
 
901
 
    That is just the user@domain part, nothing else. 
 
972
    That is just the user@domain part, nothing else.
902
973
    This part is required to contain only ascii characters.
903
974
    If it can't be extracted, raises an error.
904
975
 
917
988
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
918
989
 
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
925
993
 
926
994
    def _get_parser(self, file=None):
934
1002
            return self._config.get_option(name, section, default)
935
1003
        finally:
936
1004
            self.branch.unlock()
937
 
        return result
938
1005
 
939
1006
    def set_option(self, value, name, section=None):
940
1007
        """Set a per-branch configuration option"""
993
1060
        section[option_name] = value
994
1061
        self._save()
995
1062
 
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, 
 
1064
                        realm=None):
997
1065
        """Returns the matching credentials from authentication.conf file.
998
1066
 
999
1067
        :param scheme: protocol
1005
1073
        :param user: login (optional)
1006
1074
 
1007
1075
        :param path: the absolute path on the server (optional)
 
1076
        
 
1077
        :param realm: the http authentication realm (optional)
1008
1078
 
1009
1079
        :return: A dict containing the matching credentials or None.
1010
1080
           This includes:
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
1059
1134
                continue
 
1135
            # Prepare a credentials dictionary with additional keys
 
1136
            # for the credential providers
1060
1137
            credentials = dict(name=auth_def_name,
1061
1138
                               user=a_user,
 
1139
                               scheme=a_scheme,
 
1140
                               host=host,
 
1141
                               port=port,
 
1142
                               path=path,
 
1143
                               realm=realm,
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)
1068
1151
            break
1069
1152
 
 
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)
 
1158
 
1070
1159
        return credentials
1071
1160
 
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,
 
1163
                        realm=None):
1074
1164
        """Set authentication credentials for a host.
1075
1165
 
1076
1166
        Any existing credentials with matching scheme, host, port and path
1087
1177
            apply to.
1088
1178
        :param verify_certificates: On https, verify server certificates if
1089
1179
            True.
 
1180
        :param realm: The http authentication realm (optional).
1090
1181
        """
1091
1182
        values = {'host': host, 'user': user}
1092
1183
        if password is not None:
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):
1107
1200
                    break
1108
1201
            else:
1110
1203
        config.update({name: values})
1111
1204
        self._save()
1112
1205
 
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.
1116
1209
 
1117
1210
        :param scheme: protocol
1124
1217
 
1125
1218
        :param path: the absolute path on the server (optional)
1126
1219
 
 
1220
        :param ask: Ask the user if there is no explicitly configured username 
 
1221
                    (optional)
 
1222
 
 
1223
        :param default: The username returned if none is defined (optional).
 
1224
 
1127
1225
        :return: The found user.
1128
1226
        """
1129
1227
        credentials = self.get_credentials(scheme, host, port, user=None,
1130
 
                                           path=path)
 
1228
                                           path=path, realm=realm)
1131
1229
        if credentials is not None:
1132
1230
            user = credentials['user']
1133
1231
        else:
1134
1232
            user = None
 
1233
        if user is None:
 
1234
            if ask:
 
1235
                if prompt is None:
 
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)
 
1241
                else:
 
1242
                    prompt_host = host
 
1243
                user = ui.ui_factory.get_username(prompt, host=prompt_host)
 
1244
            else:
 
1245
                user = default
1135
1246
        return user
1136
1247
 
1137
1248
    def get_password(self, scheme, host, user, port=None,
1152
1263
 
1153
1264
        :return: The found password or the one entered by the user.
1154
1265
        """
1155
 
        credentials = self.get_credentials(scheme, host, port, user, path)
 
1266
        credentials = self.get_credentials(scheme, host, port, user, path,
 
1267
                                           realm)
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.
1193
1305
 
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.
 
1310
 
 
1311
    A fallback credential store is one that is queried if no credentials can be
 
1312
    found via authentication.conf.
1198
1313
    """
1199
1314
 
1200
1315
    def get_credential_store(self, encoding=None):
1203
1318
            cs = cs()
1204
1319
        return cs
1205
1320
 
 
1321
    def is_fallback(self, name):
 
1322
        """Check if the named credentials store should be used as fallback."""
 
1323
        return self.get_info(name)
 
1324
 
 
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.
 
1328
 
 
1329
        The first credentials store that can provide credentials wins.
 
1330
        """
 
1331
        credentials = None
 
1332
        for name in self.keys():
 
1333
            if not self.is_fallback(name):
 
1334
                continue
 
1335
            cs = self.get_credential_store(name)
 
1336
            credentials = cs.get_credentials(scheme, host, port, user,
 
1337
                                             path, realm)
 
1338
            if credentials is not None:
 
1339
                # We found some credentials
 
1340
                break
 
1341
        return credentials
 
1342
 
 
1343
    def register(self, key, obj, help=None, override_existing=False,
 
1344
                 fallback=False):
 
1345
        """Register a new object to a name.
 
1346
 
 
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 
 
1357
                used as fallback.
 
1358
        """
 
1359
        return super(CredentialStoreRegistry,
 
1360
                     self).register(key, obj, help, info=fallback,
 
1361
                                    override_existing=override_existing)
 
1362
 
 
1363
    def register_lazy(self, key, module_name, member_name,
 
1364
                      help=None, override_existing=False,
 
1365
                      fallback=False):
 
1366
        """Register a new credential store to be loaded on request.
 
1367
 
 
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
 
1372
                a callable.
 
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 
 
1377
                used as fallback.
 
1378
        """
 
1379
        return super(CredentialStoreRegistry, self).register_lazy(
 
1380
            key, module_name, member_name, help,
 
1381
            info=fallback, override_existing=override_existing)
 
1382
 
1206
1383
 
1207
1384
credential_store_registry = CredentialStoreRegistry()
1208
1385
 
1211
1388
    """An abstract class to implement storage for credentials"""
1212
1389
 
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)
1216
1393
 
 
1394
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
 
1395
                        realm=None):
 
1396
        """Return the matching credentials from this credential store.
 
1397
 
 
1398
        This method is only called on fallback credential stores.
 
1399
        """
 
1400
        raise NotImplementedError(self.get_credentials)
 
1401
 
 
1402
 
1217
1403
 
1218
1404
class PlainTextCredentialStore(CredentialStore):
1219
1405
    """Plain text credential store for the authentication.conf file."""
1230
1416
 
1231
1417
class BzrDirConfig(object):
1232
1418
 
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()
1235
1422
 
1236
1423
    def set_default_stack_on(self, value):
1237
1424
        """Set the default stacking location.
1241
1428
        This policy affects all branches contained by this bzrdir, except for
1242
1429
        those under repositories.
1243
1430
        """
 
1431
        if self._config is None:
 
1432
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1244
1433
        if value is None:
1245
1434
            self._config.set_option('', 'default_stack_on')
1246
1435
        else:
1254
1443
        This policy affects all branches contained by this bzrdir, except for
1255
1444
        those under repositories.
1256
1445
        """
 
1446
        if self._config is None:
 
1447
            return None
1257
1448
        value = self._config.get_option('default_stack_on')
1258
1449
        if value == '':
1259
1450
            value = None
1304
1495
            configobj.setdefault(section, {})[name] = value
1305
1496
        self._set_configobj(configobj)
1306
1497
 
 
1498
    def _get_config_file(self):
 
1499
        try:
 
1500
            return StringIO(self._transport.get_bytes(self._filename))
 
1501
        except errors.NoSuchFile:
 
1502
            return StringIO()
 
1503
 
1307
1504
    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')
 
1505
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1313
1506
 
1314
1507
    def _set_configobj(self, configobj):
1315
1508
        out_file = StringIO()