~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Martin Pool
  • Date: 2005-11-04 01:46:31 UTC
  • mto: (1185.33.49 bzr.dev)
  • mto: This revision was merged to the branch mainline in revision 1512.
  • Revision ID: mbp@sourcefrog.net-20051104014631-750e0ad4172c952c
Make biobench directly executable

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007 Canonical Ltd
 
1
# Copyright (C) 2005 by Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
 
#            and others
4
3
#
5
4
# This program is free software; you can redistribute it and/or modify
6
5
# it under the terms of the GNU General Public License as published by
19
18
"""Configuration that affects the behaviour of Bazaar.
20
19
 
21
20
Currently this configuration resides in ~/.bazaar/bazaar.conf
22
 
and ~/.bazaar/locations.conf, which is written to by bzr.
 
21
and ~/.bazaar/branches.conf, which is written to by bzr.
23
22
 
24
23
In bazaar.conf the following options may be set:
25
24
[DEFAULT]
28
27
check_signatures=require|ignore|check-available(default)
29
28
create_signatures=always|never|when-required(default)
30
29
gpg_signing_command=name-of-program
31
 
log_format=name-of-format
32
30
 
33
 
in locations.conf, you specify the url of a branch and options for it.
 
31
in branches.conf, you specify the url of a branch and options for it.
34
32
Wildcards may be used - * and ? as normal in shell completion. Options
35
 
set in both bazaar.conf and locations.conf are overridden by the locations.conf
 
33
set in both bazaar.conf and branches.conf are overriden by the branches.conf
36
34
setting.
37
35
[/home/robertc/source]
38
36
recurse=False|True(default)
39
37
email= as above
40
 
check_signatures= as above 
 
38
check_signatures= as abive 
41
39
create_signatures= as above.
42
40
 
43
41
explanation of options
50
48
create_signatures - this option controls whether bzr will always create 
51
49
                    gpg signatures, never create them, or create them if the
52
50
                    branch is configured to require them.
53
 
log_format - this option sets the default log format.  Possible values are
54
 
             long, short, line, or a plugin can register new formats.
55
 
 
56
 
In bazaar.conf you can also define aliases in the ALIASES sections, example
57
 
 
58
 
[ALIASES]
59
 
lastlog=log --line -r-10..-1
60
 
ll=log --line -r-10..-1
61
 
h=help
62
 
up=pull
 
51
                    NB: This option is planned, but not implemented yet.
63
52
"""
64
53
 
 
54
 
 
55
import errno
65
56
import os
66
 
import sys
67
 
 
68
 
from bzrlib.lazy_import import lazy_import
69
 
lazy_import(globals(), """
70
 
import errno
71
57
from fnmatch import fnmatch
72
58
import re
73
 
from cStringIO import StringIO
74
59
 
75
60
import bzrlib
76
 
from bzrlib import (
77
 
    debug,
78
 
    errors,
79
 
    mail_client,
80
 
    osutils,
81
 
    symbol_versioning,
82
 
    trace,
83
 
    ui,
84
 
    urlutils,
85
 
    win32utils,
86
 
    )
87
 
from bzrlib.util.configobj import configobj
88
 
""")
 
61
import bzrlib.errors as errors
 
62
import bzrlib.util.configobj.configobj as configobj
89
63
 
90
64
 
91
65
CHECK_IF_POSSIBLE=0
93
67
CHECK_NEVER=2
94
68
 
95
69
 
96
 
SIGN_WHEN_REQUIRED=0
97
 
SIGN_ALWAYS=1
98
 
SIGN_NEVER=2
99
 
 
100
 
 
101
 
POLICY_NONE = 0
102
 
POLICY_NORECURSE = 1
103
 
POLICY_APPENDPATH = 2
104
 
 
105
 
_policy_name = {
106
 
    POLICY_NONE: None,
107
 
    POLICY_NORECURSE: 'norecurse',
108
 
    POLICY_APPENDPATH: 'appendpath',
109
 
    }
110
 
_policy_value = {
111
 
    None: POLICY_NONE,
112
 
    'none': POLICY_NONE,
113
 
    'norecurse': POLICY_NORECURSE,
114
 
    'appendpath': POLICY_APPENDPATH,
115
 
    }
116
 
 
117
 
 
118
 
STORE_LOCATION = POLICY_NONE
119
 
STORE_LOCATION_NORECURSE = POLICY_NORECURSE
120
 
STORE_LOCATION_APPENDPATH = POLICY_APPENDPATH
121
 
STORE_BRANCH = 3
122
 
STORE_GLOBAL = 4
123
 
 
124
 
 
125
70
class ConfigObj(configobj.ConfigObj):
126
71
 
127
72
    def get_bool(self, section, key):
128
 
        return self[section].as_bool(key)
 
73
        val = self[section][key].lower()
 
74
        if val in ('1', 'yes', 'true', 'on'):
 
75
            return True
 
76
        elif val in ('0', 'no', 'false', 'off'):
 
77
            return False
 
78
        else:
 
79
            raise ValueError("Value %r is not boolean" % val)
129
80
 
130
81
    def get_value(self, section, name):
131
82
        # Try [] for the old DEFAULT section.
144
95
        """Get the users pop up editor."""
145
96
        raise NotImplementedError
146
97
 
147
 
    def get_mail_client(self):
148
 
        """Get a mail client to use"""
149
 
        selected_client = self.get_user_option('mail_client')
150
 
        try:
