/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
 
"""Configuration that affects the behaviour of Breezy.
20
 
 
21
 
Currently this configuration resides in ~/.config/breezy/breezy.conf
22
 
and ~/.config/breezy/locations.conf, which is written to by brz.
23
 
 
24
 
If the first location doesn't exist, then brz falls back to reading
25
 
Bazaar configuration files in ~/.bazaar or ~/.config/bazaar.
26
 
 
27
 
In breezy.conf the following options may be set:
 
19
"""Configuration that affects the behaviour of Bazaar.
 
20
 
 
21
Currently this configuration resides in ~/.bazaar/bazaar.conf
 
22
and ~/.bazaar/locations.conf, which is written to by bzr.
 
23
 
 
24
In bazaar.conf the following options may be set:
28
25
[DEFAULT]
29
26
editor=name-of-program
30
27
email=Your Name <your@email.address>
31
28
check_signatures=require|ignore|check-available(default)
32
29
create_signatures=always|never|when-required(default)
 
30
gpg_signing_command=name-of-program
33
31
log_format=name-of-format
34
32
validate_signatures_in_log=true|false(default)
35
33
acceptable_keys=pattern1,pattern2
37
35
 
38
36
in locations.conf, you specify the url of a branch and options for it.
39
37
Wildcards may be used - * and ? as normal in shell completion. Options
40
 
set in both breezy.conf and locations.conf are overridden by the locations.conf
 
38
set in both bazaar.conf and locations.conf are overridden by the locations.conf
41
39
setting.
42
40
[/home/robertc/source]
43
41
recurse=False|True(default)
50
48
explanation of options
51
49
----------------------
52
50
editor - this option sets the pop up editor to use during commits.
53
 
email - this option sets the user id brz will use when committing.
54
 
check_signatures - this option will control whether brz will require good gpg
 
51
email - this option sets the user id bzr will use when committing.
 
52
check_signatures - this option will control whether bzr will require good gpg
55
53
                   signatures, ignore them, or check them if they are
56
 
                   present.  Currently it is unused except that
57
 
                   check_signatures turns on create_signatures.
58
 
create_signatures - this option controls whether brz will always create
 
54
                   present.  Currently it is unused except that check_signatures
 
55
                   turns on create_signatures.
 
56
create_signatures - this option controls whether bzr will always create
59
57
                    gpg signatures or not on commits.  There is an unused
60
58
                    option which in future is expected to work if
61
59
                    branch settings require signatures.
65
63
acceptable_keys - comma separated list of key patterns acceptable for
66
64
                  verify-signatures command
67
65
 
68
 
In breezy.conf you can also define aliases in the ALIASES sections, example
 
66
In bazaar.conf you can also define aliases in the ALIASES sections, example
69
67
 
70
68
[ALIASES]
71
69
lastlog=log --line -r-10..-1
74
72
up=pull
75
73
"""
76
74
 
 
75
from __future__ import absolute_import
 
76
from cStringIO import StringIO
77
77
import os
78
78
import sys
79
79
 
80
 
import configobj
81
 
from io import BytesIO
82
 
 
83
 
import breezy
84
 
from .lazy_import import lazy_import
 
80
import bzrlib
 
81
from bzrlib.decorators import needs_write_lock
 
82
from bzrlib.lazy_import import lazy_import
85
83
lazy_import(globals(), """
86
84
import base64
87
 
import errno
88
85
import fnmatch
89
86
import re
90
 
import stat
91
87
 
92
 
from breezy import (
93
 
    cmdline,
 
88
from bzrlib import (
 
89
    atomicfile,
94
90
    controldir,
95
91
    debug,
96
92
    directory_service,
97
 
    lock,
 
93
    errors,
 
94
    lazy_regex,
 
95
    library_state,
98
96
    lockdir,
99
97
    mergetools,
100
98
    osutils,
 
99
    symbol_versioning,
101
100
    trace,
102
101
    transport,
103
102
    ui,
104
103
    urlutils,
105
104
    win32utils,
106
105
    )
107
 
from breezy.i18n import gettext
 
106
from bzrlib.i18n import gettext
 
107
from bzrlib.util.configobj import configobj
108
108
""")
109
 
from . import (
 
109
from bzrlib import (
110
110
    commands,
111
 
    bedding,
112
 
    errors,
113
111
    hooks,
114
112
    lazy_regex,
115
113
    registry,
116
114
    )
117
 
 
118
 
 
119
 
CHECK_IF_POSSIBLE = 0
120
 
CHECK_ALWAYS = 1
121
 
CHECK_NEVER = 2
122
 
 
123
 
 
124
 
SIGN_WHEN_REQUIRED = 0
125
 
SIGN_ALWAYS = 1
126
 
SIGN_NEVER = 2
 
115
from bzrlib.symbol_versioning import (
 
116
    deprecated_in,
 
117
    deprecated_method,
 
118
    )
 
119
 
 
120
 
 
121
CHECK_IF_POSSIBLE=0
 
122
CHECK_ALWAYS=1
 
123
CHECK_NEVER=2
 
124
 
 
125
 
 
126
SIGN_WHEN_REQUIRED=0
 
127
SIGN_ALWAYS=1
 
128
SIGN_NEVER=2
127
129
 
128
130
 
129
131
POLICY_NONE = 0
150
152
STORE_GLOBAL = 4
151
153
 
152
154
 
153
 
class OptionExpansionLoop(errors.BzrError):
154
 
 
155
 
    _fmt = 'Loop involving %(refs)r while expanding "%(string)s".'
156
 
 
157
 
    def __init__(self, string, refs):
158
 
        self.string = string
159
 
        self.refs = '->'.join(refs)
160
 
 
161
 
 
162
 
class ExpandingUnknownOption(errors.BzrError):
163
 
 
164
 
    _fmt = 'Option "%(name)s" is not defined while expanding "%(string)s".'
165
 
 
166
 
    def __init__(self, name, string):
167
 
        self.name = name
168
 
        self.string = string
169
 
 
170
 
 
171
 
class IllegalOptionName(errors.BzrError):
172
 
 
173
 
    _fmt = 'Option "%(name)s" is not allowed.'
174
 
 
175
 
    def __init__(self, name):
176
 
        self.name = name
177
 
 
178
 
 
179
 
class ConfigContentError(errors.BzrError):
180
 
 
181
 
    _fmt = "Config file %(filename)s is not UTF-8 encoded\n"
182
 
 
183
 
    def __init__(self, filename):
184
 
        self.filename = filename
185
 
 
186
 
 
187
 
class ParseConfigError(errors.BzrError):
188
 
 
189
 
    _fmt = "Error(s) parsing config file %(filename)s:\n%(errors)s"
190
 
 
191
 
    def __init__(self, errors, filename):
192
 
        self.filename = filename
193
 
        self.errors = '\n'.join(e.msg for e in errors)
194
 
 
195
 
 
196
 
class ConfigOptionValueError(errors.BzrError):
197
 
 
198
 
    _fmt = ('Bad value "%(value)s" for option "%(name)s".\n'
199
 
            'See ``brz help %(name)s``')
200
 
 
201
 
    def __init__(self, name, value):
202
 
        errors.BzrError.__init__(self, name=name, value=value)
203
 
 
204
 
 
205
 
class NoEmailInUsername(errors.BzrError):
206
 
 
207
 
    _fmt = "%(username)r does not seem to contain a reasonable email address"
208
 
 
209
 
    def __init__(self, username):
210
 
        self.username = username
211
 
 
212
 
 
213
 
class NoSuchConfig(errors.BzrError):
214
 
 
215
 
    _fmt = ('The "%(config_id)s" configuration does not exist.')
216
 
 
217
 
    def __init__(self, config_id):
218
 
        errors.BzrError.__init__(self, config_id=config_id)
219
 
 
220
 
 
221
 
class NoSuchConfigOption(errors.BzrError):
222
 
 
223
 
    _fmt = ('The "%(option_name)s" configuration option does not exist.')
224
 
 
225
 
    def __init__(self, option_name):
226
 
        errors.BzrError.__init__(self, option_name=option_name)
227
 
 
228
 
 
229
155
def signature_policy_from_unicode(signature_string):
230
156
    """Convert a string to a signing policy."""
231
157
    if signature_string.lower() == 'check-available':
250
176
                     % signature_string)
251
177
 
252
178
 
253
 
def _has_triplequote_bug():
254
 
    """True if triple quote logic is reversed, see lp:710410."""
255
 
    conf = configobj.ConfigObj()
256
 
    quote = getattr(conf, "_get_triple_quote", None)
257
 
    if quote and quote('"""') != "'''":
258
 
        return True
259
 
    return False
260
 
 
261
 
 
262
179
class ConfigObj(configobj.ConfigObj):
263
180
 
264
181
    def __init__(self, infile=None, **kwargs):
267
184
                                        interpolation=False,
268
185
                                        **kwargs)
269
186
 
270
 
    if _has_triplequote_bug():
271
 
        def _get_triple_quote(self, value):
272
 
            quot = super(ConfigObj, self)._get_triple_quote(value)
273
 
            if quot == configobj.tdquot:
274
 
                return configobj.tsquot
275
 
            return configobj.tdquot
276
 
 
277
187
    def get_bool(self, section, key):
278
188
        return self[section].as_bool(key)
279
189
 
298
208
        raise NotImplementedError(self.config_id)
299
209
 
300
210
    def get_change_editor(self, old_tree, new_tree):
301
 
        from breezy import diff
 
211
        from bzrlib import diff
302
212
        cmd = self._get_change_editor()
303
213
        if cmd is None:
304
214
            return None
305
 
        cmd = cmd.replace('@old_path', '{old_path}')
306
 
        cmd = cmd.replace('@new_path', '{new_path}')
307
 
        cmd = cmdline.split(cmd)
308
 
        if '{old_path}' not in cmd:
309
 
            cmd.extend(['{old_path}', '{new_path}'])
310
215
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
311
216
                                             sys.stdout)
312
217
 
399
304
                else:
400
305
                    name = chunk[1:-1]
401
306
                    if name in _ref_stack:
402
 
                        raise OptionExpansionLoop(string, _ref_stack)
 
307
                        raise errors.OptionExpansionLoop(string, _ref_stack)
403
308
                    _ref_stack.append(name)
404
309
                    value = self._expand_option(name, env, _ref_stack)
405
310
                    if value is None:
406
 
                        raise ExpandingUnknownOption(name, string)
 
311
                        raise errors.ExpandingUnknownOption(name, string)
407
312
                    if isinstance(value, list):
408
313
                        list_value = True
409
314
                        chunks.extend(value)
429
334
            value = env[name]
430
335
        else:
431
336
            # FIXME: This is a limited implementation, what we really need is a
432
 
            # way to query the brz config for the value of an option,
 
337
            # way to query the bzr config for the value of an option,
433
338
            # respecting the scope rules (That is, once we implement fallback
434
339
            # configs, getting the option value should restart from the top
435
340
            # config, not the current one) -- vila 20101222
493
398
            otherwise.
