~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

Optimize Tree._iter_changes with specific file_ids

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
49
49
create_signatures - this option controls whether bzr will always create 
50
50
                    gpg signatures, never create them, or create them if the
51
51
                    branch is configured to require them.
52
 
log_format - This options set the default log format.  Options are long, 
53
 
             short, line, or a plugin can register new formats
 
52
log_format - this option sets the default log format.  Possible values are
 
53
             long, short, line, or a plugin can register new formats.
54
54
 
55
55
In bazaar.conf you can also define aliases in the ALIASES sections, example
56
56
 
61
61
up=pull
62
62
"""
63
63
 
 
64
import os
 
65
import sys
64
66
 
 
67
from bzrlib.lazy_import import lazy_import
 
68
lazy_import(globals(), """
65
69
import errno
66
70
from fnmatch import fnmatch
67
 
import os
68
71
import re
69
 
import sys
70
72
from StringIO import StringIO
71
73
 
72
74
import bzrlib
73
 
import bzrlib.errors as errors
74
 
from bzrlib.osutils import pathjoin
 
75
from bzrlib import (
 
76
    errors,
 
77
    osutils,
 
78
    symbol_versioning,
 
79
    urlutils,
 
80
    )
 
81
import bzrlib.util.configobj.configobj as configobj
 
82
""")
 
83
 
75
84
from bzrlib.trace import mutter, warning
76
 
import bzrlib.util.configobj.configobj as configobj
77
85
 
78
86
 
79
87
CHECK_IF_POSSIBLE=0
86
94
SIGN_NEVER=2
87
95
 
88
96
 
 
97
POLICY_NONE = 0
 
98
POLICY_NORECURSE = 1
 
99
POLICY_APPENDPATH = 2
 
100
 
 
101
_policy_name = {
 
102
    POLICY_NONE: None,
 
103
    POLICY_NORECURSE: 'norecurse',
 
104
    POLICY_APPENDPATH: 'appendpath',
 
105
    }
 
106
_policy_value = {
 
107
    None: POLICY_NONE,
 
108
    'none': POLICY_NONE,
 
109
    'norecurse': POLICY_NORECURSE,
 
110
    'appendpath': POLICY_APPENDPATH,
 
111
    }
 
112
 
 
113
 
 
114
STORE_LOCATION = POLICY_NONE
 
115
STORE_LOCATION_NORECURSE = POLICY_NORECURSE
 
116
STORE_LOCATION_APPENDPATH = POLICY_APPENDPATH
 
117
STORE_BRANCH = 3
 
118
STORE_GLOBAL = 4
 
119
 
 
120
 
89
121
class ConfigObj(configobj.ConfigObj):
90
122
 
91
123
    def get_bool(self, section, key):
167
199
    
168
200
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
169
201
        
170
 
        $BZREMAIL can be set to override this, then
 
202
        $BZR_EMAIL can be set to override this (as well as the
 
203
        deprecated $BZREMAIL), then
171
204
        the concrete policy type is checked, and finally
172
205
        $EMAIL is examined.
173
206
        If none is found, a reasonable default is (hopefully)
175
208
    
176
209
        TODO: Check it's reasonably well-formed.
177
210
        """
 
211
        v = os.environ.get('BZR_EMAIL')
 
212
        if v:
 
213
            return v.decode(bzrlib.user_encoding)
178
214
        v = os.environ.get('BZREMAIL')
179
215
        if v:
 
216
            warning('BZREMAIL is deprecated in favor of BZR_EMAIL. Please update your configuration.')
180
217
            return v.decode(bzrlib.user_encoding)
181
218
    
182
219
        v = self._get_user_id()
250
287
            raise errors.ParseConfigError(e.errors, e.config.filename)
251
288
        return self._parser
252
289
 
 
290
    def _get_matching_sections(self):
 
291
        """Return an ordered list of (section_name, extra_path) pairs.
 
292
 
 
293
        If the section contains inherited configuration, extra_path is
 
294
        a string containing the additional path components.
 
295
        """
 
296
        section = self._get_section()
 
297
        if section is not None:
 
298
            return [(section, '')]
 
299
        else:
 
300
            return []
 
301
 
253
302
    def _get_section(self):
254
303
        """Override this to define the section used by the config."""
255
304
        return "DEFAULT"
256
305
 
 
306
    def _get_option_policy(self, section, option_name):
 
307
        """Return the policy for the given (section, option_name) pair."""
 
308
        return POLICY_NONE
 
309
 
257
310
    def _get_signature_checking(self):
258
311
        """See Config._get_signature_checking."""
259
312
        policy = self._get_user_option('check_signatures')
272
325
 
273
326
    def _get_user_option(self, option_name):
274
327
        """See Config._get_user_option."""
275
 
        try:
276
 
            return self._get_parser().get_value(self._get_section(),
277
 
                                                option_name)
278
 
        except KeyError:
279
 
            pass
 
328
        for (section, extra_path) in self._get_matching_sections():
 
329
            try:
 
330
                value = self._get_parser().get_value(section, option_name)
 
331
            except KeyError:
 
332
                continue
 
333
            policy = self._get_option_policy(section, option_name)
 
334
            if policy == POLICY_NONE:
 
335
                return value
 
336
            elif policy == POLICY_NORECURSE:
 
337
                # norecurse items only apply to the exact path
 
338
                if extra_path:
 
339
                    continue
 
340
                else:
 
341
                    return value
 
342
            elif policy == POLICY_APPENDPATH:
 
343
                if extra_path:
 
344
                    value = urlutils.join(value, extra_path)
 
345
                return value
 
346
            else:
 
347
                raise AssertionError('Unexpected config policy %r' % policy)
 
348
        else:
 
349
            return None
280
350
 
281
351
    def _gpg_signing_command(self):
282
352
        """See Config.gpg_signing_command."""
367
437
                        ' to ~/.bazaar/locations.conf')
368
438
            name_generator = branches_config_filename
369
439
        super(LocationConfig, self).__init__(name_generator)
 
440
        # local file locations are looked up by local path, rather than
 
441
        # by file url. This is because the config file is a user
 
442
        # file, and we would rather not expose the user to file urls.
 
443
        if location.startswith('file://'):
 
444
            location = urlutils.local_path_from_url(location)
370
445
        self.location = location
371
446
 
372
 
    def _get_section(self):
373
 
        """Get the section we should look in for config items.
374
 
 
375
 
        Returns None if none exists. 
376
 
        TODO: perhaps return a NullSection that thunks through to the 
377
 
              global config.
378
 
        """
 
447
    def _get_matching_sections(self):
 
448
        """Return an ordered list of section names matching this location."""
379
449
        sections = self._get_parser()
380
450
        location_names = self.location.split('/')
381
451
        if self.location.endswith('/'):
382
452
            del location_names[-1]
383
453
        matches=[]
384
454
        for section in sections:
385
 
            section_names = section.split('/')
 
455
            # location is a local path if possible, so we need
 
456
            # to convert 'file://' urls to local paths if necessary.
 
457
            # This also avoids having file:///path be a more exact
 
458
            # match than '/path'.
 
459
            if section.startswith('file://'):
 
460
                section_path = urlutils.local_path_from_url(section)
 
461
            else:
 
462
                section_path = section
 
463
            section_names = section_path.split('/')
386
464
            if section.endswith('/'):
387
465
                del section_names[-1]
388
466
            names = zip(location_names, section_names)
397
475
            # if section is longer, no match.
398
476
            if len(section_names) > len(location_names):
399
477
                continue
400
 
            # if path is longer, and recurse is not true, no match
401
 
            if len(section_names) < len(location_names):
402
 
                try:
403
 
                    if not self._get_parser()[section].as_bool('recurse'):
404
 
                        continue
405
 
                except KeyError:
406
 
                    pass
407
 
            matches.append((len(section_names), section))
408
 
        if not len(matches):
409
 
            return None
 
478
            matches.append((len(section_names), section,
 
479
                            '/'.join(location_names[len(section_names):])))
410
480
        matches.sort(reverse=True)
411
 
        return matches[0][1]
412
 
 
413
 
    def set_user_option(self, option, value):
 
481
        sections = []
 
482
        for (length, section, extra_path) in matches:
 
483
            sections.append((section, extra_path))
 
484
            # should we stop looking for parent configs here?
 
485
            try:
 
486
                if self._get_parser()[section].as_bool('ignore_parents'):
 
487
                    break
 
488
            except KeyError:
 
489
                pass
 
490
        return sections
 
491
 
 
492
    def _get_option_policy(self, section, option_name):
 
493
        """Return the policy for the given (section, option_name) pair."""
 
494
        # check for the old 'recurse=False' flag
 
495
        try:
 
496
            recurse = self._get_parser()[section].as_bool('recurse')
 
497
        except KeyError:
 
498
            recurse = True
 
499
        if not recurse:
 
500
            return POLICY_NORECURSE
 
501
 
 
502
        policy_key = option_name + ':policy'
 
503
        try:
 
504
            policy_name = self._get_parser()[section][policy_key]
 
505
        except KeyError:
 
506
            policy_name = None
 
507
 
 
508
        return _policy_value[policy_name]
 
509
 
 
510
    def _set_option_policy(self, section, option_name, option_policy):
 
511
        """Set the policy for the given option name in the given section."""
 
512
        # The old recurse=False option affects all options in the
 
513
        # section.  To handle multiple policies in the section, we
 
514
        # need to convert it to a policy_norecurse key.
 