151
 
            mail_client_class = {
152
 
                None: mail_client.DefaultMail,
153
 
                # Specific clients
154
 
                'evolution': mail_client.Evolution,
155
 
                'kmail': mail_client.KMail,
156
 
                'mutt': mail_client.Mutt,
157
 
                'thunderbird': mail_client.Thunderbird,
158
 
                # Generic options
159
 
                'default': mail_client.DefaultMail,
160
 
                'editor': mail_client.Editor,
161
 
                'mapi': mail_client.MAPIClient,
162
 
                'xdg-email': mail_client.XDGEmail,
163
 
            }[selected_client]
164
 
        except KeyError:
165
 
            raise errors.UnknownMailClient(selected_client)
166
 
        return mail_client_class(self)
167
 
 
168
98
    def _get_signature_checking(self):
169
99
        """Template method to override signature checking policy."""
170
100
 
171
 
    def _get_signing_policy(self):
172
 
        """Template method to override signature creation policy."""
173
 
 
174
101
    def _get_user_option(self, option_name):
175
102
        """Template method to provide a user option."""
176
103
        return None
190
117
        """See gpg_signing_command()."""
191
118
        return None
192
119
 
193
 
    def log_format(self):
194
 
        """What log format should be used"""
195
 
        result = self._log_format()
196
 
        if result is None:
197
 
            result = "long"
198
 
        return result
199
 
 
200
 
    def _log_format(self):
201
 
        """See log_format()."""
202
 
        return None
203
 
 
204
120
    def __init__(self):
205
121
        super(Config, self).__init__()
206
122
 
217
133
 
218
134
    def user_email(self):
219
135
        """Return just the email component of a username."""
220
 
        return extract_email_address(self.username())
 
136
        e = self.username()
 
137
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
138
        if not m:
 
139
            raise BzrError("%r doesn't seem to contain "
 
140
                           "a reasonable email address" % e)
 
141
        return m.group(0)
221
142
 
222
143
    def username(self):
223
144
        """Return email-style username.
224
145
    
225
146
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
226
147
        
227
 
        $BZR_EMAIL can be set to override this (as well as the
228
 
        deprecated $BZREMAIL), then
 
148
        $BZREMAIL can be set to override this, then
229
149
        the concrete policy type is checked, and finally
230
 
        $EMAIL is examined.
231
 
        If none is found, a reasonable default is (hopefully)
 
150
        $EMAIL is examinged.
 
151
        but if none is found, a reasonable default is (hopefully)
232
152
        created.
233
153
    
234
154
        TODO: Check it's reasonably well-formed.
235
155
        """
236
 
        v = os.environ.get('BZR_EMAIL')
 
156
        v = os.environ.get('BZREMAIL')
237
157
        if v:
238
158
            return v.decode(bzrlib.user_encoding)
239
 
 
 
159
    
240
160
        v = self._get_user_id()
241
161
        if v:
242
162
            return v
243
 
 
 
163
        
244
164
        v = os.environ.get('EMAIL')
245
165
        if v:
246
166
            return v.decode(bzrlib.user_encoding)
258
178
            return policy
259
179
        return CHECK_IF_POSSIBLE
260
180
 
261
 
    def signing_policy(self):
262
 
        """What is the current policy for signature checking?."""
263
 
        policy = self._get_signing_policy()
264
 
        if policy is not None:
265
 
            return policy
266
 
        return SIGN_WHEN_REQUIRED
267
 
 
268
181
    def signature_needed(self):
269
182
        """Is a signature needed when committing ?."""
270
 
        policy = self._get_signing_policy()
271
 
        if policy is None:
272
 
            policy = self._get_signature_checking()
273
 
            if policy is not None:
274
 
                trace.warning("Please use create_signatures,"
275
 
                              " not check_signatures to set signing policy.")
276
 
            if policy == CHECK_ALWAYS:
277
 
                return True
278
 
        elif policy == SIGN_ALWAYS:
 
183
        policy = self._get_signature_checking()
 
184
        if policy == CHECK_ALWAYS:
279
185
            return True
280
186
        return False
281
187
 
282
 
    def get_alias(self, value):
283
 
        return self._get_alias(value)
284
 
 
285
 
    def _get_alias(self, value):
286
 
        pass
287
 
 
288
 
    def get_nickname(self):
289
 
        return self._get_nickname()
290
 
 
291
 
    def _get_nickname(self):
292
 
        return None
293
 
 
294
 
    def get_bzr_remote_path(self):
295
 
        try:
296
 
            return os.environ['BZR_REMOTE_PATH']
297
 
        except KeyError:
298
 
            path = self.get_user_option("bzr_remote_path")
299
 
            if path is None:
300
 
                path = 'bzr'
301
 
            return path
302
 
 
303
188
 
304
189
class IniBasedConfig(Config):
305
190
    """A configuration policy that draws from ini files."""
312
197
        else:
313
198
            input = file
314
199
        try:
315
 
            self._parser = ConfigObj(input, encoding='utf-8')
 
200
            self._parser = ConfigObj(input)
316
201
        except configobj.ConfigObjError, e:
317
202
            raise errors.ParseConfigError(e.errors, e.config.filename)
318
203
        return self._parser
319
204
 
320
 
    def _get_matching_sections(self):
321
 
        """Return an ordered list of (section_name, extra_path) pairs.
322
 
 
323
 
        If the section contains inherited configuration, extra_path is
324
 
        a string containing the additional path components.
325
 
        """
326
 
        section = self._get_section()
327
 
        if section is not None:
328
 
            return [(section, '')]
329
 
        else:
330
 
            return []
331
 
 
332
205
    def _get_section(self):
333
206
        """Override this to define the section used by the config."""
334
207
        return "DEFAULT"
335
208
 
336
 
    def _get_option_policy(self, section, option_name):
337
 
        """Return the policy for the given (section, option_name) pair."""