494
399
        """
495
400
        l = self.get_user_option(option_name, expand=expand)
496
 
        if isinstance(l, str):
 
401
        if isinstance(l, (str, unicode)):
497
402
            # A single value, most probably the user forgot (or didn't care to
498
403
            # add) the final ','
499
404
            l = [l]
500
405
        return l
501
406
 
 
407
    @deprecated_method(deprecated_in((2, 5, 0)))
 
408
    def get_user_option_as_int_from_SI(self, option_name, default=None):
 
409
        """Get a generic option from a human readable size in SI units, e.g 10MB
 
410
 
 
411
        Accepted suffixes are K,M,G. It is case-insensitive and may be followed
 
412
        by a trailing b (i.e. Kb, MB). This is intended to be practical and not
 
413
        pedantic.
 
414
 
 
415
        :return Integer, expanded to its base-10 value if a proper SI unit is 
 
416
            found. If the option doesn't exist, or isn't a value in 
 
417
            SI units, return default (which defaults to None)
 
418
        """
 
419
        val = self.get_user_option(option_name)
 
420
        if isinstance(val, list):
 
421
            val = val[0]
 
422
        if val is None:
 
423
            val = default
 
424
        else:
 
425
            p = re.compile("^(\d+)([kmg])*b*$", re.IGNORECASE)
 
426
            try:
 
427
                m = p.match(val)
 
428
                if m is not None:
 
429
                    val = int(m.group(1))
 
430
                    if m.group(2) is not None:
 
431
                        if m.group(2).lower() == 'k':
 
432
                            val *= 10**3
 
433
                        elif m.group(2).lower() == 'm':
 
434
                            val *= 10**6
 
435
                        elif m.group(2).lower() == 'g':
 
436
                            val *= 10**9
 
437
                else:
 
438
                    ui.ui_factory.show_warning(gettext('Invalid config value for "{0}" '
 
439
                                               ' value {1!r} is not an SI unit.').format(
 
440
                                                option_name, val))
 
441
                    val = default
 
442
            except TypeError:
 
443
                val = default
 
444
        return val
 
445
 
 
446
    @deprecated_method(deprecated_in((2, 5, 0)))
 
447
    def gpg_signing_command(self):
 
448
        """What program should be used to sign signatures?"""
 
449
        result = self._gpg_signing_command()
 
450
        if result is None:
 
451
            result = "gpg"
 
452
        return result
 
453
 
 
454
    def _gpg_signing_command(self):
 
455
        """See gpg_signing_command()."""
 
456
        return None
 
457
 
 
458
    @deprecated_method(deprecated_in((2, 5, 0)))
 
459
    def log_format(self):
 
460
        """What log format should be used"""
 
461
        result = self._log_format()
 
462
        if result is None:
 
463
            result = "long"
 
464
        return result
 
465
 
502
466
    def _log_format(self):
503
467
        """See log_format()."""
504
468
        return None
516
480
        """See validate_signatures_in_log()."""
517
481
        return None
518
482
 
 
483
    @deprecated_method(deprecated_in((2, 5, 0)))
 
484
    def acceptable_keys(self):
 
485
        """Comma separated list of key patterns acceptable to 
 
486
        verify-signatures command"""
 
487
        result = self._acceptable_keys()
 
488
        return result
 
489
 
 
490
    def _acceptable_keys(self):
 
491
        """See acceptable_keys()."""
 
492
        return None
 
493
 
 
494
    @deprecated_method(deprecated_in((2, 5, 0)))
 
495
    def post_commit(self):
 
496
        """An ordered list of python functions to call.
 
497
 
 
498
        Each function takes branch, rev_id as parameters.
 
499
        """
 
500
        return self._post_commit()
 
501
 
519
502
    def _post_commit(self):
520
503
        """See Config.post_commit."""
521
504
        return None
529
512
 
530
513
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
531
514
 
532
 
        $BRZ_EMAIL or $BZR_EMAIL can be set to override this, then
 
515
        $BZR_EMAIL can be set to override this, then
533
516
        the concrete policy type is checked, and finally
534
517
        $EMAIL is examined.
535
 
        If no username can be found, NoWhoami exception is raised.
 
518
        If no username can be found, errors.NoWhoami exception is raised.
536
519
        """
537
 
        v = os.environ.get('BRZ_EMAIL') or os.environ.get('BZR_EMAIL')
 
520
        v = os.environ.get('BZR_EMAIL')
538
521
        if v:
539
 
            return v
 
522
            return v.decode(osutils.get_user_encoding())
540
523
        v = self._get_user_id()
541
524
        if v:
542
525
            return v
543
 
        return bedding.default_email()
 
526
        return default_email()
 
527
 
 
528
    def ensure_username(self):
 
529
        """Raise errors.NoWhoami if username is not set.
 
530
 
 
531
        This method relies on the username() function raising the error.
 
532
        """
 
533
        self.username()
 
534
 
 
535
    @deprecated_method(deprecated_in((2, 5, 0)))
 
536
    def signature_checking(self):
 
537
        """What is the current policy for signature checking?."""
 
538
        policy = self._get_signature_checking()
 
539
        if policy is not None:
 
540
            return policy
 
541
        return CHECK_IF_POSSIBLE
 
542
 
 
543
    @deprecated_method(deprecated_in((2, 5, 0)))
 
544
    def signing_policy(self):
 
545
        """What is the current policy for signature checking?."""
 
546
        policy = self._get_signing_policy()
 
547
        if policy is not None:
 
548
            return policy
 
549
        return SIGN_WHEN_REQUIRED
 
550
 
 
551
    @deprecated_method(deprecated_in((2, 5, 0)))
 
552
    def signature_needed(self):
 
553
        """Is a signature needed when committing ?."""
 
554
        policy = self._get_signing_policy()
 
555
        if policy is None:
 
556
            policy = self._get_signature_checking()
 
557
            if policy is not None:
 
558
                #this warning should go away once check_signatures is
 
559
                #implemented (if not before)
 
560
                trace.warning("Please use create_signatures,"
 
561
                              " not check_signatures to set signing policy.")
 
562
        elif policy == SIGN_ALWAYS:
 
563
            return True
 
564
        return False
 
565
 
 
566
    @deprecated_method(deprecated_in((2, 5, 0)))
 
567
    def gpg_signing_key(self):
 
568
        """GPG user-id to sign commits"""
 
569
        key = self.get_user_option('gpg_signing_key')
 
570
        if key == "default" or key == None:
 
571
            return self.user_email()
 
572
        else:
 
573
            return key
544
574
 
545
575
    def get_alias(self, value):
546
576
        return self._get_alias(value)
591
621
        # This should be done through the proposed config defaults mechanism
592
622
        # when it becomes available in the future.
593
623
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
594
 
                                             expand=False) or
595
 
                        mergetools.known_merge_tools.get(name, None))
 
624
                                             expand=False)
 
625
                        or mergetools.known_merge_tools.get(name, None))
596
626
        return command_line
597
627
 
598
628
 
606
636
        These are all empty initially, because by default nothing should get
607
637
        notified.
608
638
        """
609
 
        super(_ConfigHooks, self).__init__('breezy.config', 'ConfigHooks')
 
639
        super(_ConfigHooks, self).__init__('bzrlib.config', 'ConfigHooks')
610
640
        self.add_hook('load',
611
641
                      'Invoked when a config store is loaded.'
612
642
                      ' The signature is (store).',
628
658
                      'Invoked when a config option is removed.'
629
659
                      ' The signature is (stack, name).',
630
660
                      (2, 4))
631
 
 
632
 
 
633
661
ConfigHooks = _ConfigHooks()
634
662
 
635
663
 
643
671
        These are all empty initially, because by default nothing should get
644
672
        notified.
645
673
        """
646
 
        super(_OldConfigHooks, self).__init__(
647
 
            'breezy.config', 'OldConfigHooks')
 
674
        super(_OldConfigHooks, self).__init__('bzrlib.config', 'OldConfigHooks')
648
675
        self.add_hook('load',
649
676
                      'Invoked when a config store is loaded.'
650
677
                      ' The signature is (config).',
666
693
                      'Invoked when a config option is removed.'
667
694
                      ' The signature is (config, name).',
668
695
                      (2, 4))
669
 
 
670
 
 
671
696
OldConfigHooks = _OldConfigHooks()
672
697
 
673
698
 
674
699
class IniBasedConfig(Config):
675
700
    """A configuration policy that draws from ini files."""
676
701
 
677
 
    def __init__(self, file_name=None):
 
702
    def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
 
703
                 file_name=None):
678
704
        """Base class for configuration files using an ini-like syntax.
679
705
 
680
706
        :param file_name: The configuration file path.
681
707
        """
682
708
        super(IniBasedConfig, self).__init__()
683
709
        self.file_name = file_name
684
 
        self.file_name = file_name
 
710
        if symbol_versioning.deprecated_passed(get_filename):
 
711
            symbol_versioning.warn(
 
712
                'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
 
713
                ' Use file_name instead.',
 
714
                DeprecationWarning,
 
715
                stacklevel=2)
 
716
            if get_filename is not None:
 
717
                self.file_name = get_filename()
 
718
        else:
 
719
            self.file_name = file_name
685
720
        self._content = None
686
721
        self._parser = None
687
722
 
689
724
    def from_string(cls, str_or_unicode, file_name=None, save=False):
690
725
        """Create a config object from a string.
691
726
 
692
 
        :param str_or_unicode: A string representing the file content. This
693
 
            will be utf-8 encoded.
 
727
        :param str_or_unicode: A string representing the file content. This will
 
728
            be utf-8 encoded.
694
729
 
695
730
        :param file_name: The configuration file path.
696
731
 
701
736
        return conf
702
737
 
703
738
    def _create_from_string(self, str_or_unicode, save):
704
 
        if isinstance(str_or_unicode, str):
705
 
            str_or_unicode = str_or_unicode.encode('utf-8')
706
 
        self._content = BytesIO(str_or_unicode)
 
739
        self._content = StringIO(str_or_unicode.encode('utf-8'))
707
740
        # Some tests use in-memory configs, some other always need the config
708
741
        # file to exist on disk.
709
742
        if save:
710
743
            self._write_config_file()
711
744
 
712
 
    def _get_parser(self):
 
745
    def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
713
746
        if self._parser is not None:
714
747
            return self._parser
 
748
        if symbol_versioning.deprecated_passed(file):
 
749
            symbol_versioning.warn(
 
750
                'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
 
751
                ' Use IniBasedConfig(_content=xxx) instead.',
 
752
                DeprecationWarning,
 
753
                stacklevel=2)
715
754
        if self._content is not None:
716
755
            co_input = self._content
717
756
        elif self.file_name is None:
720
759
            co_input = self.file_name
721
760
        try:
722
761
            self._parser = ConfigObj(co_input, encoding='utf-8')
723
 
        except configobj.ConfigObjError as e:
724
 
            raise ParseConfigError(e.errors, e.config.filename)
 
762
        except configobj.ConfigObjError, e:
 
763
            raise errors.ParseConfigError(e.errors, e.config.filename)
725
764
        except UnicodeDecodeError:
726
 
            raise ConfigContentError(self.file_name)
 
765
            raise errors.ConfigContentError(self.file_name)
727
766
        # Make sure self.reload() will use the right file name
728
767
        self._parser.filename = self.file_name
729
768
        for hook in OldConfigHooks['load']:
785
824
            which sections should be searched. This is a list of (name,
786
825
            configobj) tuples.
787
826
        """
 
