~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Martin Pool
  • Date: 2009-07-27 06:28:35 UTC
  • mto: This revision was merged to the branch mainline in revision 4587.
  • Revision ID: mbp@sourcefrog.net-20090727062835-o66p8it658tq1sma
Add CountedLock.get_physical_lock_status

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
174
177
        """Get a generic option - no special process, no default."""
175
178
        return self._get_user_option(option_name)
176
179
 
 
180
    def get_user_option_as_bool(self, option_name):
 
181
        """Get a generic option as a boolean - no special process, no default.
 
182
 
 
183
        :return None if the option doesn't exist or its value can't be
 
184
            interpreted as a boolean. Returns True or False ortherwise.
 
185
        """
 
186
        s = self._get_user_option(option_name)
 
187
        return ui.bool_from_string(s)
 
188
 
177
189
    def gpg_signing_command(self):
178
190
        """What program should be used to sign signatures?"""
179
191
        result = self._gpg_signing_command()
196
208
        """See log_format()."""
197
209
        return None
198
210
 
199
 
    def __init__(self):
200
 
        super(Config, self).__init__()
201
 
 
202
211
    def post_commit(self):
203
212
        """An ordered list of python functions to call.
204
213
 
216
225
 
217
226
    def username(self):
218
227
        """Return email-style username.
219
 
    
 
228
 
220
229
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
221
 
        
 
230
 
222
231
        $BZR_EMAIL can be set to override this (as well as the
223
232
        deprecated $BZREMAIL), then
224
233
        the concrete policy type is checked, and finally
225
234
        $EMAIL is examined.
226
235
        If none is found, a reasonable default is (hopefully)
227
236
        created.
228
 
    
 
237
 
229
238
        TODO: Check it's reasonably well-formed.
230
239
        """
231
240
        v = os.environ.get('BZR_EMAIL')
299
308
class IniBasedConfig(Config):
300
309
    """A configuration policy that draws from ini files."""
301
310
 
 
311
    def __init__(self, get_filename):
 
312
        super(IniBasedConfig, self).__init__()
 
313
        self._get_filename = get_filename
 
314
        self._parser = None
 
315
 
302
316
    def _get_parser(self, file=None):
303
317
        if self._parser is not None:
304
318
            return self._parser
381
395
        """See Config.log_format."""
382
396
        return self._get_user_option('log_format')
383
397
 
384
 
    def __init__(self, get_filename):
385
 
        super(IniBasedConfig, self).__init__()
386
 
        self._get_filename = get_filename
387
 
        self._parser = None
388
 
        
389
398
    def _post_commit(self):
390
399
        """See Config.post_commit."""
391
400
        return self._get_user_option('post_commit')
414
423
 
415
424
    def _get_alias(self, value):
416
425
        try:
417
 
            return self._get_parser().get_value("ALIASES", 
 
426
            return self._get_parser().get_value("ALIASES",
418
427
                                                value)
419
428
        except KeyError:
420
429
            pass
642
651
 
643
652
    def _get_safe_value(self, option_name):
644
653
        """This variant of get_best_value never returns untrusted values.
645
 
        
 
654
 
646
655
        It does not return values from the branch data, because the branch may
647
656
        not be controlled by the user.
648
657
 
657
666
 
658
667
    def _get_user_id(self):
659
668
        """Return the full user id for the branch.
660
 
    
 
669
 
661
670
        e.g. "John Hacker <jhacker@example.com>"
662
671
        This is looked up in the email controlfile for the branch.
663
672
        """
667
676
                    .rstrip("\r\n"))
668
677
        except errors.NoSuchFile, e:
669
678
            pass
670
 
        
 
679
 
671
680
        return self._get_best_value('_get_user_id')
672
681
 
673
682
    def _get_signature_checking(self):
709
718
                        trace.warning('Value "%s" is masked by "%s" from'
710
719
                                      ' branch.conf', value, mask_value)
711
720
 
712
 
 
713
721
    def _gpg_signing_command(self):
714
722
        """See Config.gpg_signing_command."""
715
723
        return self._get_safe_value('_gpg_signing_command')
716
 
        
 
724
 
717
725
    def __init__(self, branch):
718
726
        super(BranchConfig, self).__init__()
719
727
        self._location_config = None
720
728
        self._branch_data_config = None
721
729
        self._global_config = None
722
730
        self.branch = branch