338
 
        return POLICY_NONE
339
 
 
340
209
    def _get_signature_checking(self):
341
210
        """See Config._get_signature_checking."""
342
211
        policy = self._get_user_option('check_signatures')
343
212
        if policy:
344
213
            return self._string_to_signature_policy(policy)
345
214
 
346
 
    def _get_signing_policy(self):
347
 
        """See Config._get_signing_policy"""
348
 
        policy = self._get_user_option('create_signatures')
349
 
        if policy:
350
 
            return self._string_to_signing_policy(policy)
351
 
 
352
215
    def _get_user_id(self):
353
216
        """Get the user id from the 'email' key in the current section."""
354
217
        return self._get_user_option('email')
355
218
 
356
219
    def _get_user_option(self, option_name):
357
220
        """See Config._get_user_option."""
358
 
        for (section, extra_path) in self._get_matching_sections():
359
 
            try:
360
 
                value = self._get_parser().get_value(section, option_name)
361
 
            except KeyError:
362
 
                continue
363
 
            policy = self._get_option_policy(section, option_name)
364
 
            if policy == POLICY_NONE:
365
 
                return value
366
 
            elif policy == POLICY_NORECURSE:
367
 
                # norecurse items only apply to the exact path
368
 
                if extra_path:
369
 
                    continue
370
 
                else:
371
 
                    return value
372
 
            elif policy == POLICY_APPENDPATH:
373
 
                if extra_path:
374
 
                    value = urlutils.join(value, extra_path)
375
 
                return value
376
 
            else:
377
 
                raise AssertionError('Unexpected config policy %r' % policy)
378
 
        else:
379
 
            return None
 
221
        try:
 
222
            return self._get_parser().get_value(self._get_section(),
 
223
                                                option_name)
 
224
        except KeyError:
 
225
            pass
380
226
 
381
227
    def _gpg_signing_command(self):
382
228
        """See Config.gpg_signing_command."""
383
229
        return self._get_user_option('gpg_signing_command')
384
230
 
385
 
    def _log_format(self):
386
 
        """See Config.log_format."""
387
 
        return self._get_user_option('log_format')
388
 
 
389
231
    def __init__(self, get_filename):
390
232
        super(IniBasedConfig, self).__init__()
391
233
        self._get_filename = get_filename
406
248
        raise errors.BzrError("Invalid signatures policy '%s'"
407
249
                              % signature_string)
408
250
 
409
 
    def _string_to_signing_policy(self, signature_string):
410
 
        """Convert a string to a signing policy."""
411
 
        if signature_string.lower() == 'when-required':
412
 
            return SIGN_WHEN_REQUIRED
413
 
        if signature_string.lower() == 'never':
414
 
            return SIGN_NEVER
415
 
        if signature_string.lower() == 'always':
416
 
            return SIGN_ALWAYS
417
 
        raise errors.BzrError("Invalid signing policy '%s'"
418
 
                              % signature_string)
419
 
 
420
 
    def _get_alias(self, value):
421
 
        try:
422
 
            return self._get_parser().get_value("ALIASES", 
423
 
                                                value)
424
 
        except KeyError:
425
 
            pass
426
 
 
427
 
    def _get_nickname(self):
428
 
        return self.get_user_option('nickname')
429
 
 
430
251
 
431
252
class GlobalConfig(IniBasedConfig):
432
253
    """The configuration that should be used for a specific location."""
437
258
    def __init__(self):
438
259
        super(GlobalConfig, self).__init__(config_filename)
439
260
 
440
 
    def set_user_option(self, option, value):
441
 
        """Save option and its value in the configuration."""
442
 
        # FIXME: RBC 20051029 This should refresh the parser and also take a
443
 
        # file lock on bazaar.conf.
444
 
        conf_dir = os.path.dirname(self._get_filename())
445
 
        ensure_config_dir_exists(conf_dir)
446
 
        if 'DEFAULT' not in self._get_parser():
447
 
            self._get_parser()['DEFAULT'] = {}
448
 
        self._get_parser()['DEFAULT'][option] = value
449
 
        f = open(self._get_filename(), 'wb')
450
 
        self._get_parser().write(f)
451
 
        f.close()
452
 
 
453
261
 
454
262
class LocationConfig(IniBasedConfig):
455
263
    """A configuration object that gives the policy for a location."""
456
264
 
457
265
    def __init__(self, location):
458
 
        name_generator = locations_config_filename
459
 
        if (not os.path.exists(name_generator()) and
460
 
                os.path.exists(branches_config_filename())):
461
 
            if sys.platform == 'win32':
462
 
                trace.warning('Please rename %s to %s'
463
 
                              % (branches_config_filename(),
464
 
                                 locations_config_filename()))
465
 
            else:
466
 
                trace.warning('Please rename ~/.bazaar/branches.conf'
467
 
                              ' to ~/.bazaar/locations.conf')
468
 
            name_generator = branches_config_filename
469
 
        super(LocationConfig, self).__init__(name_generator)
470
 
        # local file locations are looked up by local path, rather than
471
 
        # by file url. This is because the config file is a user
472
 
        # file, and we would rather not expose the user to file urls.
473
 
        if location.startswith('file://'):
474
 
            location = urlutils.local_path_from_url(location)
 
266
        super(LocationConfig, self).__init__(branches_config_filename)
 
267
        self._global_config = None
475
268
        self.location = location
476
269
 
477
 
    def _get_matching_sections(self):
478
 
        """Return an ordered list of section names matching this location."""
 
270
    def _get_global_config(self):
 
271
        if self._global_config is None:
 
272
            self._global_config = GlobalConfig()
 