827
        opts = []
788
828
        if sections is None:
789
829
            parser = self._get_parser()
790
830
            sections = []
808
848
        return POLICY_NONE
809
849
 
810
850
    def _get_change_editor(self):
811
 
        return self.get_user_option('change_editor', expand=False)
 
851
        return self.get_user_option('change_editor')
812
852
 
813
853
    def _get_signature_checking(self):
814
854
        """See Config._get_signature_checking."""
851
891
        else:
852
892
            return None
853
893
 
 
894
    def _gpg_signing_command(self):
 
895
        """See Config.gpg_signing_command."""
 
896
        return self._get_user_option('gpg_signing_command')
 
897
 
854
898
    def _log_format(self):
855
899
        """See Config.log_format."""
856
900
        return self._get_user_option('log_format')
894
938
        try:
895
939
            del section[option_name]
896
940
        except KeyError:
897
 
            raise NoSuchConfigOption(option_name)
 
941
            raise errors.NoSuchConfigOption(option_name)
898
942
        self._write_config_file()
899
943
        for hook in OldConfigHooks['remove']:
900
944
            hook(self, option_name)
902
946
    def _write_config_file(self):
903
947
        if self.file_name is None:
904
948
            raise AssertionError('We cannot save, self.file_name is None')
905
 
        from . import atomicfile
906
949
        conf_dir = os.path.dirname(self.file_name)
907
 
        bedding.ensure_config_dir_exists(conf_dir)
908
 
        with atomicfile.AtomicFile(self.file_name) as atomic_file:
909
 
            self._get_parser().write(atomic_file)
 
950
        ensure_config_dir_exists(conf_dir)
 
951
        atomic_file = atomicfile.AtomicFile(self.file_name)
 
952
        self._get_parser().write(atomic_file)
 
953
        atomic_file.commit()
 
954
        atomic_file.close()
910
955
        osutils.copy_ownership_from_path(self.file_name)
911
956
        for hook in OldConfigHooks['save']:
912
957
            hook(self)
918
963
    If several processes try to write the config file, the accesses need to be
919
964
    serialized.
920
965
 
921
 
    Daughter classes should use the self.lock_write() decorator method when
922
 
    they upate a config (they call, directly or indirectly, the
 
966
    Daughter classes should decorate all methods that update a config with the
 
967
    ``@needs_write_lock`` decorator (they call, directly or indirectly, the
923
968
    ``_write_config_file()`` method. These methods (typically ``set_option()``
924
969
    and variants must reload the config file from disk before calling
925
970
    ``_write_config_file()``), this can be achieved by calling the
964
1009
 
965
1010
        If the directory doesn't exist it is created.
966
1011
        """
967
 
        bedding.ensure_config_dir_exists(self.dir)
968
 
        token = self._lock.lock_write(token)
969
 
        return lock.LogicalLockResult(self.unlock, token)
 
1012
        ensure_config_dir_exists(self.dir)
 
1013
        return self._lock.lock_write(token)
970
1014
 
971
1015
    def unlock(self):
972
1016
        self._lock.unlock()
974
1018
    def break_lock(self):
975
1019
        self._lock.break_lock()
976
1020
 
 
1021
    @needs_write_lock
977
1022
    def remove_user_option(self, option_name, section_name=None):
978
 
        with self.lock_write():
979
 
            super(LockableConfig, self).remove_user_option(
980
 
                option_name, section_name)
 
1023
        super(LockableConfig, self).remove_user_option(option_name,
 
1024
                                                       section_name)
981
1025
 
982
1026
    def _write_config_file(self):
983
1027
        if self._lock is None or not self._lock.is_held:
984
1028
            # NB: if the following exception is raised it probably means a
985
 
            # missing call to lock_write() by one of the callers.
 
1029
            # missing @needs_write_lock decorator on one of the callers.
986
1030
            raise errors.ObjectNotLocked(self)
987
1031
        super(LockableConfig, self)._write_config_file()
988
1032
 
991
1035
    """The configuration that should be used for a specific location."""
992
1036
 
993
1037
    def __init__(self):
994
 
        super(GlobalConfig, self).__init__(file_name=bedding.config_path())
 
1038
        super(GlobalConfig, self).__init__(file_name=config_filename())
995
1039
 
996
1040
    def config_id(self):
997
 
        return 'breezy'
 
1041
        return 'bazaar'
998
1042
 
999
1043
    @classmethod
1000
1044
    def from_string(cls, str_or_unicode, save=False):
1009
1053
        conf._create_from_string(str_or_unicode, save)
1010
1054
        return conf
1011
1055
 
 
1056
    @needs_write_lock
1012
1057
    def set_user_option(self, option, value):
1013
1058
        """Save option and its value in the configuration."""
1014
 
        with self.lock_write():
1015
 
            self._set_option(option, value, 'DEFAULT')
 
1059
        self._set_option(option, value, 'DEFAULT')
1016
1060
 
1017
1061
    def get_aliases(self):
1018
1062
        """Return the aliases section."""
1021
1065
        else:
1022
1066
            return {}
1023
1067
 
 
1068
    @needs_write_lock
1024
1069
    def set_alias(self, alias_name, alias_command):
1025
1070
        """Save the alias in the configuration."""
1026
 
        with self.lock_write():
1027
 
            self._set_option(alias_name, alias_command, 'ALIASES')
 
1071
        self._set_option(alias_name, alias_command, 'ALIASES')
1028
1072
 
 
1073
    @needs_write_lock
1029
1074
    def unset_alias(self, alias_name):
1030
1075
        """Unset an existing alias."""
1031
 
        with self.lock_write():
1032
 
            self.reload()
1033
 
            aliases = self._get_parser().get('ALIASES')
1034
 
            if not aliases or alias_name not in aliases:
1035
 
                raise errors.NoSuchAlias(alias_name)
1036
 
            del aliases[alias_name]
1037
 
            self._write_config_file()
 
1076
        self.reload()
 
1077
        aliases = self._get_parser().get('ALIASES')
 
1078
        if not aliases or alias_name not in aliases:
 
1079
            raise errors.NoSuchAlias(alias_name)
 
1080
        del aliases[alias_name]
 
1081
        self._write_config_file()
1038
1082
 
1039
1083
    def _set_option(self, option, value, section):
1040
1084
        self.reload()
1053
1097
            # doesn't exist yet. So we force DEFAULT when yielding
1054
1098
            name = 'DEFAULT'
1055
1099
            if 'DEFAULT' not in parser:
1056
 
                parser['DEFAULT'] = {}
 
1100
               parser['DEFAULT']= {}
1057
1101
        yield (name, parser[name], self.config_id())
1058
1102
 
 
1103
    @needs_write_lock
1059
1104
    def remove_user_option(self, option_name, section_name=None):
1060
1105
        if section_name is None:
1061
1106
            # We need to force the default section.
1062
1107
            section_name = 'DEFAULT'
1063
 
        with self.lock_write():
1064
 
            # We need to avoid the LockableConfig implementation or we'll lock
1065
 
            # twice
1066
 
            super(LockableConfig, self).remove_user_option(
1067
 
                option_name, section_name)
1068
 
 
 
1108
        # We need to avoid the LockableConfig implementation or we'll lock
 
1109
        # twice
 
1110
        super(LockableConfig, self).remove_user_option(option_name,
 
1111
                                                       section_name)
1069
1112
 
1070
1113
def _iter_for_location_by_parts(sections, location):
1071
1114
    """Keep only the sessions matching the specified location.
1107
1150
        else:
1108
1151
            # Rely on zip truncating in length to the length of the shortest
1109
1152
            # argument sequence.
1110
 
            for name in zip(location_parts, section_parts):
 
1153
            names = zip(location_parts, section_parts)
 
1154
            for name in names:
1111
1155
                if not fnmatch.fnmatch(name[0], name[1]):
1112
1156
                    matched = False
1113
1157
                    break
1123
1167
 
1124
1168
    def __init__(self, location):
1125
1169
        super(LocationConfig, self).__init__(
1126
 
            file_name=bedding.locations_config_path())
 
1170
            file_name=locations_config_filename())
1127
1171
        # local file locations are looked up by local path, rather than
1128
1172
        # by file url. This is because the config file is a user
1129
1173
        # file, and we would rather not expose the user to file urls.
1151
1195
 
1152
1196
    def _get_matching_sections(self):
1153
1197
        """Return an ordered list of section names matching this location."""
 
1198
        matches = list(_iter_for_location_by_parts(self._get_parser(),
 
1199
                                                   self.location))
1154
1200
        # put the longest (aka more specific) locations first
1155
 
        matches = sorted(
1156
 
            _iter_for_location_by_parts(self._get_parser(), self.location),
1157
 
            key=lambda match: (match[2], match[0]),
 
1201
        matches.sort(
 
1202
            key=lambda (section, extra_path, length): (length, section),
1158
1203
            reverse=True)
1159
1204
        for (section, extra_path, length) in matches:
1160
1205
            yield section, extra_path
1193
1238
 
1194
1239
    def _set_option_policy(self, section, option_name, option_policy):
1195
1240
        """Set the policy for the given option name in the given section."""
 
1241
        # The old recurse=False option affects all options in the
 
1242
        # section.  To handle multiple policies in the section, we
 
1243
        # need to convert it to a policy_norecurse key.
 
1244
        try:
 
1245
            recurse = self._get_parser()[section].as_bool('recurse')
 
1246
        except KeyError:
 
1247
            pass
 
1248
        else:
 
1249
            symbol_versioning.warn(
 
1250
                'The recurse option is deprecated as of 0.14.  '
 
1251
                'The section "%s" has been converted to use policies.'
 
1252
                % section,
 
1253
                DeprecationWarning)
 
1254
            del self._get_parser()[section]['recurse']
 
1255
            if not recurse:
 
1256
                for key in self._get_parser()[section].keys():
 
1257
                    if not key.endswith(':policy'):
 
1258
                        self._get_parser()[section][key +
 
1259
                                                    ':policy'] = 'norecurse'
 
1260
 
1196
1261
        policy_key = option_name + ':policy'
1197
1262
        policy_name = _policy_name[option_policy]
1198
1263
        if policy_name is not None:
1201
1266
            if policy_key in self._get_parser()[section]:
1202
1267
                del self._get_parser()[section][policy_key]
1203
1268
 
 
1269
    @needs_write_lock
1204
1270
    def set_user_option(self, option, value, store=STORE_LOCATION):
1205
1271
        """Save option and its value in the configuration."""
1206
1272
        if store not in [STORE_LOCATION,
1207
1273
                         STORE_LOCATION_NORECURSE,
1208
1274
                         STORE_LOCATION_APPENDPATH]:
1209
1275
            raise ValueError('bad storage policy %r for %r' %
1210
 
                             (store, option))
1211
 
        with self.lock_write():
1212
 
            self.reload()
1213
 
            location = self.location
1214
 
            if location.endswith('/'):
1215
 
                location = location[:-1]
1216
 
            parser = self._get_parser()
1217
 
            if location not in parser and not location + '/' in parser:
1218
 
                parser[location] = {}
1219
 
            elif location + '/' in parser:
1220
 
                location = location + '/'
1221
 
            parser[location][option] = value
1222
 
            # the allowed values of store match the config policies
1223
 
            self._set_option_policy(location, option, store)
1224
 
            self._write_config_file()
1225
 
            for hook in OldConfigHooks['set']:
1226
 
                hook(self, option, value)
 
1276
                (store, option))
 
1277
        self.reload()
 
1278
        location = self.location
 
1279
        if location.endswith('/'):
 
1280
            location = location[:-1]
 
1281
        parser = self._get_parser()
 
1282
        if not location in parser and not location + '/' in parser:
 
1283
            parser[location] = {}
 
1284
        elif location + '/' in parser:
 
1285
            location = location + '/'
 
1286
        parser[location][option]=value
 
1287
        # the allowed values of store match the config policies
 
1288
        self._set_option_policy(location, option, store)
 
1289
        self._write_config_file()
 
1290
        for hook in OldConfigHooks['set']:
 
1291
            hook(self, option, value)
1227
1292
 
1228
1293
 
1229
1294
class BranchConfig(Config):
1319
1384
                yield section
1320
1385
 
1321
1386
    def _get_options(self, sections=None):
 
1387
        opts = []
1322
1388
        # First the locations options
1323
1389
        for option in self._get_location_config()._get_options():
1324
1390
            yield option
1338
1404
            yield option
1339
1405
 
1340
1406
    def set_user_option(self, name, value, store=STORE_BRANCH,
1341
 
                        warn_masked=False):
 
1407
        warn_masked=False):