515
        try:
 
516
            recurse = self._get_parser()[section].as_bool('recurse')
 
517
        except KeyError:
 
518
            pass
 
519
        else:
 
520
            symbol_versioning.warn(
 
521
                'The recurse option is deprecated as of 0.14.  '
 
522
                'The section "%s" has been converted to use policies.'
 
523
                % section,
 
524
                DeprecationWarning)
 
525
            del self._get_parser()[section]['recurse']
 
526
            if not recurse:
 
527
                for key in self._get_parser()[section].keys():
 
528
                    if not key.endswith(':policy'):
 
529
                        self._get_parser()[section][key +
 
530
                                                    ':policy'] = 'norecurse'
 
531
 
 
532
        policy_key = option_name + ':policy'
 
533
        policy_name = _policy_name[option_policy]
 
534
        if policy_name is not None:
 
535
            self._get_parser()[section][policy_key] = policy_name
 
536
        else:
 
537
            if policy_key in self._get_parser()[section]:
 
538
                del self._get_parser()[section][policy_key]
 
539
 
 
540
    def set_user_option(self, option, value, store=STORE_LOCATION):
414
541
        """Save option and its value in the configuration."""
 
542
        assert store in [STORE_LOCATION,
 
543
                         STORE_LOCATION_NORECURSE,
 
544
                         STORE_LOCATION_APPENDPATH], 'bad storage policy'
415
545
        # FIXME: RBC 20051029 This should refresh the parser and also take a
416
546
        # file lock on locations.conf.
417
547
        conf_dir = os.path.dirname(self._get_filename())
425
555
        elif location + '/' in self._get_parser():
426
556
            location = location + '/'
427
557
        self._get_parser()[location][option]=value
 
558
        # the allowed values of store match the config policies
 
559
        self._set_option_policy(location, option, store)
428
560
        self._get_parser().write(file(self._get_filename(), 'wb'))
429
561
 
430
562
 
505
637
                return value
506
638
        return None
507
639
 
508
 
    def set_user_option(self, name, value, local=False):
509
 
        if local is True:
510
 
            self._get_location_config().set_user_option(name, value)
511
 
        else:
 
640
    def set_user_option(self, name, value, store=STORE_BRANCH):
 
641
        if store == STORE_BRANCH:
512
642
            self._get_branch_data_config().set_option(value, name)
513
 
 
 
643
        elif store == STORE_GLOBAL:
 
644
            self._get_global_config().set_user_option(name, value)
 
645
        else:
 
646
            self._get_location_config().set_user_option(name, value, store)
514
647
 
515
648
    def _gpg_signing_command(self):
516
649
        """See Config.gpg_signing_command."""
534
667
        value = self._get_explicit_nickname()
535
668
        if value is not None:
536
669
            return value
537
 
        return self.branch.base.split('/')[-2]
 
670
        return urlutils.unescape(self.branch.base.split('/')[-2])
538
671
 
539
672
    def has_explicit_nickname(self):
540
673
        """Return true if a nickname has been explicitly assigned."""
581
714
            base = os.environ.get('HOME', None)
582
715
        if base is None:
583
716
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
584
 
        return pathjoin(base, 'bazaar', '2.0')
 
717
        return osutils.pathjoin(base, 'bazaar', '2.0')
585
718
    else:
586
719
        # cygwin, linux, and darwin all have a $HOME directory
587
720
        if base is None:
588
721
            base = os.path.expanduser("~")
589
 
        return pathjoin(base, ".bazaar")
 
722
        return osutils.pathjoin(base, ".bazaar")
590
723
 
591
724
 
592
725
def config_filename():
593
726
    """Return per-user configuration ini file filename."""
594
 
    return pathjoin(config_dir(), 'bazaar.conf')
 
727
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
595
728
 
596
729
 
597
730
def branches_config_filename():
598
731
    """Return per-user configuration ini file filename."""
599
 
    return pathjoin(config_dir(), 'branches.conf')
 
732
    return osutils.pathjoin(config_dir(), 'branches.conf')
600
733
 
601
734
 
602
735
def locations_config_filename():
603
736
    """Return per-user configuration ini file filename."""
604
 
    return pathjoin(config_dir(), 'locations.conf')
 
737
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
738
 
 
739
 
 
740
def user_ignore_config_filename():
 
741
    """Return the user default ignore filename"""
 
742
    return osutils.pathjoin(config_dir(), 'ignore')
605
743
 
606
744
 
607
745
def _auto_user_id():
675
813
    """
676
814
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
677
815
    if not m:
678
 
        raise errors.BzrError("%r doesn't seem to contain "
679
 
                              "a reasonable email address" % e)
 
816
        raise errors.NoEmailInUsername(e)
680
817
    return m.group(0)
681
818
 
682
819