273
        return self._global_config
 
274
 
 
275
    def _get_section(self):
 
276
        """Get the section we should look in for config items.
 
277
 
 
278
        Returns None if none exists. 
 
279
        TODO: perhaps return a NullSection that thunks through to the 
 
280
              global config.
 
281
        """
479
282
        sections = self._get_parser()
480
283
        location_names = self.location.split('/')
481
284
        if self.location.endswith('/'):
482
285
            del location_names[-1]
483
286
        matches=[]
484
287
        for section in sections:
485
 
            # location is a local path if possible, so we need
486
 
            # to convert 'file://' urls to local paths if necessary.
487
 
            # This also avoids having file:///path be a more exact
488
 
            # match than '/path'.
489
 
            if section.startswith('file://'):
490
 
                section_path = urlutils.local_path_from_url(section)
491
 
            else:
492
 
                section_path = section
493
 
            section_names = section_path.split('/')
 
288
            section_names = section.split('/')
494
289
            if section.endswith('/'):
495
290
                del section_names[-1]
496
291
            names = zip(location_names, section_names)
505
300
            # if section is longer, no match.
506
301
            if len(section_names) > len(location_names):
507
302
                continue
508
 
            matches.append((len(section_names), section,
509
 
                            '/'.join(location_names[len(section_names):])))
 
303
            # if path is longer, and recurse is not true, no match
 
304
            if len(section_names) < len(location_names):
 
305
                try:
 
306
                    if not self._get_parser().get_bool(section, 'recurse'):
 
307
                        continue
 
308
                except KeyError:
 
309
                    pass
 
310
            matches.append((len(section_names), section))
 
311
        if not len(matches):
 
312
            return None
510
313
        matches.sort(reverse=True)
511
 
        sections = []
512
 
        for (length, section, extra_path) in matches:
513
 
            sections.append((section, extra_path))
514
 
            # should we stop looking for parent configs here?
515
 
            try:
516
 
                if self._get_parser()[section].as_bool('ignore_parents'):
517
 
                    break
518
 
            except KeyError:
519
 
                pass
520
 
        return sections
521
 
 
522
 
    def _get_option_policy(self, section, option_name):
523
 
        """Return the policy for the given (section, option_name) pair."""
524
 
        # check for the old 'recurse=False' flag
525
 
        try:
526
 
            recurse = self._get_parser()[section].as_bool('recurse')
527
 
        except KeyError:
528
 
            recurse = True
529
 
        if not recurse:
530
 
            return POLICY_NORECURSE
531
 
 
532
 
        policy_key = option_name + ':policy'
533
 
        try:
534
 
            policy_name = self._get_parser()[section][policy_key]
535
 
        except KeyError:
536
 
            policy_name = None
537
 
 
538
 
        return _policy_value[policy_name]
539
 
 
540
 
    def _set_option_policy(self, section, option_name, option_policy):
541
 
        """Set the policy for the given option name in the given section."""
542
 
        # The old recurse=False option affects all options in the
543
 
        # section.  To handle multiple policies in the section, we
544
 
        # need to convert it to a policy_norecurse key.
545
 
        try:
546
 
            recurse = self._get_parser()[section].as_bool('recurse')
547
 
        except KeyError:
548
 
            pass
549
 
        else:
550
 
            symbol_versioning.warn(
551
 
                'The recurse option is deprecated as of 0.14.  '
552
 
                'The section "%s" has been converted to use policies.'
553
 
                % section,
554
 
                DeprecationWarning)
555
 
            del self._get_parser()[section]['recurse']
556
 
            if not recurse:
557
 
                for key in self._get_parser()[section].keys():
558
 
                    if not key.endswith(':policy'):
559
 
                        self._get_parser()[section][key +
560
 
                                                    ':policy'] = 'norecurse'
561
 
 
562
 
        policy_key = option_name + ':policy'
563
 
        policy_name = _policy_name[option_policy]
564
 
        if policy_name is not None:
565
 
            self._get_parser()[section][policy_key] = policy_name
566
 
        else:
567
 
            if policy_key in self._get_parser()[section]:
568
 
                del self._get_parser()[section][policy_key]
569
 
 
570
 
    def set_user_option(self, option, value, store=STORE_LOCATION):
 
314
        return matches[0][1]
 
315
 
 
316
    def _gpg_signing_command(self):
 
317
        """See Config.gpg_signing_command."""
 
318
        command = super(LocationConfig, self)._gpg_signing_command()
 
319
        if command is not None:
 
320
            return command
 
321
        return self._get_global_config()._gpg_signing_command()
 
322
 
 
323
    def _get_user_id(self):
 
324
        user_id = super(LocationConfig, self)._get_user_id()
 
325
        if user_id is not None:
 
326
            return user_id
 
327
        return self._get_global_config()._get_user_id()
 
328
 
 
329
    def _get_user_option(self, option_name):
 
330
        """See Config._get_user_option."""
 
331
        option_value = super(LocationConfig, 
 
332
                             self)._get_user_option(option_name)
 
333
        if option_value is not None:
 
334
            return option_value
 
335
        return self._get_global_config()._get_user_option(option_name)
 
336
 
 
337
    def _get_signature_checking(self):
 
338
        """See Config._get_signature_checking."""
 
339
        check = super(LocationConfig, self)._get_signature_checking()
 
340
        if check is not None:
 
341
            return check
 
342
        return self._get_global_config()._get_signature_checking()
 
343
 
 
344
    def _post_commit(self):
 
345
        """See Config.post_commit."""
 
346
        hook = self._get_user_option('post_commit')
 
347
        if hook is not None:
 
348
            return hook
 