1342
1408
        if store == STORE_BRANCH:
1343
1409
            self._get_branch_data_config().set_option(value, name)
1344
1410
        elif store == STORE_GLOBAL:
1363
1429
    def remove_user_option(self, option_name, section_name=None):
1364
1430
        self._get_branch_data_config().remove_option(option_name, section_name)
1365
1431
 
 
1432
    def _gpg_signing_command(self):
 
1433
        """See Config.gpg_signing_command."""
 
1434
        return self._get_safe_value('_gpg_signing_command')
 
1435
 
1366
1436
    def _post_commit(self):
1367
1437
        """See Config.post_commit."""
1368
1438
        return self._get_safe_value('_post_commit')
1395
1465
        return self._get_best_value('_acceptable_keys')
1396
1466
 
1397
1467
 
 
1468
def ensure_config_dir_exists(path=None):
 
1469
    """Make sure a configuration directory exists.
 
1470
    This makes sure that the directory exists.
 
1471
    On windows, since configuration directories are 2 levels deep,
 
1472
    it makes sure both the directory and the parent directory exists.
 
1473
    """
 
1474
    if path is None:
 
1475
        path = config_dir()
 
1476
    if not os.path.isdir(path):
 
1477
        if sys.platform == 'win32':
 
1478
            parent_dir = os.path.dirname(path)
 
1479
            if not os.path.isdir(parent_dir):
 
1480
                trace.mutter('creating config parent directory: %r', parent_dir)
 
1481
                os.mkdir(parent_dir)
 
1482
        trace.mutter('creating config directory: %r', path)
 
1483
        os.mkdir(path)
 
1484
        osutils.copy_ownership_from_path(path)
 
1485
 
 
1486
 
 
1487
def config_dir():
 
1488
    """Return per-user configuration directory as unicode string
 
1489
 
 
1490
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
 
1491
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
 
1492
    that will be used instead.
 
1493
 
 
1494
    TODO: Global option --config-dir to override this.
 
1495
    """
 
1496
    base = osutils.path_from_environ('BZR_HOME')
 
1497
    if sys.platform == 'win32':
 
1498
        if base is None:
 
1499
            base = win32utils.get_appdata_location()
 
1500
        if base is None:
 
1501
            base = win32utils.get_home_location()
 
1502
        # GZ 2012-02-01: Really the two level subdirs only make sense inside
 
1503
        #                APPDATA, but hard to move. See bug 348640 for more.
 
1504
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
1505
    if base is None:
 
1506
        xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
 
1507
        if xdg_dir is None:
 
1508
            xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
1509
        xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
1510
        if osutils.isdir(xdg_dir):
 
1511
            trace.mutter(
 
1512
                "Using configuration in XDG directory %s." % xdg_dir)
 
1513
            return xdg_dir
 
1514
        base = osutils._get_home_dir()
 
1515
    return osutils.pathjoin(base, ".bazaar")
 
1516
 
 
1517
 
 
1518
def config_filename():
 
1519
    """Return per-user configuration ini file filename."""
 
1520
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
 
1521
 
 
1522
 
 
1523
def locations_config_filename():
 
1524
    """Return per-user configuration ini file filename."""
 
1525
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
1526
 
 
1527
 
 
1528
def authentication_config_filename():
 
1529
    """Return per-user authentication ini file filename."""
 
1530
    return osutils.pathjoin(config_dir(), 'authentication.conf')
 
1531
 
 
1532
 
 
1533
def user_ignore_config_filename():
 
1534
    """Return the user default ignore filename"""
 
1535
    return osutils.pathjoin(config_dir(), 'ignore')
 
1536
 
 
1537
 
 
1538
def crash_dir():
 
1539
    """Return the directory name to store crash files.
 
1540
 
 
1541
    This doesn't implicitly create it.
 
1542
 
 
1543
    On Windows it's in the config directory; elsewhere it's /var/crash
 
1544
    which may be monitored by apport.  It can be overridden by
 
1545
    $APPORT_CRASH_DIR.
 
1546
    """
 
1547
    if sys.platform == 'win32':
 
1548
        return osutils.pathjoin(config_dir(), 'Crash')
 
1549
    else:
 
1550
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
1551
        # 2010-01-31
 
1552
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
1553
 
 
1554
 
 
1555
def xdg_cache_dir():
 
1556
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
 
1557
    # Possibly this should be different on Windows?
 
1558
    e = os.environ.get('XDG_CACHE_HOME', None)
 
1559
    if e:
 
1560
        return e
 
1561
    else:
 
1562
        return os.path.expanduser('~/.cache')
 
1563
 
 
1564
 
 
1565
def _get_default_mail_domain(mailname_file='/etc/mailname'):
 
1566
    """If possible, return the assumed default email domain.
 
1567
 
 
1568
    :returns: string mail domain, or None.
 
1569
    """
 
1570
    if sys.platform == 'win32':
 
1571
        # No implementation yet; patches welcome
 
1572
        return None
 
1573
    try:
 
1574
        f = open(mailname_file)
 
1575
    except (IOError, OSError), e:
 
1576
        return None
 
1577
    try:
 
1578
        domain = f.readline().strip()
 
1579
        return domain
 
1580
    finally:
 
1581
        f.close()
 
1582
 
 
1583
 
 
1584
def default_email():
 
1585
    v = os.environ.get('BZR_EMAIL')
 
1586
    if v:
 
1587
        return v.decode(osutils.get_user_encoding())
 
1588
    v = os.environ.get('EMAIL')
 
1589
    if v:
 
1590
        return v.decode(osutils.get_user_encoding())
 
1591
    name, email = _auto_user_id()
 
1592
    if name and email:
 
1593
        return u'%s <%s>' % (name, email)
 
1594
    elif email:
 
1595
        return email
 
1596
    raise errors.NoWhoami()
 
1597
 
 
1598
 
 
1599
def _auto_user_id():
 
1600
    """Calculate automatic user identification.
 
1601
 
 
1602
    :returns: (realname, email), either of which may be None if they can't be
 
1603
    determined.
 
1604
 
 
1605
    Only used when none is set in the environment or the id file.
 
1606
 
 
1607
    This only returns an email address if we can be fairly sure the 
 
1608
    address is reasonable, ie if /etc/mailname is set on unix.
 
1609
 
 
1610
    This doesn't use the FQDN as the default domain because that may be 
 
1611
    slow, and it doesn't use the hostname alone because that's not normally 
 
1612
    a reasonable address.
 
1613
    """
 
1614
    if sys.platform == 'win32':
 
1615
        # No implementation to reliably determine Windows default mail
 
1616
        # address; please add one.
 
1617
        return None, None
 
1618
 
 
1619
    default_mail_domain = _get_default_mail_domain()
 
1620
    if not default_mail_domain:
 
1621
        return None, None
 
1622
 
 
1623
    import pwd
 
1624
    uid = os.getuid()
 
1625
    try:
 
1626
        w = pwd.getpwuid(uid)
 
1627
    except KeyError:
 
1628
        trace.mutter('no passwd entry for uid %d?' % uid)
 
1629
        return None, None
 
1630
 
 
1631
    # we try utf-8 first, because on many variants (like Linux),
 
1632
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
1633
    # false positives.  (many users will have their user encoding set to
 
1634
    # latin-1, which cannot raise UnicodeError.)
 
1635
    try:
 
1636
        gecos = w.pw_gecos.decode('utf-8')
 
1637
        encoding = 'utf-8'
 
1638
    except UnicodeError:
 
1639
        try:
 
1640
            encoding = osutils.get_user_encoding()
 
1641
            gecos = w.pw_gecos.decode(encoding)
 
1642
        except UnicodeError, e:
 
1643
            trace.mutter("cannot decode passwd entry %s" % w)
 
1644
            return None, None
 
1645
    try:
 
1646
        username = w.pw_name.decode(encoding)
 
1647
    except UnicodeError, e:
 
1648
        trace.mutter("cannot decode passwd entry %s" % w)
 
1649
        return None, None
 
1650
 
 
1651
    comma = gecos.find(',')
 
1652
    if comma == -1:
 
1653
        realname = gecos
 
1654
    else:
 
1655
        realname = gecos[:comma]
 
1656
 
 
1657
    return realname, (username + '@' + default_mail_domain)
 
1658
 
 
1659
 
1398
1660
def parse_username(username):
1399
1661
    """Parse e-mail username and return a (name, address) tuple."""
1400
1662
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1401
1663
    if match is None:
1402
1664
        return (username, '')
1403
 
    return (match.group(1), match.group(2))
 
1665
    else:
 
1666
        return (match.group(1), match.group(2))
1404
1667
 
1405
1668
 