723
 
        self.option_sources = (self._get_location_config, 
 
731
        self.option_sources = (self._get_location_config,
724
732
                               self._get_branch_data_config,
725
733
                               self._get_global_config)
726
734
 
768
776
    """Return per-user configuration directory.
769
777
 
770
778
    By default this is ~/.bazaar/
771
 
    
 
779
 
772
780
    TODO: Global option --config-dir to override this.
773
781
    """
774
782
    base = os.environ.get('BZR_HOME', None)
898
906
def extract_email_address(e):
899
907
    """Return just the address part of an email string.
900
908
 
901
 
    That is just the user@domain part, nothing else. 
 
909
    That is just the user@domain part, nothing else.
902
910
    This part is required to contain only ascii characters.
903
911
    If it can't be extracted, raises an error.
904
912
 
917
925
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
918
926
 
919
927
    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')
 
928
        self._config = branch._get_config()
924
929
        self.branch = branch
925
930
 
926
931
    def _get_parser(self, file=None):
934
939
            return self._config.get_option(name, section, default)
935
940
        finally:
936
941
            self.branch.unlock()
937
 
        return result
938
942
 
939
943
    def set_option(self, value, name, section=None):
940
944
        """Set a per-branch configuration option"""
993
997
        section[option_name] = value
994
998
        self._save()
995
999
 
996
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None):
 
1000
    def get_credentials(self, scheme, host, port=None, user=None, path=None, 
 
1001
                        realm=None):
997
1002
        """Returns the matching credentials from authentication.conf file.
998
1003
 
999
1004
        :param scheme: protocol
1005
1010
        :param user: login (optional)
1006
1011
 
1007
1012
        :param path: the absolute path on the server (optional)
 
1013
        
 
1014
        :param realm: the http authentication realm (optional)
1008
1015
 
1009
1016
        :return: A dict containing the matching credentials or None.
1010
1017
           This includes:
1011
1018
           - name: the section name of the credentials in the
1012
1019
             authentication.conf file,
1013
 
           - user: can't de different from the provided user if any,
 
1020
           - user: can't be different from the provided user if any,
 
1021
           - scheme: the server protocol,
 
1022
           - host: the server address,
 
1023
           - port: the server port (can be None),
 
1024
           - path: the absolute server path (can be None),
 
1025
           - realm: the http specific authentication realm (can be None),
1014
1026
           - password: the decoded password, could be None if the credential
1015
1027
             defines only the user
1016
1028
           - verify_certificates: https specific, True if the server
1057
1069
            if a_user is None:
1058
1070
                # Can't find a user
1059
1071
                continue
 
1072
            # Prepare a credentials dictionary with additional keys
 
1073
            # for the credential providers
1060
1074
            credentials = dict(name=auth_def_name,
1061
1075
                               user=a_user,
 
1076
                               scheme=a_scheme,
 
1077
                               host=host,
 
1078
                               port=port,
 
1079
                               path=path,
 
1080
                               realm=realm,
1062
1081
                               password=auth_def.get('password', None),
1063
1082
                               verify_certificates=a_verify_certificates)
 
1083
            # Decode the password in the credentials (or get one)
1064
1084
            self.decode_password(credentials,
1065
1085
                                 auth_def.get('password_encoding', None))
1066
1086
            if 'auth' in debug.debug_flags:
1067
1087
                trace.mutter("Using authentication section: %r", auth_def_name)
1068
1088
            break
1069
1089
 
 
1090
        if credentials is None:
 
1091
            # No credentials were found in authentication.conf, try the fallback
 
1092
            # credentials stores.
 
1093
            credentials = credential_store_registry.get_fallback_credentials(
 
1094
                scheme, host, port, user, path, realm)
 
1095
 
1070
1096
        return credentials
1071
1097
 
1072
1098
    def set_credentials(self, name, host, user, scheme=None, password=None,
1073
 
                        port=None, path=None, verify_certificates=None):
 
1099
                        port=None, path=None, verify_certificates=None,
 
1100
                        realm=None):
1074
1101
        """Set authentication credentials for a host.
1075
1102
 
1076
1103
        Any existing credentials with matching scheme, host, port and path
1087
1114
            apply to.
1088
1115
        :param verify_certificates: On https, verify server certificates if
1089
1116
            True.
 
1117
        :param realm: The http authentication realm (optional).
1090
1118
        """
1091
1119
        values = {'host': host, 'user': user}
1092
1120
        if password is not None:
1099
1127
            values['path'] = path
1100
1128
        if verify_certificates is not None:
1101
1129
            values['verify_certificates'] = str(verify_certificates)
 
1130
        if realm is not None:
 
1131
            values['realm'] = realm
1102
1132
        config = self._get_config()
1103
1133
        for_deletion = []
1104
1134
        for section, existing_values in config.items():
1105
 
            for key in ('scheme', 'host', 'port', 'path'):
 
1135
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1106
1136
                if existing_values.get(key) != values.get(key):
1107
1137
                    break
1108
1138
            else:
1110
1140
        config.update({name: values})
1111
1141
        self._save()
1112
1142
 
1113
 
    def get_user(self, scheme, host, port=None,
1114
 
                 realm=None, path=None, prompt=None):
 
1143
    def get_user(self, scheme, host, port=None, realm=None, path=None,
 
1144
                 prompt=None, ask=False, default=None):
1115
1145
        """Get a user from authentication file.
1116
1146
 
1117
1147
        :param scheme: protocol
1124
1154
 
1125
1155
        :param path: the absolute path on the server (optional)
1126
1156
 
 
1157
        :param ask: Ask the user if there is no explicitly configured username 
 
1158
                    (optional)
 
1159
 
 
1160
        :param default: The username returned if none is defined (optional).
 
1161
 
1127
1162
        :return: The found user.
1128
1163
        """
1129
1164
        credentials = self.get_credentials(scheme, host, port, user=None,
1130
 
                                           path=path)
 
1165
                                           path=path, realm=realm)
1131
1166
        if credentials is not None:
1132
1167
            user = credentials['user']
1133
1168
        else:
1134
1169
            user = None
 
1170
        if user is None:
 
1171
            if ask:
 
1172
                if prompt is None:
 
1173
                    # Create a default prompt suitable for most cases
 
1174
                    prompt = scheme.upper() + ' %(host)s username'
 
1175
                # Special handling for optional fields in the prompt
 
1176
                if port is not None:
 
1177
                    prompt_host = '%s:%d' % (host, port)
 
1178
                else:
 
1179
                    prompt_host = host
 
1180
                user = ui.ui_factory.get_username(prompt, host=prompt_host)
 
1181
            else:
 
1182
                user = default
1135
1183
        return user
1136
1184
 