349
        return self._get_global_config()._post_commit()
 
350
 
 
351
    def set_user_option(self, option, value):
571
352
        """Save option and its value in the configuration."""
572
 
        assert store in [STORE_LOCATION,
573
 
                         STORE_LOCATION_NORECURSE,
574
 
                         STORE_LOCATION_APPENDPATH], 'bad storage policy'
575
353
        # FIXME: RBC 20051029 This should refresh the parser and also take a
576
 
        # file lock on locations.conf.
577
 
        conf_dir = os.path.dirname(self._get_filename())
578
 
        ensure_config_dir_exists(conf_dir)
 
354
        # file lock on branches.conf.
 
355
        if not os.path.isdir(os.path.dirname(self._get_filename())):
 
356
            os.mkdir(os.path.dirname(self._get_filename()))
579
357
        location = self.location
580
358
        if location.endswith('/'):
581
359
            location = location[:-1]
585
363
        elif location + '/' in self._get_parser():
586
364
            location = location + '/'
587
365
        self._get_parser()[location][option]=value
588
 
        # the allowed values of store match the config policies
589
 
        self._set_option_policy(location, option, store)
590
 
        self._get_parser().write(file(self._get_filename(), 'wb'))
 
366
        self._get_parser().write()
591
367
 
592
368
 
593
369
class BranchConfig(Config):
594
370
    """A configuration object giving the policy for a branch."""
595
371
 
596
 
    def _get_branch_data_config(self):
597
 
        if self._branch_data_config is None:
598
 
            self._branch_data_config = TreeConfig(self.branch)
599
 
        return self._branch_data_config
600
 
 
601
372
    def _get_location_config(self):
602
373
        if self._location_config is None:
603
374
            self._location_config = LocationConfig(self.branch.base)
604
375
        return self._location_config
605
376
 
606
 
    def _get_global_config(self):
607
 
        if self._global_config is None:
608
 
            self._global_config = GlobalConfig()
609
 
        return self._global_config
610
 
 
611
 
    def _get_best_value(self, option_name):
612
 
        """This returns a user option from local, tree or global config.
613
 
 
614
 
        They are tried in that order.  Use get_safe_value if trusted values
615
 
        are necessary.
616
 
        """
617
 
        for source in self.option_sources:
618
 
            value = getattr(source(), option_name)()
619
 
            if value is not None:
620
 
                return value
621
 
        return None
622
 
 
623
 
    def _get_safe_value(self, option_name):
624
 
        """This variant of get_best_value never returns untrusted values.
625
 
        
626
 
        It does not return values from the branch data, because the branch may
627
 
        not be controlled by the user.
628
 
 
629
 
        We may wish to allow locations.conf to control whether branches are
630
 
        trusted in the future.
631
 
        """
632
 
        for source in (self._get_location_config, self._get_global_config):
633
 
            value = getattr(source(), option_name)()
634
 
            if value is not None:
635
 
                return value
636
 
        return None
637
 
 
638
377
    def _get_user_id(self):
639
378
        """Return the full user id for the branch.
640
379
    
642
381
        This is looked up in the email controlfile for the branch.
643
382
        """
644
383
        try:
645
 
            return (self.branch.control_files.get_utf8("email") 
 
384
            return (self.branch.controlfile("email", "r") 
646
385
                    .read()
647
386
                    .decode(bzrlib.user_encoding)
648
387
                    .rstrip("\r\n"))
649
388
        except errors.NoSuchFile, e:
650
389
            pass
651
390
        
652
 
        return self._get_best_value('_get_user_id')
 
391
        return self._get_location_config()._get_user_id()
653
392
 
654
393
    def _get_signature_checking(self):
655
394
        """See Config._get_signature_checking."""
656
 
        return self._get_best_value('_get_signature_checking')
657
 
 
658
 
    def _get_signing_policy(self):
659
 
        """See Config._get_signing_policy."""
660
 
        return self._get_best_value('_get_signing_policy')
 
395
        return self._get_location_config()._get_signature_checking()
661
396
 
662
397
    def _get_user_option(self, option_name):
663
398
        """See Config._get_user_option."""
664
 
        for source in self.option_sources:
665
 
            value = source()._get_user_option(option_name)
666
 
            if value is not None:
667
 
                return value
668
 
        return None
669
 
 
670
 
    def set_user_option(self, name, value, store=STORE_BRANCH,
671
 
        warn_masked=False):
672
 
        if store == STORE_BRANCH:
673
 
            self._get_branch_data_config().set_option(value, name)
674
 
        elif store == STORE_GLOBAL:
675
 
            self._get_global_config().set_user_option(name, value)
676
 
        else:
677
 
            self._get_location_config().set_user_option(name, value, store)
678
 
        if not warn_masked:
679
 
            return
680
 
        if store in (STORE_GLOBAL, STORE_BRANCH):
681
 
            mask_value = self._get_location_config().get_user_option(name)
682
 
            if mask_value is not None:
683
 
                trace.warning('Value "%s" is masked by "%s" from'
684
 
                              ' locations.conf', value, mask_value)
685
 
            else:
686
 
                if store == STORE_GLOBAL:
687
 
                    branch_config = self._get_branch_data_config()
688
 
                    mask_value = branch_config.get_user_option(name)
689
 
                    if mask_value is not None:
690
 
                        trace.warning('Value "%s" is masked by "%s" from'
691
 
                                      ' branch.conf', value, mask_value)
692
 
 
 
399
        return self._get_location_config()._get_user_option(option_name)
693
400
 
694
401
    def _gpg_signing_command(self):
695
402
        """See Config.gpg_signing_command."""
696
 
        return self._get_safe_value('_gpg_signing_command')
 
403
        return self._get_location_config()._gpg_signing_command()
697
404
        
698
405
    def __init__(self, branch):
699
406
        super(BranchConfig, self).__init__()
700
407
        self._location_config = None
701
 
        self._branch_data_config = None
702
 
        self._global_config = None
703
408
        self.branch = branch
704
 
        self.option_sources = (self._get_location_config, 
705
 
                               self._get_branch_data_config,
706
 
                               self._get_global_config)
707
409
 
708
410
    def _post_commit(self):
709
411
        """See Config.post_commit."""
710
 
        return self._get_safe_value('_post_commit')
711
 
 
712
 
    def _get_nickname(self):
713
 
        value = self._get_explicit_nickname()
714
 
        if value is not None:
715
 
            return value
716
 
        return urlutils.unescape(self.branch.base.split('/')[-2])
717
 
 
718
 
    def has_explicit_nickname(self):
719
 
        """Return true if a nickname has been explicitly assigned."""
720
 
        return self._get_explicit_nickname() is not None
721
 
 
722
 
    def _get_explicit_nickname(self):
723
 
        return self._get_best_value('_get_nickname')
724
 
 
725
 
    def _log_format(self):
726
 
        """See Config.log_format."""
727
 
        return self._get_best_value('_log_format')
728
 
 
729
 
 
730
 
def ensure_config_dir_exists(path=None):
731
 
    """Make sure a configuration directory exists.
732
 
    This makes sure that the directory exists.
733
 
    On windows, since configuration directories are 2 levels deep,
734
 
    it makes sure both the directory and the parent directory exists.
735
 
    """
736
 
    if path is None:
737
 
        path = config_dir()
738
 
    if not os.path.isdir(path):
739
 
        if sys.platform == 'win32':
740
 
            parent_dir = os.path.dirname(path)
741
 
            if not os.path.isdir(parent_dir):
742
 
                trace.mutter('creating config parent directory: %r', parent_dir)
743
 
            os.mkdir(parent_dir)
744
 
        trace.mutter('creating config directory: %r', path)
745
 
        os.mkdir(path)
 
412
        return self._get_location_config()._post_commit()
746
413
 
747
414
 
748
415
def config_dir():
752
419
    
753
420
    TODO: Global option --config-dir to override this.
754
421
    """
755
 
    base = os.environ.get('BZR_HOME', None)
756
 
    if sys.platform == 'win32':
757
 
        if base is None:
758
 
            base = win32utils.get_appdata_location_unicode()
759
 
        if base is None:
760
 
            base = os.environ.get('HOME', None)
761
 
        if base is None:
762
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
763
 
                                  ' or HOME set')
764
 
        return osutils.pathjoin(base, 'bazaar', '2.0')
765
 
    else:
766
 
        # cygwin, linux, and darwin all have a $HOME directory
767
 
        if base is None:
768
 
            base = os.path.expanduser("~")
769
 
        return osutils.pathjoin(base, ".bazaar")
 
422
    return os.path.join(os.path.expanduser("~"), ".bazaar")
770
423
 
771
424
 
772
425
def config_filename():
773
426
    """Return per-user configuration ini file filename."""
774
 
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
 
427
    return os.path.join(config_dir(), 'bazaar.conf')
775
428
 
776
429
 
777
430
def branches_config_filename():
778
431
    """Return per-user configuration ini file filename."""
779
 
    return osutils.pathjoin(config_dir(), 'branches.conf')
780
 
 
781
 
 
782
 
def locations_config_filename():
783
 
    """Return per-user configuration ini file filename."""
784
 
    return osutils.pathjoin(config_dir(), 'locations.conf')
785
 
 
786
 
 
787
 
def authentication_config_filename():
788
 
    """Return per-user authentication ini file filename."""
789
 
    return osutils.pathjoin(config_dir(), 'authentication.conf')
790
 
 
791
 
 
792
 
def user_ignore_config_filename():
793
 
    """Return the user default ignore filename"""
794
 
    return osutils.pathjoin(config_dir(), 'ignore')
 
432
    return os.path.join(config_dir(), 'branches.conf')
795
433
 
796
434
 
797
435
def _auto_user_id():
807
445
    """
808
446
    import socket
809
447
 
810
 
    if sys.platform == 'win32':
811
 
        name = win32utils.get_user_name_unicode()
812
 
        if name is None:
813
 
            raise errors.BzrError("Cannot autodetect user name.\n"
814
 
                                  "Please, set your name with command like:\n"
815
 
                                  'bzr whoami "Your Name <name@domain.com>"')
816
 
        host = win32utils.get_host_name_unicode()
817
 
        if host is None:
818
 
            host = socket.gethostname()
819
 
        return name, (name + '@' + host)
 
448
    # XXX: Any good way to get real user name on win32?
820
449
 
821
450
    try:
822
451
        import pwd
823
452
        uid = os.getuid()
824
453
        w = pwd.getpwuid(uid)
825
 
 
826
 
        # we try utf-8 first, because on many variants (like Linux),
827
 
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
828
 
        # false positives.  (many users will have their user encoding set to
829
 
        # latin-1, which cannot raise UnicodeError.)
830
 
        try:
831
 
            gecos = w.pw_gecos.decode('utf-8')
832
 
            encoding = 'utf-8'
833
 
        except UnicodeError:
834
 
            try:
835
 
                gecos = w.pw_gecos.decode(bzrlib.user_encoding)
836
 
                encoding = bzrlib.user_encoding
837
 
            except UnicodeError:
838
 
                raise errors.BzrCommandError('Unable to determine your name.  '
839
 
                   'Use "bzr whoami" to set it.')
840
 
        try:
841
 
            username = w.pw_name.decode(encoding)
842
 
        except UnicodeError:
843
 
            raise errors.BzrCommandError('Unable to determine your name.  '
844
 
                'Use "bzr whoami" to set it.')
845
 
 
 
454
        gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
455
        username = w.pw_name.decode(bzrlib.user_encoding)
846
456
        comma = gecos.find(',')
847
457
        if comma == -1:
848
458
            realname = gecos
853
463
 
854
464
    except ImportError:
855
465
        import getpass
856
 
        try:
857
 
            realname = username = getpass.getuser().decode(bzrlib.user_encoding)
858
 
        except UnicodeDecodeError:
859
 
            raise errors.BzrError("Can't decode username as %s." % \
860
 
                    bzrlib.user_encoding)
 
466
        realname = username = getpass.getuser().decode(bzrlib.user_encoding)
861
467
 
862
468
    return realname, (username + '@' + socket.gethostname())
863
469
 
864
470
 
865
 
def parse_username(username):
866
 
    """Parse e-mail username and return a (name, address) tuple."""
867
 
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
868
 
    if match is None:
869
 
        return (username, '')
870
 
    else:
871
 
        return (match.group(1), match.group(2))
872
 
 
873
 
 
874
471
def extract_email_address(e):
875
472
    """Return just the address part of an email string.
876
 
 
 
473
    
877
474
    That is just the user@domain part, nothing else. 
878
475
    This part is required to contain only ascii characters.
879
476
    If it can't be extracted, raises an error.
880
 
 
 
477
    
881
478
    >>> extract_email_address('Jane Tester <jane@test.com>')
882
479
    "jane@test.com"
883
480
    """
884
 
    name, email = parse_username(e)
885
 
    if not email:
886
 
        raise errors.NoEmailInUsername(e)
887
 
    return email
888
 
 
889
 
 
890
 
class TreeConfig(IniBasedConfig):
891
 
    """Branch configuration data associated with its contents, not location"""
892
 
 
893
 
    def __init__(self, branch):
894
 
        self.branch = branch
895
 
 
896
 
    def _get_parser(self, file=None):
897
 
        if file is not None:
898
 
            return IniBasedConfig._get_parser(file)
899
 
        return self._get_config()
900
 
 
901
 
    def _get_config(self):
902
 
        try:
903
 
            obj = ConfigObj(self.branch.control_files.get('branch.conf'),
904
 
                            encoding='utf-8')
905
 
        except errors.NoSuchFile:
906
 
            obj = ConfigObj(encoding='utf=8')
907
 
        return obj
908
 
 
909
 
    def get_option(self, name, section=None, default=None):
910
 
        self.branch.lock_read()
911
 
        try:
912
 
            obj = self._get_config()
913
 
            try:
914
 
                if section is not None:
915
 
                    obj = obj[section]
916
 
                result = obj[name]
917
 
            except KeyError:
918
 
                result = default
919
 
        finally:
920
 
            self.branch.unlock()
921
 
        return result
922
 
 
923
 
    def set_option(self, value, name, section=None):
924
 
        """Set a per-branch configuration option"""
925
 
        self.branch.lock_write()
926
 
        try:
927
 
            cfg_obj = self._get_config()
928
 
            if section is None:
929
 
                obj = cfg_obj
930
 
            else:
931
 
                try:
932
 
                    obj = cfg_obj[section]
933
 
                except KeyError:
934
 
                    cfg_obj[section] = {}
935
 
                    obj = cfg_obj[section]
936
 
            obj[name] = value
937
 
            out_file = StringIO()
938
 
            cfg_obj.write(out_file)
939
 
            out_file.seek(0)
940
 
            self.branch.control_files.put('branch.conf', out_file)
941
 
        finally:
942
 
            self.branch.unlock()
943
 
 
944
 
 
945
 
class AuthenticationConfig(object):
946
 
    """The authentication configuration file based on a ini file.
947
 
 
948
 
    Implements the authentication.conf file described in
949
 
    doc/developers/authentication-ring.txt.
950
 
    """
951
 
 
952
 
    def __init__(self, _file=None):
953
 
        self._config = None # The ConfigObj
954
 
        if _file is None:
955
 
            self._filename = authentication_config_filename()
956
 
            self._input = self._filename = authentication_config_filename()
957
 
        else:
958
 
            # Tests can provide a string as _file
959
 
            self._filename = None
960
 
            self._input = _file
961
 
 
962
 
    def _get_config(self):
963
 
        if self._config is not None:
964
 
            return self._config
965
 
        try:
966
 
            # FIXME: Should we validate something here ? Includes: empty
967
 
            # sections are useless, at least one of
968
 
            # user/password/password_encoding should be defined, etc.
969
 
 
970
 
            # Note: the encoding below declares that the file itself is utf-8
971
 
            # encoded, but the values in the ConfigObj are always Unicode.
972
 
            self._config = ConfigObj(self._input, encoding='utf-8')
973
 
        except configobj.ConfigObjError, e:
974
 
            raise errors.ParseConfigError(e.errors, e.config.filename)
975
 
        return self._config
976
 
 
977
 
    def _save(self):
978
 
        """Save the config file, only tests should use it for now."""
979
 
        conf_dir = os.path.dirname(self._filename)
980
 
        ensure_config_dir_exists(conf_dir)
981
 
        self._get_config().write(file(self._filename, 'wb'))
982
 
 
983
 
    def _set_option(self, section_name, option_name, value):
984
 
        """Set an authentication configuration option"""
985
 
        conf = self._get_config()
986
 
        section = conf.get(section_name)
987
 
        if section is None:
988
 
            conf[section] = {}
989
 
            section = conf[section]
990
 
        section[option_name] = value
991
 
        self._save()
992
 
 
993
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None):
994
 
        """Returns the matching credentials from authentication.conf file.
995
 
 
996
 
        :param scheme: protocol
997
 
 
998
 
        :param host: the server address
999
 
 
1000
 
        :param port: the associated port (optional)
1001
 
 
1002
 
        :param user: login (optional)
1003
 
 
1004
 
        :param path: the absolute path on the server (optional)
1005
 
 
1006
 
        :return: A dict containing the matching credentials or None.
1007
 
           This includes:
1008
 
           - name: the section name of the credentials in the
1009
 
             authentication.conf file,
1010
 
           - user: can't de different from the provided user if any,
1011
 
           - password: the decoded password, could be None if the credential
1012
 
             defines only the user
1013
 
           - verify_certificates: https specific, True if the server
1014
 
             certificate should be verified, False otherwise.
1015
 
        """