1406
1669
def extract_email_address(e):
1415
1678
    """
1416
1679
    name, email = parse_username(e)
1417
1680
    if not email:
1418
 
        raise NoEmailInUsername(e)
 
1681
        raise errors.NoEmailInUsername(e)
1419
1682
    return email
1420
1683
 
1421
1684
 
1422
1685
class TreeConfig(IniBasedConfig):
1423
1686
    """Branch configuration data associated with its contents, not location"""
1424
1687
 
1425
 
    # XXX: Really needs a better name, as this is not part of the tree!
1426
 
    # -- mbp 20080507
 
1688
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
1427
1689
 
1428
1690
    def __init__(self, branch):
1429
1691
        self._config = branch._get_config()
1435
1697
        return self._config._get_configobj()
1436
1698
 
1437
1699
    def get_option(self, name, section=None, default=None):
1438
 
        with self.branch.lock_read():
 
1700
        self.branch.lock_read()
 
1701
        try:
1439
1702
            return self._config.get_option(name, section, default)
 
1703
        finally:
 
1704
            self.branch.unlock()
1440
1705
 
1441
1706
    def set_option(self, value, name, section=None):
1442
1707
        """Set a per-branch configuration option"""
1443
1708
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1444
1709
        # higher levels providing the right lock -- vila 20101004
1445
 
        with self.branch.lock_write():
 
1710
        self.branch.lock_write()
 
1711
        try:
1446
1712
            self._config.set_option(value, name, section)
 
1713
        finally:
 
1714
            self.branch.unlock()
1447
1715
 
1448
1716
    def remove_option(self, option_name, section_name=None):
1449
1717
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
1450
1718
        # higher levels providing the right lock -- vila 20101004
1451
 
        with self.branch.lock_write():
 
1719
        self.branch.lock_write()
 
1720
        try:
1452
1721
            self._config.remove_option(option_name, section_name)
1453
 
 
1454
 
 
1455
 
_authentication_config_permission_errors = set()
 
1722
        finally:
 
1723
            self.branch.unlock()
1456
1724
 
1457
1725
 
1458
1726
class AuthenticationConfig(object):
1463
1731
    """
1464
1732
 
1465
1733
    def __init__(self, _file=None):
1466
 
        self._config = None  # The ConfigObj
 
1734
        self._config = None # The ConfigObj
1467
1735
        if _file is None:
1468
 
            self._input = self._filename = bedding.authentication_config_path()
1469
 
            self._check_permissions()
 
1736
            self._filename = authentication_config_filename()
 
1737
            self._input = self._filename = authentication_config_filename()
1470
1738
        else:
1471
1739
            # Tests can provide a string as _file
1472
1740
            self._filename = None
1483
1751
            # Note: the encoding below declares that the file itself is utf-8
1484
1752
            # encoded, but the values in the ConfigObj are always Unicode.
1485
1753
            self._config = ConfigObj(self._input, encoding='utf-8')
1486
 
        except configobj.ConfigObjError as e:
1487
 
            raise ParseConfigError(e.errors, e.config.filename)
 
1754
        except configobj.ConfigObjError, e:
 
1755
            raise errors.ParseConfigError(e.errors, e.config.filename)
1488
1756
        except UnicodeError:
1489
 
            raise ConfigContentError(self._filename)
 
1757
            raise errors.ConfigContentError(self._filename)
1490
1758
        return self._config
1491
1759
 
1492
 
    def _check_permissions(self):
1493
 
        """Check permission of auth file are user read/write able only."""
1494
 
        try:
1495
 
            st = os.stat(self._filename)
1496
 
        except OSError as e:
1497
 
            if e.errno != errno.ENOENT:
1498
 
                trace.mutter('Unable to stat %r: %r', self._filename, e)
1499
 
            return
1500
 
        mode = stat.S_IMODE(st.st_mode)
1501
 
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP
1502
 
             | stat.S_IWGRP | stat.S_IRGRP) & mode):
1503
 
            # Only warn once
1504
 
            if (self._filename not in _authentication_config_permission_errors and
1505
 
                not GlobalConfig().suppress_warning(
1506
 
                    'insecure_permissions')):
1507
 
                trace.warning("The file '%s' has insecure "
1508
 
                              "file permissions. Saved passwords may be accessible "
1509
 
                              "by other users.", self._filename)
1510
 
                _authentication_config_permission_errors.add(self._filename)
1511
 
 
1512
1760
    def _save(self):
1513
1761
        """Save the config file, only tests should use it for now."""
1514
1762
        conf_dir = os.path.dirname(self._filename)
1515
 
        bedding.ensure_config_dir_exists(conf_dir)
1516
 
        fd = os.open(self._filename, os.O_RDWR | os.O_CREAT, 0o600)
 
1763
        ensure_config_dir_exists(conf_dir)
 
1764
        f = file(self._filename, 'wb')
1517
1765
        try:
1518
 
            f = os.fdopen(fd, 'wb')
1519
1766
            self._get_config().write(f)
1520
1767
        finally:
1521
1768
            f.close()
1562
1809
             certificate should be verified, False otherwise.
1563
1810
        """
1564
1811
        credentials = None
1565
 
        for auth_def_name, auth_def in self._get_config().iteritems():
1566
 
            if not isinstance(auth_def, configobj.Section):
1567
 
                raise ValueError("%s defined outside a section" %
1568
 
                                 auth_def_name)
 
1812
        for auth_def_name, auth_def in self._get_config().items():
 
1813
            if type(auth_def) is not configobj.Section:
 
1814
                raise ValueError("%s defined outside a section" % auth_def_name)
1569
1815
 
1570
1816
            a_scheme, a_host, a_user, a_path = map(
1571
1817
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1588
1834
            if a_scheme is not None and scheme != a_scheme:
1589
1835
                continue
1590
1836
            if a_host is not None:
1591
 
                if not (host == a_host or
1592
 
                        (a_host.startswith('.') and host.endswith(a_host))):
 
1837
                if not (host == a_host
 
1838
                        or (a_host.startswith('.') and host.endswith(a_host))):
1593
1839
                    continue
1594
1840
            if a_port is not None and port != a_port:
1595
1841
                continue
1596
 
            if (a_path is not None and path is not None and
1597
 
                    not path.startswith(a_path)):
 
1842
            if (a_path is not None and path is not None
 
1843
                and not path.startswith(a_path)):
1598
1844
                continue
1599
 
            if (a_user is not None and user is not None and
1600
 
                    a_user != user):
 
1845
            if (a_user is not None and user is not None
 
1846
                and a_user != user):
1601
1847
                # Never contradict the caller about the user to be used
1602
1848
                continue
1603
1849
            if a_user is None:
1664
1910
        if realm is not None:
1665
1911
            values['realm'] = realm
1666
1912
        config = self._get_config()
1667
 
        for section, existing_values in config.iteritems():
 
1913
        for_deletion = []
 
1914
        for section, existing_values in config.items():
1668
1915
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1669
1916
                if existing_values.get(key) != values.get(key):
1670
1917
                    break
1687
1934
 
1688
1935
        :param path: the absolute path on the server (optional)
1689
1936
 
1690
 
        :param ask: Ask the user if there is no explicitly configured username
 
1937
        :param ask: Ask the user if there is no explicitly configured username 
1691
1938
                    (optional)
1692
1939
 
1693
1940
        :param default: The username returned if none is defined (optional).
1737
1984
                                           realm)
1738
1985
        if credentials is not None:
1739
1986
            password = credentials['password']
1740
 
            if password is not None and scheme == 'ssh':
 
1987
            if password is not None and scheme is 'ssh':
1741
1988
                trace.warning('password ignored in section [%s],'
1742
1989
                              ' use an ssh agent instead'
1743
1990
                              % credentials['name'])
1748
1995
        if password is None:
1749
1996
            if prompt is None:
1750
1997
                # Create a default prompt suitable for most cases
1751
 
                prompt = (u'%s' %
1752
 
                          scheme.upper() + u' %(user)s@%(host)s password')
 
1998
                prompt = u'%s' % scheme.upper() + u' %(user)s@%(host)s password'
1753
1999
            # Special handling for optional fields in the prompt
1754
2000
            if port is not None:
1755
2001
                prompt_host = '%s:%d' % (host, port)
1774
2020
    A credential store provides access to credentials via the password_encoding
1775
2021
    field in authentication.conf sections.
1776
2022
 
1777
 
    Except for stores provided by brz itself, most stores are expected to be
 
2023
    Except for stores provided by bzr itself, most stores are expected to be
1778
2024
    provided by plugins that will therefore use
1779
2025
    register_lazy(password_encoding, module_name, member_name, help=help,
1780
2026
    fallback=fallback) to install themselves.
1824
2070
        :param override_existing: Raise KeyErorr if False and something has
1825
2071
                already been registered for that key. If True, ignore if there
1826
2072
                is an existing key (always register the new value).
1827
 
        :param fallback: Whether this credential store should be
 
2073
        :param fallback: Whether this credential store should be 
1828
2074
                used as fallback.
1829
2075
        """