1137
1185
    def get_password(self, scheme, host, user, port=None,
1152
1200
 
1153
1201
        :return: The found password or the one entered by the user.
1154
1202
        """
1155
 
        credentials = self.get_credentials(scheme, host, port, user, path)
 
1203
        credentials = self.get_credentials(scheme, host, port, user, path,
 
1204
                                           realm)
1156
1205
        if credentials is not None:
1157
1206
            password = credentials['password']
1158
1207
            if password is not None and scheme is 'ssh':
1191
1240
    A credential store provides access to credentials via the password_encoding
1192
1241
    field in authentication.conf sections.
1193
1242
 
1194
 
    Except for stores provided by bzr itself,most stores are expected to be
 
1243
    Except for stores provided by bzr itself, most stores are expected to be
1195
1244
    provided by plugins that will therefore use
1196
1245
    register_lazy(password_encoding, module_name, member_name, help=help,
1197
 
    info=info) to install themselves.
 
1246
    fallback=fallback) to install themselves.
 
1247
 
 
1248
    A fallback credential store is one that is queried if no credentials can be
 
1249
    found via authentication.conf.
1198
1250
    """
1199
1251
 
1200
1252
    def get_credential_store(self, encoding=None):
1203
1255
            cs = cs()
1204
1256
        return cs
1205
1257
 
 
1258
    def is_fallback(self, name):
 
1259
        """Check if the named credentials store should be used as fallback."""
 
1260
        return self.get_info(name)
 
1261
 
 
1262
    def get_fallback_credentials(self, scheme, host, port=None, user=None,
 
1263
                                 path=None, realm=None):
 
1264
        """Request credentials from all fallback credentials stores.
 
1265
 
 
1266
        The first credentials store that can provide credentials wins.
 
1267
        """
 
1268
        credentials = None
 
1269
        for name in self.keys():
 
1270
            if not self.is_fallback(name):
 
1271
                continue
 
1272
            cs = self.get_credential_store(name)
 
1273
            credentials = cs.get_credentials(scheme, host, port, user,
 
1274
                                             path, realm)
 
1275
            if credentials is not None:
 
1276
                # We found some credentials
 
1277
                break
 
1278
        return credentials
 
1279
 
 
1280
    def register(self, key, obj, help=None, override_existing=False,
 
1281
                 fallback=False):
 
1282
        """Register a new object to a name.
 
1283
 
 
1284
        :param key: This is the key to use to request the object later.
 
1285
        :param obj: The object to register.
 
1286
        :param help: Help text for this entry. This may be a string or
 
1287
                a callable. If it is a callable, it should take two
 
1288
                parameters (registry, key): this registry and the key that
 
1289
                the help was registered under.
 
1290
        :param override_existing: Raise KeyErorr if False and something has
 
1291
                already been registered for that key. If True, ignore if there
 
1292
                is an existing key (always register the new value).
 
1293
        :param fallback: Whether this credential store should be 
 
1294
                used as fallback.
 
1295
        """
 
1296
        return super(CredentialStoreRegistry,
 
1297
                     self).register(key, obj, help, info=fallback,
 
1298
                                    override_existing=override_existing)
 
1299
 
 
1300
    def register_lazy(self, key, module_name, member_name,
 
1301
                      help=None, override_existing=False,
 
1302
                      fallback=False):
 
1303
        """Register a new credential store to be loaded on request.
 
1304
 
 
1305
        :param module_name: The python path to the module. Such as 'os.path'.
 
1306
        :param member_name: The member of the module to return.  If empty or
 
1307
                None, get() will return the module itself.
 
1308
        :param help: Help text for this entry. This may be a string or
 
1309
                a callable.
 
1310
        :param override_existing: If True, replace the existing object
 
1311
                with the new one. If False, if there is already something
 
1312
                registered with the same key, raise a KeyError
 
1313
        :param fallback: Whether this credential store should be 
 
1314
                used as fallback.
 
1315
        """
 
1316
        return super(CredentialStoreRegistry, self).register_lazy(
 
1317
            key, module_name, member_name, help,
 
1318
            info=fallback, override_existing=override_existing)
 
1319
 
1206
1320
 
1207
1321
credential_store_registry = CredentialStoreRegistry()
1208
1322
 
1211
1325
    """An abstract class to implement storage for credentials"""
1212
1326
 
1213
1327
    def decode_password(self, credentials):
1214
 
        """Returns a password for the provided credentials in clear text."""
 
1328
        """Returns a clear text password for the provided credentials."""
1215
1329
        raise NotImplementedError(self.decode_password)
1216
1330
 
 
1331
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
 
1332
                        realm=None):
 
1333
        """Return the matching credentials from this credential store.
 
1334
 
 
1335
        This method is only called on fallback credential stores.
 
1336
        """
 
1337
        raise NotImplementedError(self.get_credentials)
 
1338
 
 
1339
 
1217
1340
 
1218
1341
class PlainTextCredentialStore(CredentialStore):
1219
1342
    """Plain text credential store for the authentication.conf file."""
1230
1353
 
1231
1354
class BzrDirConfig(object):
1232
1355
 
1233
 
    def __init__(self, transport):
1234
 
        self._config = TransportConfig(transport, 'control.conf')
 
1356
    def __init__(self, bzrdir):
 
1357
        self._bzrdir = bzrdir
 
1358
        self._config = bzrdir._get_config()
1235
1359
 
1236
1360
    def set_default_stack_on(self, value):
1237
1361
        """Set the default stacking location.
1241
1365
        This policy affects all branches contained by this bzrdir, except for
1242
1366
        those under repositories.
1243
1367
        """
 
1368
        if self._config is None:
 
1369
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1244
1370
        if value is None:
1245
1371
            self._config.set_option('', 'default_stack_on')
1246
1372
        else:
1254
1380
        This policy affects all branches contained by this bzrdir, except for
1255
1381
        those under repositories.
1256
1382
        """
 
1383
        if self._config is None:
 
1384
            return None
1257
1385
        value = self._config.get_option('default_stack_on')
1258
1386
        if value == '':
1259
1387
            value = None
1304
1432
            configobj.setdefault(section, {})[name] = value
1305
1433
        self._set_configobj(configobj)
1306
1434
 
 
1435
    def _get_config_file(self):
 
1436
        try:
 
1437
            return self._transport.get(self._filename)
 
1438
        except errors.NoSuchFile:
 
1439
            return StringIO()
 
1440
 
1307
1441
    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')
 
1442
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1313
1443
 
1314
1444
    def _set_configobj(self, configobj):
1315
1445
        out_file = StringIO()