1016
 
        credentials = None
1017
 
        for auth_def_name, auth_def in self._get_config().items():
1018
 
            a_scheme, a_host, a_user, a_path = map(
1019
 
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1020
 
 
1021
 
            try:
1022
 
                a_port = auth_def.as_int('port')
1023
 
            except KeyError:
1024
 
                a_port = None
1025
 
            except ValueError:
1026
 
                raise ValueError("'port' not numeric in %s" % auth_def_name)
1027
 
            try:
1028
 
                a_verify_certificates = auth_def.as_bool('verify_certificates')
1029
 
            except KeyError:
1030
 
                a_verify_certificates = True
1031
 
            except ValueError:
1032
 
                raise ValueError(
1033
 
                    "'verify_certificates' not boolean in %s" % auth_def_name)
1034
 
 
1035
 
            # Attempt matching
1036
 
            if a_scheme is not None and scheme != a_scheme:
1037
 
                continue
1038
 
            if a_host is not None:
1039
 
                if not (host == a_host
1040
 
                        or (a_host.startswith('.') and host.endswith(a_host))):
1041
 
                    continue
1042
 
            if a_port is not None and port != a_port:
1043
 
                continue
1044
 
            if (a_path is not None and path is not None
1045
 
                and not path.startswith(a_path)):
1046
 
                continue
1047
 
            if (a_user is not None and user is not None
1048
 
                and a_user != user):
1049
 
                # Never contradict the caller about the user to be used
1050
 
                continue
1051
 
            if a_user is None:
1052
 
                # Can't find a user
1053
 
                continue
1054
 
            credentials = dict(name=auth_def_name,
1055
 
                               user=a_user, password=auth_def['password'],
1056
 
                               verify_certificates=a_verify_certificates)
1057
 
            self.decode_password(credentials,
1058
 
                                 auth_def.get('password_encoding', None))
1059
 
            if 'auth' in debug.debug_flags:
1060
 
                trace.mutter("Using authentication section: %r", auth_def_name)
1061
 
            break
1062
 
 
1063
 
        return credentials
1064
 
 
1065
 
    def get_user(self, scheme, host, port=None,
1066
 
                 realm=None, path=None, prompt=None):
1067
 
        """Get a user from authentication file.
1068
 
 
1069
 
        :param scheme: protocol
1070
 
 
1071
 
        :param host: the server address
1072
 
 
1073
 
        :param port: the associated port (optional)
1074
 
 
1075
 
        :param realm: the realm sent by the server (optional)
1076
 
 
1077
 
        :param path: the absolute path on the server (optional)
1078
 
 
1079
 
        :return: The found user.
1080
 
        """
1081
 
        credentials = self.get_credentials(scheme, host, port, user=None,
1082
 
                                           path=path)
1083
 
        if credentials is not None:
1084
 
            user = credentials['user']
1085
 
        else:
1086
 
            user = None
1087
 
        return user
1088
 
 
1089
 
    def get_password(self, scheme, host, user, port=None,
1090
 
                     realm=None, path=None, prompt=None):
1091
 
        """Get a password from authentication file or prompt the user for one.
1092
 
 
1093
 
        :param scheme: protocol
1094
 
 
1095
 
        :param host: the server address
1096
 
 
1097
 
        :param port: the associated port (optional)
1098
 
 
1099
 
        :param user: login
1100
 
 
1101
 
        :param realm: the realm sent by the server (optional)
1102
 
 
1103
 
        :param path: the absolute path on the server (optional)
1104
 
 
1105
 
        :return: The found password or the one entered by the user.
1106
 
        """
1107
 
        credentials = self.get_credentials(scheme, host, port, user, path)
1108
 
        if credentials is not None:
1109
 
            password = credentials['password']
1110
 
        else:
1111
 
            password = None
1112
 
        # Prompt user only if we could't find a password
1113
 
        if password is None:
1114
 
            if prompt is None:
1115
 
                # Create a default prompt suitable for most of the cases
1116
 
                prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1117
 
            # Special handling for optional fields in the prompt
1118
 
            if port is not None:
1119
 
                prompt_host = '%s:%d' % (host, port)
1120
 
            else:
1121
 
                prompt_host = host
1122
 
            password = ui.ui_factory.get_password(prompt,
1123
 
                                                  host=prompt_host, user=user)
1124
 
        return password
1125
 
 
1126
 
    def decode_password(self, credentials, encoding):
1127
 
        return credentials
 
481
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
482
    if not m:
 
483
        raise BzrError("%r doesn't seem to contain "
 
484
                       "a reasonable email address" % e)
 
485
    return m.group(0)