1830
2076
        return super(CredentialStoreRegistry,
1844
2090
        :param override_existing: If True, replace the existing object
1845
2091
                with the new one. If False, if there is already something
1846
2092
                registered with the same key, raise a KeyError
1847
 
        :param fallback: Whether this credential store should be
 
2093
        :param fallback: Whether this credential store should be 
1848
2094
                used as fallback.
1849
2095
        """
1850
2096
        return super(CredentialStoreRegistry, self).register_lazy(
1871
2117
        raise NotImplementedError(self.get_credentials)
1872
2118
 
1873
2119
 
 
2120
 
1874
2121
class PlainTextCredentialStore(CredentialStore):
1875
2122
    __doc__ = """Plain text credential store for the authentication.conf file"""
1876
2123
 
1891
2138
        """See CredentialStore.decode_password."""
1892
2139
        # GZ 2012-07-28: Will raise binascii.Error if password is not base64,
1893
2140
        #                should probably propogate as something more useful.
1894
 
        return base64.standard_b64decode(credentials['password'])
1895
 
 
 
2141
        return base64.decodestring(credentials['password'])
1896
2142
 
1897
2143
credential_store_registry.register('base64', Base64CredentialStore,
1898
2144
                                   help=Base64CredentialStore.__doc__)
1997
2243
 
1998
2244
    def _get_config_file(self):
1999
2245
        try:
2000
 
            f = BytesIO(self._transport.get_bytes(self._filename))
 
2246
            f = StringIO(self._transport.get_bytes(self._filename))
2001
2247
            for hook in OldConfigHooks['load']:
2002
2248
                hook(self)
2003
2249
            return f
2004
2250
        except errors.NoSuchFile:
2005
 
            return BytesIO()
2006
 
        except errors.PermissionDenied:
2007
 
            trace.warning(
2008
 
                "Permission denied while trying to open "
2009
 
                "configuration file %s.",
2010
 
                urlutils.unescape_for_display(
2011
 
                    urlutils.join(self._transport.base, self._filename),
2012
 
                    "utf-8"))
2013
 
            return BytesIO()
 
2251
            return StringIO()
 
2252
        except errors.PermissionDenied, e:
 
2253
            trace.warning("Permission denied while trying to open "
 
2254
                "configuration file %s.", urlutils.unescape_for_display(
 
2255
                urlutils.join(self._transport.base, self._filename), "utf-8"))
 
2256
            return StringIO()
2014
2257
 
2015
2258
    def _external_url(self):
2016
2259
        return urlutils.join(self._transport.external_url(), self._filename)
2020
2263
        try:
2021
2264
            try:
2022
2265
                conf = ConfigObj(f, encoding='utf-8')
2023
 
            except configobj.ConfigObjError as e:
2024
 
                raise ParseConfigError(e.errors, self._external_url())
 
2266
            except configobj.ConfigObjError, e:
 
2267
                raise errors.ParseConfigError(e.errors, self._external_url())
2025
2268
            except UnicodeDecodeError:
2026
 
                raise ConfigContentError(self._external_url())
 
2269
                raise errors.ConfigContentError(self._external_url())
2027
2270
        finally:
2028
2271
            f.close()
2029
2272
        return conf
2030
2273
 
2031
2274
    def _set_configobj(self, configobj):
2032
 
        out_file = BytesIO()
 
2275
        out_file = StringIO()
2033
2276
        configobj.write(out_file)
2034
2277
        out_file.seek(0)
2035
2278
        self._transport.put_file(self._filename, out_file)
2101
2344
                raise AssertionError(
2102
2345
                    'Only empty lists are supported as default values')
2103
2346
            self.default = u','
2104
 
        elif isinstance(default, (bytes, str, bool, int, float)):
 
2347
        elif isinstance(default, (str, unicode, bool, int, float)):
2105
2348
            # Rely on python to convert strings, booleans and integers
2106
2349
            self.default = u'%s' % (default,)
2107
2350
        elif callable(default):
2139
2382
                trace.warning('Value "%s" is not valid for "%s"',
2140
2383
                              unicode_value, self.name)
2141
2384
            elif self.invalid == 'error':
2142
 
                raise ConfigOptionValueError(self.name, unicode_value)
 
2385
                raise errors.ConfigOptionValueError(self.name, unicode_value)
2143
2386
        return converted
2144
2387
 
2145
2388
    def get_override(self):
2147
2390
        for var in self.override_from_env:
2148
2391
            try:
2149
2392
                # If the env variable is defined, its value takes precedence
2150
 
                value = os.environ[var]
 
2393
                value = os.environ[var].decode(osutils.get_user_encoding())
2151
2394
                break
2152
2395
            except KeyError:
2153
2396
                continue
2158
2401
        for var in self.default_from_env:
2159
2402
            try:
2160
2403
                # If the env variable is defined, its value is the default one
2161
 
                value = os.environ[var]
 
2404
                value = os.environ[var].decode(osutils.get_user_encoding())
2162
2405
                break
2163
2406
            except KeyError:
2164
2407
                continue
2166
2409
            # Otherwise, fallback to the value defined at registration
2167
2410
            if callable(self.default):
2168
2411
                value = self.default()
2169
 
                if not isinstance(value, str):
 
2412
                if not isinstance(value, unicode):
2170
2413
                    raise AssertionError(
2171
2414
                        "Callable default value for '%s' should be unicode"
2172
2415
                        % (self.name))
2179
2422
 
2180
2423
    def get_help_text(self, additional_see_also=None, plain=True):
2181
2424
        result = self.help
2182
 
        from breezy import help_topics
 
2425
        from bzrlib import help_topics
2183
2426
        result += help_topics._format_see_also(additional_see_also)
2184
2427
        if plain:
2185
2428
            result = help_topics.help_as_plain_text(result)
2198
2441
 
2199
2442
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2200
2443
 
2201
 
 
2202
2444
def int_SI_from_store(unicode_str):
2203
2445
    """Convert a human readable size in SI units, e.g 10MB into an integer.
2204
2446
 
2206
2448
    by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2207
2449
    pedantic.
2208
2450
 
2209
 
    :return Integer, expanded to its base-10 value if a proper SI unit is
 
2451
    :return Integer, expanded to its base-10 value if a proper SI unit is 
2210
2452
        found, None otherwise.
2211
2453
    """
2212
 
    regexp = "^(\\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
 
2454
    regexp = "^(\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2213
2455
    p = re.compile(regexp, re.IGNORECASE)
2214
2456
    m = p.match(unicode_str)
2215
2457
    val = None
2220
2462
            try:
2221
2463
                coeff = _unit_suffixes[unit.upper()]
2222
2464
            except KeyError:
2223
 
                raise ValueError(
2224
 
                    gettext('{0} is not an SI unit.').format(unit))
 
2465
                raise ValueError(gettext('{0} is not an SI unit.').format(unit))
2225
2466
            val *= coeff
2226
2467
    return val
2227
2468
 
2251
2492
            invalid=invalid, unquote=False)
2252
2493
 
2253
2494
    def from_unicode(self, unicode_str):
2254
 
        if not isinstance(unicode_str, str):
 
2495
        if not isinstance(unicode_str, basestring):
2255
2496
            raise TypeError
2256
2497
        # Now inject our string directly as unicode. All callers got their
2257
2498
        # value from configobj, so values that need to be quoted are already
2259
2500
        _list_converter_config.reset()
2260
2501
        _list_converter_config._parse([u"list=%s" % (unicode_str,)])
2261
2502
        maybe_list = _list_converter_config['list']
2262
 
        if isinstance(maybe_list, str):
 
2503
        if isinstance(maybe_list, basestring):
2263
2504
            if maybe_list:
2264
2505
                # A single value, most probably the user forgot (or didn't care
2265
2506
                # to add) the final ','
2284
2525
        can take quoting into account.
2285
2526
        """
2286
2527
        super(RegistryOption, self).__init__(
2287
 
            name, default=lambda: registry.default_key,
 
2528
            name, default=lambda: unicode(registry.default_key),
2288
2529
            default_from_env=default_from_env,
2289
2530
            from_unicode=self.from_unicode, help=help,
2290
2531
            invalid=invalid, unquote=False)
2291
2532
        self.registry = registry
2292
2533
 
2293
2534
    def from_unicode(self, unicode_str):
2294
 
        if not isinstance(unicode_str, str):
 
2535
        if not isinstance(unicode_str, basestring):
2295
2536
            raise TypeError
2296
2537
        try:
2297
2538
            return self.registry.get(unicode_str)
2299
2540
            raise ValueError(
2300
2541
                "Invalid value %s for %s."
2301
2542
                "See help for a list of possible values." % (unicode_str,
2302
 
                                                             self.name))
 
2543
                    self.name))
2303
2544
 
2304
2545
    @property
2305
2546
    def help(self):
2309
2550
        return "".join(ret)
2310
2551
 
2311
2552
 
2312
 
_option_ref_re = lazy_regex.lazy_compile('({[^\\d\\W](?:\\.\\w|-\\w|\\w)*})')
 
2553
_option_ref_re = lazy_regex.lazy_compile('({[^\d\W](?:\.\w|-\w|\w)*})')
2313
2554
"""Describes an expandable option reference.
2314
2555
 
2315
2556
We want to match the most embedded reference first.
2318
2559
for '{bar{baz}}' we will get '{baz}'
2319
2560
"""
2320
2561
 
2321
 
 
2322
2562
def iter_option_refs(string):
2323
2563
    # Split isolate refs so every other chunk is a ref
2324
2564
    is_ref = False
2325
 
    for chunk in _option_ref_re.split(string):
 
2565
    for chunk  in _option_ref_re.split(string):
2326
2566
        yield is_ref, chunk
2327
2567
        is_ref = not is_ref
2328
2568
 
2340
2580
        :param option_name: The name to validate.
2341
2581
        """
2342
2582
        if _option_ref_re.match('{%s}' % option_name) is None:
2343
 
            raise IllegalOptionName(option_name)
 
2583
            raise errors.IllegalOptionName(option_name)
2344
2584
 
2345
2585
    def register(self, option):
2346
2586
        """Register a new option to its name.
2359
2599
 
2360
2600
        :param module_name: the python path to the module. Such as 'os.path'.
2361
2601
 
2362
 
        :param member_name: the member of the module to return.  If empty or
 
2602
        :param member_name: the member of the module to return.  If empty or 
2363
2603
                None, get() will return the module itself.
2364
2604
        """
2365
2605
        self._check_option_name(key)
2391
2631
'''))
2392
2632
option_registry.register(
2393
2633
    ListOption('acceptable_keys',
2394
 
               default=None,
2395
 
               help="""\
 
2634
           default=None,
 
2635
           help="""\
2396
2636
List of GPG key patterns which are acceptable for verification.
2397
2637
"""))
2398
2638
option_registry.register(
2428
2668
See also: bound.
2429
2669
"""))
2430
2670
option_registry.register(
2431
 
    Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
 
2671
    Option('branch.fetch_tags', default=False,  from_unicode=bool_from_store,
2432
2672
           help="""\
2433
2673
Whether revisions associated with tags should be fetched.
2434
2674
"""))
2435
2675
option_registry.register_lazy(
2436
 
    'transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
 
2676
    'bzr.transform.orphan_policy', 'bzrlib.transform', 'opt_transform_orphan')
2437
2677
option_registry.register(
2438
2678
    Option('bzr.workingtree.worth_saving_limit', default=10,
2439
 
           from_unicode=int_from_store, invalid='warning',
 
2679
           from_unicode=int_from_store,  invalid='warning',
2440
2680
           help='''\
2441
2681
How many changes before saving the dirstate.
2442
2682
 
2456
2696
bug tracker was specified.
2457
2697
'''))
2458
2698
option_registry.register(
2459
 
    Option('calculate_revnos', default=True,
2460
 
           from_unicode=bool_from_store,
2461
 
           help='''\
2462
 
Calculate revision numbers if they are not known.
2463
 
 
2464
 
Always show revision numbers, even for branch formats that don't store them
2465
 
natively (such as Git). Calculating the revision number requires traversing
2466
 
the left hand ancestry of the branch and can be slow on very large branches.
2467
 
'''))
2468
 
option_registry.register(
2469
2699
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2470
2700
           from_unicode=signature_policy_from_unicode,
2471
2701
           help='''\
2506
2736
'''))
2507
2737
option_registry.register(
2508
2738
    ListOption('debug_flags', default=[],
2509
 
               help='Debug flags to activate.'))
 
2739
           help='Debug flags to activate.'))
2510
2740
option_registry.register(
2511
2741
    Option('default_format', default='2a',
2512
2742
           help='Format used when creating branches.'))
2513
2743
option_registry.register(
 
2744
    Option('dpush_strict', default=None,
 
2745
           from_unicode=bool_from_store,
 
2746
           help='''\
 
2747
The default value for ``dpush --strict``.
 
2748
 
 
2749
If present, defines the ``--strict`` option default value for checking
 
2750
uncommitted changes before pushing into a different VCS without any
 
2751
custom bzr metadata.
 
2752
'''))
 
2753
option_registry.register(
2514
2754
    Option('editor',
2515
2755
           help='The command called to launch an editor to enter a message.'))
2516
2756
option_registry.register(
2517
 
    Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
2518
 
           default=bedding.default_email, help='The users identity'))
 
2757
    Option('email', override_from_env=['BZR_EMAIL'], default=default_email,
 
2758
           help='The users identity'))
 
2759
option_registry.register(
 
2760
    Option('gpg_signing_command',
 
2761
           default='gpg',
 
2762
           help="""\
 
2763
Program to use use for creating signatures.
 
2764
 
 
2765
This should support at least the -u and --clearsign options.
 
2766
"""))
2519
2767
option_registry.register(
2520
2768
    Option('gpg_signing_key',
2521
2769
           default=None,
2525
2773
This defaults to the first key associated with the users email.
2526
2774
"""))
2527
2775
option_registry.register(
 
2776
    Option('ignore_missing_extensions', default=False,
 
2777
           from_unicode=bool_from_store,
 
2778
           help='''\
 
2779
Control the missing extensions warning display.
 
2780
 
 
2781
The warning will not be emitted if set to True.
 
2782
'''))
 
2783
option_registry.register(
2528
2784
    Option('language',
2529
2785
           help='Language to translate messages into.'))
2530
2786
option_registry.register(
2531
 
    Option('locks.steal_dead', default=True, from_unicode=bool_from_store,
 
2787
    Option('locks.steal_dead', default=False, from_unicode=bool_from_store,
2532
2788
           help='''\
2533
2789
Steal locks that appears to be dead.
2534
2790
 
2541
2797
'''))
2542
2798
option_registry.register(
2543
2799
    Option('log_format', default='long',
2544
 
           help='''\
 
2800
           help= '''\
2545
2801
Log format to use when displaying revisions.
2546
2802
 
2547
2803
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2548
2804
may be provided by plugins.
2549
2805
'''))
2550
 
option_registry.register_lazy('mail_client', 'breezy.mail_client',
2551
 
                              'opt_mail_client')
 
2806
option_registry.register_lazy('mail_client', 'bzrlib.mail_client',
 
2807
    'opt_mail_client')
2552
2808
option_registry.register(
2553
2809
    Option('output_encoding',
2554
 
           help='Unicode encoding for output'
 
2810
           help= 'Unicode encoding for output'
2555
2811
           ' (terminal encoding if not specified).'))
2556
2812
option_registry.register(
2557
2813
    Option('parent_location',
2571
2827
 
2572
2828
Each function takes branch, rev_id as parameters.
2573
2829
'''))
2574
 
option_registry.register_lazy('progress_bar', 'breezy.ui.text',
 
2830
option_registry.register_lazy('progress_bar', 'bzrlib.ui.text',
2575
2831
                              'opt_progress_bar')
2576
2832
option_registry.register(
2577
2833
    Option('public_branch',
2610
2866
lost if the machine crashes.  See also dirstate.fdatasync.
2611
2867
'''))
2612
2868
option_registry.register_lazy('smtp_server',
2613
 
                              'breezy.smtp_connection', 'smtp_server')
 
2869
    'bzrlib.smtp_connection', 'smtp_server')
2614
2870
option_registry.register_lazy('smtp_password',
2615
 
                              'breezy.smtp_connection', 'smtp_password')
 
2871
    'bzrlib.smtp_connection', 'smtp_password')
2616
2872
option_registry.register_lazy('smtp_username',
2617
 
                              'breezy.smtp_connection', 'smtp_username')
 
2873
    'bzrlib.smtp_connection', 'smtp_username')
2618
2874
option_registry.register(
2619
2875
    Option('selftest.timeout',
2620
 
           default='600',
2621
 
           from_unicode=int_from_store,
2622
 
           help='Abort selftest if one test takes longer than this many seconds',
2623
 
           ))
 
2876
        default='600',
 
2877
        from_unicode=int_from_store,
 
2878
        help='Abort selftest if one test takes longer than this many seconds',
 
2879
        ))
2624
2880
 
2625
2881
option_registry.register(
2626
2882
    Option('send_strict', default=None,
2638
2894
           help="If we wait for a new request from a client for more than"
2639
2895
                " X seconds, consider the client idle, and hangup."))
2640
2896
option_registry.register(
2641
 
    Option('ssh',
2642
 
           default=None, override_from_env=['BRZ_SSH'],
2643
 
           help='SSH vendor to use.'))
2644
 
option_registry.register(
2645
2897
    Option('stacked_on_location',
2646
2898
           default=None,
2647
2899
           help="""The location where this branch is stacked on."""))
2659
2911
           help='''Where submissions from this branch are mailed to.'''))
2660
2912
option_registry.register(
2661
2913
    ListOption('suppress_warnings',
2662
 
               default=[],
2663
 
               help="List of warning classes to suppress."))
 
2914
           default=[],
 
2915
           help="List of warning classes to suppress."))
2664
2916
option_registry.register(
2665
2917
    Option('validate_signatures_in_log', default=False,
2666
2918
           from_unicode=bool_from_store, invalid='warning',
2667
 
           help='''Whether to validate signatures in brz log.'''))
 
2919
           help='''Whether to validate signatures in bzr log.'''))
2668
2920
option_registry.register_lazy('ssl.ca_certs',
2669
 
                              'breezy.transport.http', 'opt_ssl_ca_certs')
 
2921
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2670
2922
 
2671
2923
option_registry.register_lazy('ssl.cert_reqs',
2672
 
                              'breezy.transport.http', 'opt_ssl_cert_reqs')
 
2924
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2673
2925
 
2674
2926
 
2675
2927
class Section(object):
2689
2941
        return self.options.get(name, default)
2690
2942
 
2691
2943
    def iter_option_names(self):
2692
 
        for k in self.options.keys():
 
2944
        for k in self.options.iterkeys():
2693
2945
            yield k
2694
2946
 
2695
2947
    def __repr__(self):
2736
2988
 
2737
2989
        :param store: the store containing the section
2738
2990
        """
2739
 
        for k, expected in dirty.orig.items():
 
2991
        for k, expected in dirty.orig.iteritems():
2740
2992
            actual = dirty.get(k, _DeletedOption)
2741
2993
            reloaded = self.get(k, _NewlyCreatedOption)
2742
2994
            if actual is _DeletedOption:
2758
3010
                # Someone changed the value since we get it from the persistent
2759
3011
                # storage.
2760
3012
                trace.warning(gettext(
2761
 
                    "Option {0} in section {1} of {2} was changed"
2762
 
                    " from {3} to {4}. The {5} value will be saved.".format(
2763
 
                        k, self.id, store.external_url(), expected,
2764
 
                        reloaded, actual)))
 
3013
                        "Option {0} in section {1} of {2} was changed"
 
3014
                        " from {3} to {4}. The {5} value will be saved.".format(
 
3015
                            k, self.id, store.external_url(), expected,
 
3016
                            reloaded, actual)))
2765
3017
        # No need to keep track of these changes
2766
3018
        self.reset_changes()
2767
3019
 
2844
3096
        # get_mutable_section() call below.
2845
3097
        self.unload()
2846
3098
        # Apply the changes from the preserved dirty sections
2847
 
        for section_id, dirty in dirty_sections.items():
 
3099
        for section_id, dirty in dirty_sections.iteritems():
2848
3100
            clean = self.get_mutable_section(section_id)
2849
3101
            clean.apply_changes(dirty, self)
2850
3102
        # Everything is clean now
2902
3154
            try:
2903
3155
                name, value = over.split('=', 1)
2904
3156
            except ValueError:
2905
 
                raise errors.CommandError(
 
3157
                raise errors.BzrCommandError(
2906
3158
                    gettext("Invalid '%s', should be of the form 'name=value'")
2907
3159
                    % (over,))
2908
3160
            self.options[name] = value
2913
3165
        return 'cmdline'
2914
3166
 
2915
3167
    def get_sections(self):
2916
 
        yield self, self.readonly_section_class(None, self.options)
 
3168
        yield self,  self.readonly_section_class(None, self.options)
2917
3169
 
2918
3170
 
2919
3171
class IniFileStore(Store):
2930
3182
        self._config_obj = None
2931
3183
 
2932
3184
    def is_loaded(self):
2933
 
        return self._config_obj is not None
 
3185
        return self._config_obj != None
2934
3186
 
2935
3187
    def unload(self):
2936
3188
        self._config_obj = None
2970
3222
        """
2971
3223
        if self.is_loaded():
2972
3224
            raise AssertionError('Already loaded: %r' % (self._config_obj,))
2973
 
        co_input = BytesIO(bytes)
 
3225
        co_input = StringIO(bytes)
2974
3226
        try:
2975
3227
            # The config files are always stored utf8-encoded
2976
3228
            self._config_obj = ConfigObj(co_input, encoding='utf-8',
2977
3229
                                         list_values=False)
2978
 
        except configobj.ConfigObjError as e:
 
3230
        except configobj.ConfigObjError, e:
2979
3231
            self._config_obj = None
2980
 
            raise ParseConfigError(e.errors, self.external_url())
 
3232
            raise errors.ParseConfigError(e.errors, self.external_url())
2981
3233
        except UnicodeDecodeError:
2982
 
            raise ConfigContentError(self.external_url())
 
3234
            raise errors.ConfigContentError(self.external_url())
2983
3235
 
2984
3236
    def save_changes(self):
2985
3237
        if not self.is_loaded():
2988
3240
        if not self._need_saving():
2989
3241
            return
2990
3242
        # Preserve the current version
2991
 
        dirty_sections = self.dirty_sections.copy()
 
3243
        dirty_sections = dict(self.dirty_sections.items())
2992
3244
        self.apply_changes(dirty_sections)
2993
3245
        # Save to the persistent storage
2994
3246
        self.save()
2997
3249
        if not self.is_loaded():
2998
3250
            # Nothing to save
2999
3251
            return
3000
 
        out = BytesIO()
 
3252
        out = StringIO()
3001
3253
        self._config_obj.write(out)
3002
3254
        self._save_content(out.getvalue())
3003
3255
        for hook in ConfigHooks['save']:
3028
3280
            self.load()
3029
3281
        except errors.NoSuchFile:
3030
3282
            # The file doesn't exist, let's pretend it was empty
3031
 
            self._load_from_string(b'')
 
3283
            self._load_from_string('')
3032
3284
        if section_id in self.dirty_sections:
3033
3285
            # We already created a mutable section for this id
3034
3286
            return self.dirty_sections[section_id]
3050
3302
            self._config_obj.list_values = False
3051
3303
 
3052
3304
    def unquote(self, value):
3053
 
        if value and isinstance(value, str):
 
3305
        if value and isinstance(value, basestring):
3054
3306
            # _unquote doesn't handle None nor empty strings nor anything that
3055
3307
            # is not a string, really.
3056
3308
            value = self._config_obj._unquote(value)
3099
3351
        # The following will do in the interim but maybe we don't want to
3100
3352
        # expose a path here but rather a config ID and its associated
3101
3353
        # object </hand wawe>.
3102
 
        return urlutils.join(
3103
 
            self.transport.external_url(), urlutils.escape(self.file_name))
 
3354
        return urlutils.join(self.transport.external_url(), self.file_name)
3104
3355
 
3105
3356
 
3106
3357
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
3134
3385
        # ensure_config_dir_exists does. It should if the transport is local
3135
3386
        # -- vila 2011-04-06
3136
3387
        self.transport.create_prefix()
3137
 
        token = self._lock.lock_write(token)
3138
 
        return lock.LogicalLockResult(self.unlock, token)
 
3388
        return self._lock.lock_write(token)
3139
3389
 
3140
3390
    def unlock(self):
3141
3391
        self._lock.unlock()
3143
3393
    def break_lock(self):
3144
3394
        self._lock.break_lock()
3145
3395
 
 
3396
    @needs_write_lock
3146
3397
    def save(self):
3147
 
        with self.lock_write():
3148
 
            # We need to be able to override the undecorated implementation
3149
 
            self.save_without_locking()
 
3398
        # We need to be able to override the undecorated implementation
 
3399
        self.save_without_locking()
3150
3400
 
3151
3401
    def save_without_locking(self):
3152
3402
        super(LockableIniFileStore, self).save()
3153
3403
 
3154
3404
 
3155
 
# FIXME: global, breezy, shouldn't that be 'user' instead or even
 
3405
# FIXME: global, bazaar, shouldn't that be 'user' instead or even
3156
3406
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
3157
3407
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
3158
3408
 
3167
3417
    """
3168
3418
 
3169
3419
    def __init__(self, possible_transports=None):
3170
 
        path, kind = bedding._config_dir()
3171
3420
        t = transport.get_transport_from_path(
3172
 
            path, possible_transports=possible_transports)
3173
 
        super(GlobalStore, self).__init__(t, kind + '.conf')
3174
 
        self.id = 'breezy'
 
3421
            config_dir(), possible_transports=possible_transports)
 
3422
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
 
3423
        self.id = 'bazaar'
3175
3424
 
3176
3425
 
3177
3426
class LocationStore(LockableIniFileStore):
3182
3431
 
3183
3432
    def __init__(self, possible_transports=None):
3184
3433
        t = transport.get_transport_from_path(
3185
 
            bedding.config_dir(), possible_transports=possible_transports)
 
3434
            config_dir(), possible_transports=possible_transports)
3186
3435
        super(LocationStore, self).__init__(t, 'locations.conf')
3187
3436
        self.id = 'locations'
3188
3437
 
3204
3453
 
3205
3454
    def __init__(self, bzrdir):
3206
3455
        super(ControlStore, self).__init__(bzrdir.transport,
3207
 
                                           'control.conf',
 
3456
                                          'control.conf',
3208
3457
                                           lock_dir_name='branch_lock')
3209
3458
        self.id = 'control'
3210
3459
 
3321
3570
                # the location is already a local path or URL, convert the
3322
3571
                # section id to the same format
3323
3572
                section_path = urlutils.local_path_from_url(section_path)
3324
 
            if (self.location.startswith(section_path) or
3325
 
                    fnmatch.fnmatch(self.location, section_path)):
 
3573
            if (self.location.startswith(section_path)
 
3574
                or fnmatch.fnmatch(self.location, section_path)):
3326
3575
                section_parts = section_path.rstrip('/').split('/')
3327
3576
                extra_path = '/'.join(location_parts[len(section_parts):])
3328
3577
                yield store, LocationSection(section, extra_path)
3370
3619
            # sections are part of 'all_sections' and will always be found
3371
3620
            # there.
3372
3621
            while True:
3373
 
                section = next(iter_all_sections)
 
3622
                section = iter_all_sections.next()
3374
3623
                if section_id == section.id:
3375
3624
                    section = LocationSection(section, extra_path,
3376
3625
                                              self.branch_name)
3380
3629
 
3381
3630
    def get_sections(self):
3382
3631
        # Override the default implementation as we want to change the order
 
3632
        matching_sections = self._get_matching_sections()
3383
3633
        # We want the longest (aka more specific) locations first
3384
 
        sections = sorted(self._get_matching_sections(),
3385
 
                          key=lambda match: (match[0], match[1].id),
 
3634
        sections = sorted(matching_sections,
 
3635
                          key=lambda (length, section): (length, section.id),
3386
3636
                          reverse=True)
3387
3637
        # Sections mentioning 'ignore_parents' restrict the selection
3388
3638
        for _, section in sections:
3401
3651
_shared_stores = {}
3402
3652
_shared_stores_at_exit_installed = False
3403
3653
 
3404
 
 
3405
3654
class Stack(object):
3406
3655
    """A stack of configurations where an option can be defined"""
3407
3656
 
3453
3702
        """
3454
3703
        # FIXME: No caching of options nor sections yet -- vila 20110503
3455
3704
        value = None
3456
 
        found_store = None  # Where the option value has been found
 
3705
        found_store = None # Where the option value has been found
3457
3706
        # If the option is registered, it may provide additional info about
3458
3707
        # value handling
3459
3708
        try:
3467
3716
            # None or ends up being None during expansion or conversion.
3468
3717
            if val is not None:
3469
3718
                if expand:
3470
 
                    if isinstance(val, str):
 
3719
                    if isinstance(val, basestring):
3471
3720
                        val = self._expand_options_in_string(val)
3472
3721
                    else:
3473
3722
                        trace.warning('Cannot expand "%s":'
3544
3793
                    expanded = True
3545
3794
                    name = chunk[1:-1]
3546
3795
                    if name in _refs:
3547
 
                        raise OptionExpansionLoop(string, _refs)
 
3796
                        raise errors.OptionExpansionLoop(string, _refs)
3548
3797
                    _refs.append(name)
3549
3798
                    value = self._expand_option(name, env, _refs)
3550
3799
                    if value is None:
3551
 
                        raise ExpandingUnknownOption(name, string)
 
3800
                        raise errors.ExpandingUnknownOption(name, string)
3552
3801
                    chunks.append(value)
3553
3802
                    _refs.pop()
3554
3803
            result = ''.join(chunks)
3595
3844
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3596
3845
 
3597
3846
    def _get_overrides(self):
3598
 
        if breezy._global_state is not None:
3599
 
            # TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3600
 
            return breezy._global_state.cmdline_overrides.get_sections()
 
3847
        # FIXME: Hack around library_state.initialize never called
 
3848
        if bzrlib.global_state is not None:
 
3849
            return bzrlib.global_state.cmdline_overrides.get_sections()
3601
3850
        return []
3602
3851
 
3603
3852
    def get_shared_store(self, store, state=None):
3614
3863
            otherwise.
3615
3864
        """
3616
3865
        if state is None:
3617
 
            # TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3618
 
            state = breezy._global_state
 
3866
            state = bzrlib.global_state
3619
3867
        if state is None:
3620
3868
            global _shared_stores_at_exit_installed
3621
3869
            stores = _shared_stores
3622
 
 
3623
3870
            def save_config_changes():
3624
 
                for k, store in stores.items():
 
3871
                for k, store in stores.iteritems():
3625
3872
                    store.save_changes()
3626
3873
            if not _shared_stores_at_exit_installed:
3627
3874
                # FIXME: Ugly hack waiting for library_state to always be
3784
4031
    def unlock(self):
3785
4032
        return self.branch.unlock()
3786
4033
 
 
4034
    @needs_write_lock
3787
4035
    def set(self, name, value):
3788
 
        with self.lock_write():
3789
 
            super(BranchStack, self).set(name, value)
3790
 
            # Unlocking the branch will trigger a store.save_changes() so the
3791
 
            # last unlock saves all the changes.
 
4036
        super(BranchStack, self).set(name, value)
 
4037
        # Unlocking the branch will trigger a store.save_changes() so the last
 
4038
        # unlock saves all the changes.
3792
4039
 
 
4040
    @needs_write_lock
3793
4041
    def remove(self, name):
3794
 
        with self.lock_write():
3795
 
            super(BranchStack, self).remove(name)
3796
 
            # Unlocking the branch will trigger a store.save_changes() so the
3797
 
            # last unlock saves all the changes.
 
4042
        super(BranchStack, self).remove(name)
 
4043
        # Unlocking the branch will trigger a store.save_changes() so the last
 
4044
        # unlock saves all the changes.
3798
4045
 
3799
4046
 
3800
4047
class RemoteControlStack(Stack):
3809
4056
        super(RemoteControlStack, self).__init__(
3810
4057
            [NameMatcher(cstore, None).get_sections],
3811
4058
            cstore)
3812
 
        self.controldir = bzrdir
 
4059
        self.bzrdir = bzrdir
3813
4060
 
3814
4061
 
3815
4062
class BranchOnlyStack(Stack):
3832
4079
    def unlock(self):
3833
4080
        return self.branch.unlock()
3834
4081
 
 
4082
    @needs_write_lock
3835
4083
    def set(self, name, value):
3836
 
        with self.lock_write():
3837
 
            super(BranchOnlyStack, self).set(name, value)
3838
 
            # Force a write to persistent storage
3839
 
            self.store.save_changes()
 
4084
        super(BranchOnlyStack, self).set(name, value)
 
4085
        # Force a write to persistent storage
 
4086
        self.store.save_changes()
3840
4087
 
 
4088
    @needs_write_lock
3841
4089
    def remove(self, name):
3842
 
        with self.lock_write():
3843
 
            super(BranchOnlyStack, self).remove(name)
3844
 
            # Force a write to persistent storage
3845
 
            self.store.save_changes()
 
4090
        super(BranchOnlyStack, self).remove(name)
 
4091
        # Force a write to persistent storage
 
4092
        self.store.save_changes()
3846
4093
 
3847
4094
 
3848
4095
class cmd_config(commands.Command):
3874
4121
        # http://pad.lv/788991 -- vila 20101115
3875
4122
        commands.Option('scope', help='Reduce the scope to the specified'
3876
4123
                        ' configuration file.',
3877
 
                        type=str),
 
4124
                        type=unicode),
3878
4125
        commands.Option('all',
3879
 
                        help='Display all the defined values for the matching options.',
3880
 
                        ),
 
4126
            help='Display all the defined values for the matching options.',
 
4127
            ),
3881
4128
        commands.Option('remove', help='Remove the option from'
3882
4129
                        ' the configuration file.'),
3883
4130
        ]
3930
4177
        # reduced to the plugin-specific store), related to
3931
4178
        # http://pad.lv/788991 -- vila 2011-11-15
3932
4179
        if scope is not None:
3933
 
            if scope == 'breezy':
 
4180
            if scope == 'bazaar':
3934
4181
                return GlobalStack()
3935
4182
            elif scope == 'locations':
3936
4183
                return LocationStack(directory)
3941
4188
                if write_access:
3942
4189
                    self.add_cleanup(br.lock_write().unlock)
3943
4190
                return br.get_config_stack()
3944
 
            raise NoSuchConfig(scope)
 
4191
            raise errors.NoSuchConfig(scope)
3945
4192
        else:
3946
4193
            try:
3947
4194
                (_, br, _) = (
3966
4213
            value = self._quote_multiline(value)
3967
4214
            self.outf.write('%s\n' % (value,))
3968
4215
        else:
3969
 
            raise NoSuchConfigOption(name)
 
4216
            raise errors.NoSuchConfigOption(name)
3970
4217
 
3971
4218
    def _show_matching_options(self, name, directory, scope):
3972
4219
        name = lazy_regex.lazy_compile(name)
4003
4250
 
4004
4251
    def _remove_config_option(self, name, directory, scope):
4005
4252
        if name is None:
4006
 
            raise errors.CommandError(
 
4253
            raise errors.BzrCommandError(
4007
4254
                '--remove expects an option to remove.')
4008
4255
        conf = self._get_stack(directory, scope, write_access=True)
4009
4256
        try:
4011
4258
            # Explicitly save the changes
4012
4259
            conf.store.save_changes()
4013
4260
        except KeyError:
4014
 
            raise NoSuchConfigOption(name)
 
4261
            raise errors.NoSuchConfigOption(name)
4015
4262
 
4016
4263
 
4017
4264
# Test registries
4021
4268
# themselves. The builder will receive a test instance and should return a
4022
4269
# ready-to-use store or stack.  Plugins that define new store/stacks can also
4023
4270
# register themselves here to be tested against the tests defined in
4024
 
# breezy.tests.test_config. Note that the builder can be called multiple times
 
4271
# bzrlib.tests.test_config. Note that the builder can be called multiple times
4025
4272
# for the same test.
4026
4273
 
4027
4274
# The registered object should be a callable receiving a test instance