/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 breezy/config.py

  • Committer: Jelmer Vernooij
  • Date: 2018-02-18 21:42:57 UTC
  • mto: This revision was merged to the branch mainline in revision 6859.
  • Revision ID: jelmer@jelmer.uk-20180218214257-jpevutp1wa30tz3v
Update TODO to reference Breezy, not Bazaar.

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
email - this option sets the user id brz will use when committing.
54
54
check_signatures - this option will control whether brz will require good gpg
55
55
                   signatures, ignore them, or check them if they are
56
 
                   present.  Currently it is unused except that
57
 
                   check_signatures turns on create_signatures.
 
56
                   present.  Currently it is unused except that check_signatures
 
57
                   turns on create_signatures.
58
58
create_signatures - this option controls whether brz will always create
59
59
                    gpg signatures or not on commits.  There is an unused
60
60
                    option which in future is expected to work if
74
74
up=pull
75
75
"""
76
76
 
 
77
from __future__ import absolute_import
77
78
import os
78
79
import sys
79
80
 
80
81
import configobj
81
 
from io import BytesIO
82
82
 
83
83
import breezy
84
84
from .lazy_import import lazy_import
90
90
import stat
91
91
 
92
92
from breezy import (
93
 
    cmdline,
 
93
    atomicfile,
94
94
    controldir,
95
95
    debug,
96
96
    directory_service,
 
97
    lazy_regex,
 
98
    library_state,
97
99
    lock,
98
100
    lockdir,
99
101
    mergetools,
108
110
""")
109
111
from . import (
110
112
    commands,
111
 
    bedding,
112
113
    errors,
113
114
    hooks,
114
115
    lazy_regex,
115
116
    registry,
116
117
    )
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
 
118
from .sixish import (
 
119
    binary_type,
 
120
    BytesIO,
 
121
    PY3,
 
122
    text_type,
 
123
    string_types,
 
124
    )
 
125
 
 
126
 
 
127
CHECK_IF_POSSIBLE=0
 
128
CHECK_ALWAYS=1
 
129
CHECK_NEVER=2
 
130
 
 
131
 
 
132
SIGN_WHEN_REQUIRED=0
 
133
SIGN_ALWAYS=1
 
134
SIGN_NEVER=2
127
135
 
128
136
 
129
137
POLICY_NONE = 0
226
234
        errors.BzrError.__init__(self, option_name=option_name)
227
235
 
228
236
 
 
237
class NoWhoami(errors.BzrError):
 
238
 
 
239
    _fmt = ('Unable to determine your name.\n'
 
240
        "Please, set your name with the 'whoami' command.\n"
 
241
        'E.g. brz whoami "Your Name <name@example.com>"')
 
242
 
 
243
 
229
244
def signature_policy_from_unicode(signature_string):
230
245
    """Convert a string to a signing policy."""
231
246
    if signature_string.lower() == 'check-available':
250
265
                     % signature_string)
251
266
 
252
267
 
 
268
def _has_decode_bug():
 
269
    """True if configobj will fail to decode to unicode on Python 2."""
 
270
    if sys.version_info > (3,):
 
271
        return False
 
272
    conf = configobj.ConfigObj()
 
273
    decode = getattr(conf, "_decode", None)
 
274
    if decode:
 
275
        result = decode(b"\xc2\xa7", "utf-8")
 
276
        if isinstance(result[0], str):
 
277
            return True
 
278
    return False
 
279
 
 
280
 
253
281
def _has_triplequote_bug():
254
282
    """True if triple quote logic is reversed, see lp:710410."""
255
283
    conf = configobj.ConfigObj()
267
295
                                        interpolation=False,
268
296
                                        **kwargs)
269
297
 
 
298
    if _has_decode_bug():
 
299
        def _decode(self, infile, encoding):
 
300
            if isinstance(infile, str) and encoding:
 
301
                return infile.decode(encoding).splitlines(True)
 
302
            return super(ConfigObj, self)._decode(infile, encoding)
 
303
 
270
304
    if _has_triplequote_bug():
271
305
        def _get_triple_quote(self, value):
272
306
            quot = super(ConfigObj, self)._get_triple_quote(value)
302
336
        cmd = self._get_change_editor()
303
337
        if cmd is None:
304
338
            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
339
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
311
340
                                             sys.stdout)
312
341
 
493
522
            otherwise.
494
523
        """
495
524
        l = self.get_user_option(option_name, expand=expand)
496
 
        if isinstance(l, str):
 
525
        if isinstance(l, string_types):
497
526
            # A single value, most probably the user forgot (or didn't care to
498
527
            # add) the final ','
499
528
            l = [l]
529
558
 
530
559
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
531
560
 
532
 
        $BRZ_EMAIL or $BZR_EMAIL can be set to override this, then
 
561
        $BRZ_EMAIL can be set to override this, then
533
562
        the concrete policy type is checked, and finally
534
563
        $EMAIL is examined.
535
564
        If no username can be found, NoWhoami exception is raised.
536
565
        """
537
 
        v = os.environ.get('BRZ_EMAIL') or os.environ.get('BZR_EMAIL')
 
566
        v = os.environ.get('BRZ_EMAIL')
538
567
        if v:
 
568
            if not PY3:
 
569
                v = v.decode(osutils.get_user_encoding())
539
570
            return v
540
571
        v = self._get_user_id()
541
572
        if v:
542
573
            return v
543
 
        return bedding.default_email()
 
574
        return default_email()
 
575
 
 
576
    def ensure_username(self):
 
577
        """Raise NoWhoami if username is not set.
 
578
 
 
579
        This method relies on the username() function raising the error.
 
580
        """
 
581
        self.username()
544
582
 
545
583
    def get_alias(self, value):
546
584
        return self._get_alias(value)
591
629
        # This should be done through the proposed config defaults mechanism
592
630
        # when it becomes available in the future.
593
631
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
594
 
                                             expand=False) or
595
 
                        mergetools.known_merge_tools.get(name, None))
 
632
                                             expand=False)
 
633
                        or mergetools.known_merge_tools.get(name, None))
596
634
        return command_line
597
635
 
598
636
 
628
666
                      'Invoked when a config option is removed.'
629
667
                      ' The signature is (stack, name).',
630
668
                      (2, 4))
631
 
 
632
 
 
633
669
ConfigHooks = _ConfigHooks()
634
670
 
635
671
 
643
679
        These are all empty initially, because by default nothing should get
644
680
        notified.
645
681
        """
646
 
        super(_OldConfigHooks, self).__init__(
647
 
            'breezy.config', 'OldConfigHooks')
 
682
        super(_OldConfigHooks, self).__init__('breezy.config', 'OldConfigHooks')
648
683
        self.add_hook('load',
649
684
                      'Invoked when a config store is loaded.'
650
685
                      ' The signature is (config).',
666
701
                      'Invoked when a config option is removed.'
667
702
                      ' The signature is (config, name).',
668
703
                      (2, 4))
669
 
 
670
 
 
671
704
OldConfigHooks = _OldConfigHooks()
672
705
 
673
706
 
689
722
    def from_string(cls, str_or_unicode, file_name=None, save=False):
690
723
        """Create a config object from a string.
691
724
 
692
 
        :param str_or_unicode: A string representing the file content. This
693
 
            will be utf-8 encoded.
 
725
        :param str_or_unicode: A string representing the file content. This will
 
726
            be utf-8 encoded.
694
727
 
695
728
        :param file_name: The configuration file path.
696
729
 
701
734
        return conf
702
735
 
703
736
    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)
 
737
        self._content = BytesIO(str_or_unicode.encode('utf-8'))
707
738
        # Some tests use in-memory configs, some other always need the config
708
739
        # file to exist on disk.
709
740
        if save:
785
816
            which sections should be searched. This is a list of (name,
786
817
            configobj) tuples.
787
818
        """
 
819
        opts = []
788
820
        if sections is None:
789
821
            parser = self._get_parser()
790
822
            sections = []
808
840
        return POLICY_NONE
809
841
 
810
842
    def _get_change_editor(self):
811
 
        return self.get_user_option('change_editor', expand=False)
 
843
        return self.get_user_option('change_editor')
812
844
 
813
845
    def _get_signature_checking(self):
814
846
        """See Config._get_signature_checking."""
902
934
    def _write_config_file(self):
903
935
        if self.file_name is None:
904
936
            raise AssertionError('We cannot save, self.file_name is None')
905
 
        from . import atomicfile
906
937
        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)
 
938
        ensure_config_dir_exists(conf_dir)
 
939
        atomic_file = atomicfile.AtomicFile(self.file_name)
 
940
        self._get_parser().write(atomic_file)
 
941
        atomic_file.commit()
 
942
        atomic_file.close()
910
943
        osutils.copy_ownership_from_path(self.file_name)
911
944
        for hook in OldConfigHooks['save']:
912
945
            hook(self)
918
951
    If several processes try to write the config file, the accesses need to be
919
952
    serialized.
920
953
 
921
 
    Daughter classes should use the self.lock_write() decorator method when
922
 
    they upate a config (they call, directly or indirectly, the
 
954
    Daughter classes should use the self.lock_write() decorator method when they 
 
955
    upate a config (they call, directly or indirectly, the
923
956
    ``_write_config_file()`` method. These methods (typically ``set_option()``
924
957
    and variants must reload the config file from disk before calling
925
958
    ``_write_config_file()``), this can be achieved by calling the
964
997
 
965
998
        If the directory doesn't exist it is created.
966
999
        """
967
 
        bedding.ensure_config_dir_exists(self.dir)
 
1000
        ensure_config_dir_exists(self.dir)
968
1001
        token = self._lock.lock_write(token)
969
1002
        return lock.LogicalLockResult(self.unlock, token)
970
1003
 
977
1010
    def remove_user_option(self, option_name, section_name=None):
978
1011
        with self.lock_write():
979
1012
            super(LockableConfig, self).remove_user_option(
980
 
                option_name, section_name)
 
1013
                    option_name, section_name)
981
1014
 
982
1015
    def _write_config_file(self):
983
1016
        if self._lock is None or not self._lock.is_held:
991
1024
    """The configuration that should be used for a specific location."""
992
1025
 
993
1026
    def __init__(self):
994
 
        super(GlobalConfig, self).__init__(file_name=bedding.config_path())
 
1027
        super(GlobalConfig, self).__init__(file_name=config_filename())
995
1028
 
996
1029
    def config_id(self):
997
1030
        return 'breezy'
1064
1097
            # We need to avoid the LockableConfig implementation or we'll lock
1065
1098
            # twice
1066
1099
            super(LockableConfig, self).remove_user_option(
1067
 
                option_name, section_name)
 
1100
                    option_name, section_name)
1068
1101
 
1069
1102
 
1070
1103
def _iter_for_location_by_parts(sections, location):
1123
1156
 
1124
1157
    def __init__(self, location):
1125
1158
        super(LocationConfig, self).__init__(
1126
 
            file_name=bedding.locations_config_path())
 
1159
            file_name=locations_config_filename())
1127
1160
        # local file locations are looked up by local path, rather than
1128
1161
        # by file url. This is because the config file is a user
1129
1162
        # file, and we would rather not expose the user to file urls.
1319
1352
                yield section
1320
1353
 
1321
1354
    def _get_options(self, sections=None):
 
1355
        opts = []
1322
1356
        # First the locations options
1323
1357
        for option in self._get_location_config()._get_options():
1324
1358
            yield option
1338
1372
            yield option
1339
1373
 
1340
1374
    def set_user_option(self, name, value, store=STORE_BRANCH,
1341
 
                        warn_masked=False):
 
1375
        warn_masked=False):
1342
1376
        if store == STORE_BRANCH:
1343
1377
            self._get_branch_data_config().set_option(value, name)
1344
1378
        elif store == STORE_GLOBAL:
1395
1429
        return self._get_best_value('_acceptable_keys')
1396
1430
 
1397
1431
 
 
1432
def ensure_config_dir_exists(path=None):
 
1433
    """Make sure a configuration directory exists.
 
1434
    This makes sure that the directory exists.
 
1435
    On windows, since configuration directories are 2 levels deep,
 
1436
    it makes sure both the directory and the parent directory exists.
 
1437
    """
 
1438
    if path is None:
 
1439
        path = config_dir()
 
1440
    if not os.path.isdir(path):
 
1441
        if sys.platform == 'win32':
 
1442
            parent_dir = os.path.dirname(path)
 
1443
            if not os.path.isdir(parent_dir):
 
1444
                trace.mutter('creating config parent directory: %r', parent_dir)
 
1445
                os.mkdir(parent_dir)
 
1446
        trace.mutter('creating config directory: %r', path)
 
1447
        os.mkdir(path)
 
1448
        osutils.copy_ownership_from_path(path)
 
1449
 
 
1450
 
 
1451
def bazaar_config_dir():
 
1452
    """Return per-user configuration directory as unicode string
 
1453
 
 
1454
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
 
1455
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
 
1456
    that will be used instead.
 
1457
 
 
1458
    TODO: Global option --config-dir to override this.
 
1459
    """
 
1460
    base = osutils.path_from_environ('BZR_HOME')
 
1461
    if sys.platform == 'win32':
 
1462
        if base is None:
 
1463
            base = win32utils.get_appdata_location()
 
1464
        if base is None:
 
1465
            base = win32utils.get_home_location()
 
1466
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
1467
    if base is None:
 
1468
        xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
 
1469
        if xdg_dir is None:
 
1470
            xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
1471
        xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
1472
        if osutils.isdir(xdg_dir):
 
1473
            trace.mutter(
 
1474
                "Using configuration in XDG directory %s." % xdg_dir)
 
1475
            return xdg_dir
 
1476
        base = osutils._get_home_dir()
 
1477
    return osutils.pathjoin(base, ".bazaar")
 
1478
 
 
1479
 
 
1480
def _config_dir():
 
1481
    """Return per-user configuration directory as unicode string
 
1482
 
 
1483
    By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
 
1484
    Mac OS X and Linux. If the breezy config directory doesn't exist but
 
1485
    the bazaar one (see bazaar_config_dir()) does, use that instead.
 
1486
    """
 
1487
    # TODO: Global option --config-dir to override this.
 
1488
    base = osutils.path_from_environ('BRZ_HOME')
 
1489
    if sys.platform == 'win32':
 
1490
        if base is None:
 
1491
            base = win32utils.get_appdata_location()
 
1492
        if base is None:
 
1493
            base = win32utils.get_home_location()
 
1494
    if base is None:
 
1495
        base = osutils.path_from_environ('XDG_CONFIG_HOME')
 
1496
        if base is None:
 
1497
            base = osutils.pathjoin(osutils._get_home_dir(), ".config")
 
1498
    breezy_dir = osutils.pathjoin(base, 'breezy')
 
1499
    if osutils.isdir(breezy_dir):
 
1500
        return (breezy_dir, 'breezy')
 
1501
    # If the breezy directory doesn't exist, but the bazaar one does, use that:
 
1502
    bazaar_dir = bazaar_config_dir()
 
1503
    if osutils.isdir(bazaar_dir):
 
1504
        trace.mutter(
 
1505
            "Using Bazaar configuration directory (%s)", bazaar_dir)
 
1506
        return (bazaar_dir, 'bazaar')
 
1507
    return (breezy_dir, 'breezy')
 
1508
 
 
1509
 
 
1510
def config_dir():
 
1511
    """Return per-user configuration directory as unicode string
 
1512
 
 
1513
    By default this is %APPDATA%/breezy on Windows, $XDG_CONFIG_HOME/breezy on
 
1514
    Mac OS X and Linux. If the breezy config directory doesn't exist but
 
1515
    the bazaar one (see bazaar_config_dir()) does, use that instead.
 
1516
    """
 
1517
    return _config_dir()[0]
 
1518
 
 
1519
 
 
1520
def config_filename():
 
1521
    """Return per-user configuration ini file filename."""
 
1522
    path, kind = _config_dir()
 
1523
    if kind == 'bazaar':
 
1524
        return osutils.pathjoin(path, 'bazaar.conf')
 
1525
    else:
 
1526
        return osutils.pathjoin(path, 'breezy.conf')
 
1527
 
 
1528
 
 
1529
def locations_config_filename():
 
1530
    """Return per-user configuration ini file filename."""
 
1531
    return osutils.pathjoin(config_dir(), 'locations.conf')
 
1532
 
 
1533
 
 
1534
def authentication_config_filename():
 
1535
    """Return per-user authentication ini file filename."""
 
1536
    return osutils.pathjoin(config_dir(), 'authentication.conf')
 
1537
 
 
1538
 
 
1539
def user_ignore_config_filename():
 
1540
    """Return the user default ignore filename"""
 
1541
    return osutils.pathjoin(config_dir(), 'ignore')
 
1542
 
 
1543
 
 
1544
def crash_dir():
 
1545
    """Return the directory name to store crash files.
 
1546
 
 
1547
    This doesn't implicitly create it.
 
1548
 
 
1549
    On Windows it's in the config directory; elsewhere it's /var/crash
 
1550
    which may be monitored by apport.  It can be overridden by
 
1551
    $APPORT_CRASH_DIR.
 
1552
    """
 
1553
    if sys.platform == 'win32':
 
1554
        return osutils.pathjoin(config_dir(), 'Crash')
 
1555
    else:
 
1556
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
1557
        # 2010-01-31
 
1558
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
1559
 
 
1560
 
 
1561
def xdg_cache_dir():
 
1562
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
 
1563
    # Possibly this should be different on Windows?
 
1564
    e = os.environ.get('XDG_CACHE_HOME', None)
 
1565
    if e:
 
1566
        return e
 
1567
    else:
 
1568
        return os.path.expanduser('~/.cache')
 
1569
 
 
1570
 
 
1571
def _get_default_mail_domain(mailname_file='/etc/mailname'):
 
1572
    """If possible, return the assumed default email domain.
 
1573
 
 
1574
    :returns: string mail domain, or None.
 
1575
    """
 
1576
    if sys.platform == 'win32':
 
1577
        # No implementation yet; patches welcome
 
1578
        return None
 
1579
    try:
 
1580
        f = open(mailname_file)
 
1581
    except (IOError, OSError) as e:
 
1582
        return None
 
1583
    try:
 
1584
        domain = f.readline().strip()
 
1585
        return domain
 
1586
    finally:
 
1587
        f.close()
 
1588
 
 
1589
 
 
1590
def default_email():
 
1591
    v = os.environ.get('BRZ_EMAIL')
 
1592
    if v:
 
1593
        if not PY3:
 
1594
            v = v.decode(osutils.get_user_encoding())
 
1595
        return v
 
1596
    v = os.environ.get('EMAIL')
 
1597
    if v:
 
1598
        if not PY3:
 
1599
            v = v.decode(osutils.get_user_encoding())
 
1600
        return v
 
1601
    name, email = _auto_user_id()
 
1602
    if name and email:
 
1603
        return u'%s <%s>' % (name, email)
 
1604
    elif email:
 
1605
        return email
 
1606
    raise NoWhoami()
 
1607
 
 
1608
 
 
1609
def _auto_user_id():
 
1610
    """Calculate automatic user identification.
 
1611
 
 
1612
    :returns: (realname, email), either of which may be None if they can't be
 
1613
    determined.
 
1614
 
 
1615
    Only used when none is set in the environment or the id file.
 
1616
 
 
1617
    This only returns an email address if we can be fairly sure the 
 
1618
    address is reasonable, ie if /etc/mailname is set on unix.
 
1619
 
 
1620
    This doesn't use the FQDN as the default domain because that may be 
 
1621
    slow, and it doesn't use the hostname alone because that's not normally 
 
1622
    a reasonable address.
 
1623
    """
 
1624
    if sys.platform == 'win32':
 
1625
        # No implementation to reliably determine Windows default mail
 
1626
        # address; please add one.
 
1627
        return None, None
 
1628
 
 
1629
    default_mail_domain = _get_default_mail_domain()
 
1630
    if not default_mail_domain:
 
1631
        return None, None
 
1632
 
 
1633
    import pwd
 
1634
    uid = os.getuid()
 
1635
    try:
 
1636
        w = pwd.getpwuid(uid)
 
1637
    except KeyError:
 
1638
        trace.mutter('no passwd entry for uid %d?' % uid)
 
1639
        return None, None
 
1640
 
 
1641
    # we try utf-8 first, because on many variants (like Linux),
 
1642
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
1643
    # false positives.  (many users will have their user encoding set to
 
1644
    # latin-1, which cannot raise UnicodeError.)
 
1645
    gecos = w.pw_gecos
 
1646
    if isinstance(gecos, bytes):
 
1647
        try:
 
1648
            gecos = gecos.decode('utf-8')
 
1649
            encoding = 'utf-8'
 
1650
        except UnicodeError:
 
1651
            try:
 
1652
                encoding = osutils.get_user_encoding()
 
1653
                gecos = gecos.decode(encoding)
 
1654
            except UnicodeError as e:
 
1655
                trace.mutter("cannot decode passwd entry %s" % w)
 
1656
                return None, None
 
1657
 
 
1658
    username = w.pw_name
 
1659
    if isinstance(username, bytes):
 
1660
        try:
 
1661
            username = username.decode(encoding)
 
1662
        except UnicodeError as e:
 
1663
            trace.mutter("cannot decode passwd entry %s" % w)
 
1664
            return None, None
 
1665
 
 
1666
    comma = gecos.find(',')
 
1667
    if comma == -1:
 
1668
        realname = gecos
 
1669
    else:
 
1670
        realname = gecos[:comma]
 
1671
 
 
1672
    return realname, (username + '@' + default_mail_domain)
 
1673
 
 
1674
 
1398
1675
def parse_username(username):
1399
1676
    """Parse e-mail username and return a (name, address) tuple."""
1400
1677
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1401
1678
    if match is None:
1402
1679
        return (username, '')
1403
 
    return (match.group(1), match.group(2))
 
1680
    else:
 
1681
        return (match.group(1), match.group(2))
1404
1682
 
1405
1683
 
1406
1684
def extract_email_address(e):
1422
1700
class TreeConfig(IniBasedConfig):
1423
1701
    """Branch configuration data associated with its contents, not location"""
1424
1702
 
1425
 
    # XXX: Really needs a better name, as this is not part of the tree!
1426
 
    # -- mbp 20080507
 
1703
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
1427
1704
 
1428
1705
    def __init__(self, branch):
1429
1706
        self._config = branch._get_config()
1463
1740
    """
1464
1741
 
1465
1742
    def __init__(self, _file=None):
1466
 
        self._config = None  # The ConfigObj
 
1743
        self._config = None # The ConfigObj
1467
1744
        if _file is None:
1468
 
            self._input = self._filename = bedding.authentication_config_path()
 
1745
            self._filename = authentication_config_filename()
 
1746
            self._input = self._filename = authentication_config_filename()
1469
1747
            self._check_permissions()
1470
1748
        else:
1471
1749
            # Tests can provide a string as _file
1498
1776
                trace.mutter('Unable to stat %r: %r', self._filename, e)
1499
1777
            return
1500
1778
        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):
 
1779
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP |
 
1780
             stat.S_IWGRP | stat.S_IRGRP ) & mode):
1503
1781
            # Only warn once
1504
 
            if (self._filename not in _authentication_config_permission_errors and
1505
 
                not GlobalConfig().suppress_warning(
 
1782
            if (not self._filename in _authentication_config_permission_errors
 
1783
                and not GlobalConfig().suppress_warning(
1506
1784
                    'insecure_permissions')):
1507
1785
                trace.warning("The file '%s' has insecure "
1508
 
                              "file permissions. Saved passwords may be accessible "
1509
 
                              "by other users.", self._filename)
 
1786
                        "file permissions. Saved passwords may be accessible "
 
1787
                        "by other users.", self._filename)
1510
1788
                _authentication_config_permission_errors.add(self._filename)
1511
1789
 
1512
1790
    def _save(self):
1513
1791
        """Save the config file, only tests should use it for now."""
1514
1792
        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)
 
1793
        ensure_config_dir_exists(conf_dir)
 
1794
        fd = os.open(self._filename, os.O_RDWR|os.O_CREAT, 0o600)
1517
1795
        try:
1518
1796
            f = os.fdopen(fd, 'wb')
1519
1797
            self._get_config().write(f)
1564
1842
        credentials = None
1565
1843
        for auth_def_name, auth_def in self._get_config().iteritems():
1566
1844
            if not isinstance(auth_def, configobj.Section):
1567
 
                raise ValueError("%s defined outside a section" %
1568
 
                                 auth_def_name)
 
1845
                raise ValueError("%s defined outside a section" % auth_def_name)
1569
1846
 
1570
1847
            a_scheme, a_host, a_user, a_path = map(
1571
1848
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1588
1865
            if a_scheme is not None and scheme != a_scheme:
1589
1866
                continue
1590
1867
            if a_host is not None:
1591
 
                if not (host == a_host or
1592
 
                        (a_host.startswith('.') and host.endswith(a_host))):
 
1868
                if not (host == a_host
 
1869
                        or (a_host.startswith('.') and host.endswith(a_host))):
1593
1870
                    continue
1594
1871
            if a_port is not None and port != a_port:
1595
1872
                continue
1596
 
            if (a_path is not None and path is not None and
1597
 
                    not path.startswith(a_path)):
 
1873
            if (a_path is not None and path is not None
 
1874
                and not path.startswith(a_path)):
1598
1875
                continue
1599
 
            if (a_user is not None and user is not None and
1600
 
                    a_user != user):
 
1876
            if (a_user is not None and user is not None
 
1877
                and a_user != user):
1601
1878
                # Never contradict the caller about the user to be used
1602
1879
                continue
1603
1880
            if a_user is None:
1664
1941
        if realm is not None:
1665
1942
            values['realm'] = realm
1666
1943
        config = self._get_config()
 
1944
        for_deletion = []
1667
1945
        for section, existing_values in config.iteritems():
1668
1946
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1669
1947
                if existing_values.get(key) != values.get(key):
1687
1965
 
1688
1966
        :param path: the absolute path on the server (optional)
1689
1967
 
1690
 
        :param ask: Ask the user if there is no explicitly configured username
 
1968
        :param ask: Ask the user if there is no explicitly configured username 
1691
1969
                    (optional)
1692
1970
 
1693
1971
        :param default: The username returned if none is defined (optional).
1737
2015
                                           realm)
1738
2016
        if credentials is not None:
1739
2017
            password = credentials['password']
1740
 
            if password is not None and scheme == 'ssh':
 
2018
            if password is not None and scheme is 'ssh':
1741
2019
                trace.warning('password ignored in section [%s],'
1742
2020
                              ' use an ssh agent instead'
1743
2021
                              % credentials['name'])
1748
2026
        if password is None:
1749
2027
            if prompt is None:
1750
2028
                # Create a default prompt suitable for most cases
1751
 
                prompt = (u'%s' %
1752
 
                          scheme.upper() + u' %(user)s@%(host)s password')
 
2029
                prompt = u'%s' % scheme.upper() + u' %(user)s@%(host)s password'
1753
2030
            # Special handling for optional fields in the prompt
1754
2031
            if port is not None:
1755
2032
                prompt_host = '%s:%d' % (host, port)
1824
2101
        :param override_existing: Raise KeyErorr if False and something has
1825
2102
                already been registered for that key. If True, ignore if there
1826
2103
                is an existing key (always register the new value).
1827
 
        :param fallback: Whether this credential store should be
 
2104
        :param fallback: Whether this credential store should be 
1828
2105
                used as fallback.
1829
2106
        """
1830
2107
        return super(CredentialStoreRegistry,
1844
2121
        :param override_existing: If True, replace the existing object
1845
2122
                with the new one. If False, if there is already something
1846
2123
                registered with the same key, raise a KeyError
1847
 
        :param fallback: Whether this credential store should be
 
2124
        :param fallback: Whether this credential store should be 
1848
2125
                used as fallback.
1849
2126
        """
1850
2127
        return super(CredentialStoreRegistry, self).register_lazy(
1871
2148
        raise NotImplementedError(self.get_credentials)
1872
2149
 
1873
2150
 
 
2151
 
1874
2152
class PlainTextCredentialStore(CredentialStore):
1875
2153
    __doc__ = """Plain text credential store for the authentication.conf file"""
1876
2154
 
1891
2169
        """See CredentialStore.decode_password."""
1892
2170
        # GZ 2012-07-28: Will raise binascii.Error if password is not base64,
1893
2171
        #                should probably propogate as something more useful.
1894
 
        return base64.standard_b64decode(credentials['password'])
1895
 
 
 
2172
        return base64.decodestring(credentials['password'])
1896
2173
 
1897
2174
credential_store_registry.register('base64', Base64CredentialStore,
1898
2175
                                   help=Base64CredentialStore.__doc__)
2003
2280
            return f
2004
2281
        except errors.NoSuchFile:
2005
2282
            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"))
 
2283
        except errors.PermissionDenied as e:
 
2284
            trace.warning("Permission denied while trying to open "
 
2285
                "configuration file %s.", urlutils.unescape_for_display(
 
2286
                urlutils.join(self._transport.base, self._filename), "utf-8"))
2013
2287
            return BytesIO()
2014
2288
 
2015
2289
    def _external_url(self):
2101
2375
                raise AssertionError(
2102
2376
                    'Only empty lists are supported as default values')
2103
2377
            self.default = u','
2104
 
        elif isinstance(default, (bytes, str, bool, int, float)):
 
2378
        elif isinstance(default, (binary_type, text_type, bool, int, float)):
2105
2379
            # Rely on python to convert strings, booleans and integers
2106
2380
            self.default = u'%s' % (default,)
2107
2381
        elif callable(default):
2147
2421
        for var in self.override_from_env:
2148
2422
            try:
2149
2423
                # If the env variable is defined, its value takes precedence
2150
 
                value = os.environ[var]
 
2424
                value = os.environ[var].decode(osutils.get_user_encoding())
2151
2425
                break
2152
2426
            except KeyError:
2153
2427
                continue
2159
2433
            try:
2160
2434
                # If the env variable is defined, its value is the default one
2161
2435
                value = os.environ[var]
 
2436
                if not PY3:
 
2437
                    value = value.decode(osutils.get_user_encoding())
2162
2438
                break
2163
2439
            except KeyError:
2164
2440
                continue
2166
2442
            # Otherwise, fallback to the value defined at registration
2167
2443
            if callable(self.default):
2168
2444
                value = self.default()
2169
 
                if not isinstance(value, str):
 
2445
                if not isinstance(value, text_type):
2170
2446
                    raise AssertionError(
2171
2447
                        "Callable default value for '%s' should be unicode"
2172
2448
                        % (self.name))
2198
2474
 
2199
2475
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2200
2476
 
2201
 
 
2202
2477
def int_SI_from_store(unicode_str):
2203
2478
    """Convert a human readable size in SI units, e.g 10MB into an integer.
2204
2479
 
2206
2481
    by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2207
2482
    pedantic.
2208
2483
 
2209
 
    :return Integer, expanded to its base-10 value if a proper SI unit is
 
2484
    :return Integer, expanded to its base-10 value if a proper SI unit is 
2210
2485
        found, None otherwise.
2211
2486
    """
2212
2487
    regexp = "^(\\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2220
2495
            try:
2221
2496
                coeff = _unit_suffixes[unit.upper()]
2222
2497
            except KeyError:
2223
 
                raise ValueError(
2224
 
                    gettext('{0} is not an SI unit.').format(unit))
 
2498
                raise ValueError(gettext('{0} is not an SI unit.').format(unit))
2225
2499
            val *= coeff
2226
2500
    return val
2227
2501
 
2251
2525
            invalid=invalid, unquote=False)
2252
2526
 
2253
2527
    def from_unicode(self, unicode_str):
2254
 
        if not isinstance(unicode_str, str):
 
2528
        if not isinstance(unicode_str, string_types):
2255
2529
            raise TypeError
2256
2530
        # Now inject our string directly as unicode. All callers got their
2257
2531
        # value from configobj, so values that need to be quoted are already
2259
2533
        _list_converter_config.reset()
2260
2534
        _list_converter_config._parse([u"list=%s" % (unicode_str,)])
2261
2535
        maybe_list = _list_converter_config['list']
2262
 
        if isinstance(maybe_list, str):
 
2536
        if isinstance(maybe_list, string_types):
2263
2537
            if maybe_list:
2264
2538
                # A single value, most probably the user forgot (or didn't care
2265
2539
                # to add) the final ','
2284
2558
        can take quoting into account.
2285
2559
        """
2286
2560
        super(RegistryOption, self).__init__(
2287
 
            name, default=lambda: registry.default_key,
 
2561
            name, default=lambda: unicode(registry.default_key),
2288
2562
            default_from_env=default_from_env,
2289
2563
            from_unicode=self.from_unicode, help=help,
2290
2564
            invalid=invalid, unquote=False)
2291
2565
        self.registry = registry
2292
2566
 
2293
2567
    def from_unicode(self, unicode_str):
2294
 
        if not isinstance(unicode_str, str):
 
2568
        if not isinstance(unicode_str, string_types):
2295
2569
            raise TypeError
2296
2570
        try:
2297
2571
            return self.registry.get(unicode_str)
2299
2573
            raise ValueError(
2300
2574
                "Invalid value %s for %s."
2301
2575
                "See help for a list of possible values." % (unicode_str,
2302
 
                                                             self.name))
 
2576
                    self.name))
2303
2577
 
2304
2578
    @property
2305
2579
    def help(self):
2318
2592
for '{bar{baz}}' we will get '{baz}'
2319
2593
"""
2320
2594
 
2321
 
 
2322
2595
def iter_option_refs(string):
2323
2596
    # Split isolate refs so every other chunk is a ref
2324
2597
    is_ref = False
2325
 
    for chunk in _option_ref_re.split(string):
 
2598
    for chunk  in _option_ref_re.split(string):
2326
2599
        yield is_ref, chunk
2327
2600
        is_ref = not is_ref
2328
2601
 
2359
2632
 
2360
2633
        :param module_name: the python path to the module. Such as 'os.path'.
2361
2634
 
2362
 
        :param member_name: the member of the module to return.  If empty or
 
2635
        :param member_name: the member of the module to return.  If empty or 
2363
2636
                None, get() will return the module itself.
2364
2637
        """
2365
2638
        self._check_option_name(key)
2391
2664
'''))
2392
2665
option_registry.register(
2393
2666
    ListOption('acceptable_keys',
2394
 
               default=None,
2395
 
               help="""\
 
2667
           default=None,
 
2668
           help="""\
2396
2669
List of GPG key patterns which are acceptable for verification.
2397
2670
"""))
2398
2671
option_registry.register(
2428
2701
See also: bound.
2429
2702
"""))
2430
2703
option_registry.register(
2431
 
    Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
 
2704
    Option('branch.fetch_tags', default=False,  from_unicode=bool_from_store,
2432
2705
           help="""\
2433
2706
Whether revisions associated with tags should be fetched.
2434
2707
"""))
2435
2708
option_registry.register_lazy(
2436
 
    'transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
 
2709
    'bzr.transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
2437
2710
option_registry.register(
2438
2711
    Option('bzr.workingtree.worth_saving_limit', default=10,
2439
 
           from_unicode=int_from_store, invalid='warning',
 
2712
           from_unicode=int_from_store,  invalid='warning',
2440
2713
           help='''\
2441
2714
How many changes before saving the dirstate.
2442
2715
 
2456
2729
bug tracker was specified.
2457
2730
'''))
2458
2731
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
2732
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2470
2733
           from_unicode=signature_policy_from_unicode,
2471
2734
           help='''\
2506
2769
'''))
2507
2770
option_registry.register(
2508
2771
    ListOption('debug_flags', default=[],
2509
 
               help='Debug flags to activate.'))
 
2772
           help='Debug flags to activate.'))
2510
2773
option_registry.register(
2511
2774
    Option('default_format', default='2a',
2512
2775
           help='Format used when creating branches.'))
2513
2776
option_registry.register(
 
2777
    Option('dpush_strict', default=None,
 
2778
           from_unicode=bool_from_store,
 
2779
           help='''\
 
2780
The default value for ``dpush --strict``.
 
2781
 
 
2782
If present, defines the ``--strict`` option default value for checking
 
2783
uncommitted changes before pushing into a different VCS without any
 
2784
custom bzr metadata.
 
2785
'''))
 
2786
option_registry.register(
2514
2787
    Option('editor',
2515
2788
           help='The command called to launch an editor to enter a message.'))
2516
2789
option_registry.register(
2517
 
    Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
2518
 
           default=bedding.default_email, help='The users identity'))
 
2790
    Option('email', override_from_env=['BRZ_EMAIL'], default=default_email,
 
2791
           help='The users identity'))
2519
2792
option_registry.register(
2520
2793
    Option('gpg_signing_key',
2521
2794
           default=None,
2528
2801
    Option('language',
2529
2802
           help='Language to translate messages into.'))
2530
2803
option_registry.register(
2531
 
    Option('locks.steal_dead', default=True, from_unicode=bool_from_store,
 
2804
    Option('locks.steal_dead', default=False, from_unicode=bool_from_store,
2532
2805
           help='''\
2533
2806
Steal locks that appears to be dead.
2534
2807
 
2541
2814
'''))
2542
2815
option_registry.register(
2543
2816
    Option('log_format', default='long',
2544
 
           help='''\
 
2817
           help= '''\
2545
2818
Log format to use when displaying revisions.
2546
2819
 
2547
2820
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2548
2821
may be provided by plugins.
2549
2822
'''))
2550
2823
option_registry.register_lazy('mail_client', 'breezy.mail_client',
2551
 
                              'opt_mail_client')
 
2824
    'opt_mail_client')
2552
2825
option_registry.register(
2553
2826
    Option('output_encoding',
2554
 
           help='Unicode encoding for output'
 
2827
           help= 'Unicode encoding for output'
2555
2828
           ' (terminal encoding if not specified).'))
2556
2829
option_registry.register(
2557
2830
    Option('parent_location',
2610
2883
lost if the machine crashes.  See also dirstate.fdatasync.
2611
2884
'''))
2612
2885
option_registry.register_lazy('smtp_server',
2613
 
                              'breezy.smtp_connection', 'smtp_server')
 
2886
    'breezy.smtp_connection', 'smtp_server')
2614
2887
option_registry.register_lazy('smtp_password',
2615
 
                              'breezy.smtp_connection', 'smtp_password')
 
2888
    'breezy.smtp_connection', 'smtp_password')
2616
2889
option_registry.register_lazy('smtp_username',
2617
 
                              'breezy.smtp_connection', 'smtp_username')
 
2890
    'breezy.smtp_connection', 'smtp_username')
2618
2891
option_registry.register(
2619
2892
    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
 
           ))
 
2893
        default='600',
 
2894
        from_unicode=int_from_store,
 
2895
        help='Abort selftest if one test takes longer than this many seconds',
 
2896
        ))
2624
2897
 
2625
2898
option_registry.register(
2626
2899
    Option('send_strict', default=None,
2638
2911
           help="If we wait for a new request from a client for more than"
2639
2912
                " X seconds, consider the client idle, and hangup."))
2640
2913
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
2914
    Option('stacked_on_location',
2646
2915
           default=None,
2647
2916
           help="""The location where this branch is stacked on."""))
2659
2928
           help='''Where submissions from this branch are mailed to.'''))
2660
2929
option_registry.register(
2661
2930
    ListOption('suppress_warnings',
2662
 
               default=[],
2663
 
               help="List of warning classes to suppress."))
 
2931
           default=[],
 
2932
           help="List of warning classes to suppress."))
2664
2933
option_registry.register(
2665
2934
    Option('validate_signatures_in_log', default=False,
2666
2935
           from_unicode=bool_from_store, invalid='warning',
2667
2936
           help='''Whether to validate signatures in brz log.'''))
2668
2937
option_registry.register_lazy('ssl.ca_certs',
2669
 
                              'breezy.transport.http', 'opt_ssl_ca_certs')
 
2938
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2670
2939
 
2671
2940
option_registry.register_lazy('ssl.cert_reqs',
2672
 
                              'breezy.transport.http', 'opt_ssl_cert_reqs')
 
2941
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2673
2942
 
2674
2943
 
2675
2944
class Section(object):
2758
3027
                # Someone changed the value since we get it from the persistent
2759
3028
                # storage.
2760
3029
                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)))
 
3030
                        "Option {0} in section {1} of {2} was changed"
 
3031
                        " from {3} to {4}. The {5} value will be saved.".format(
 
3032
                            k, self.id, store.external_url(), expected,
 
3033
                            reloaded, actual)))
2765
3034
        # No need to keep track of these changes
2766
3035
        self.reset_changes()
2767
3036
 
2902
3171
            try:
2903
3172
                name, value = over.split('=', 1)
2904
3173
            except ValueError:
2905
 
                raise errors.CommandError(
 
3174
                raise errors.BzrCommandError(
2906
3175
                    gettext("Invalid '%s', should be of the form 'name=value'")
2907
3176
                    % (over,))
2908
3177
            self.options[name] = value
2913
3182
        return 'cmdline'
2914
3183
 
2915
3184
    def get_sections(self):
2916
 
        yield self, self.readonly_section_class(None, self.options)
 
3185
        yield self,  self.readonly_section_class(None, self.options)
2917
3186
 
2918
3187
 
2919
3188
class IniFileStore(Store):
2930
3199
        self._config_obj = None
2931
3200
 
2932
3201
    def is_loaded(self):
2933
 
        return self._config_obj is not None
 
3202
        return self._config_obj != None
2934
3203
 
2935
3204
    def unload(self):
2936
3205
        self._config_obj = None
3050
3319
            self._config_obj.list_values = False
3051
3320
 
3052
3321
    def unquote(self, value):
3053
 
        if value and isinstance(value, str):
 
3322
        if value and isinstance(value, string_types):
3054
3323
            # _unquote doesn't handle None nor empty strings nor anything that
3055
3324
            # is not a string, really.
3056
3325
            value = self._config_obj._unquote(value)
3167
3436
    """
3168
3437
 
3169
3438
    def __init__(self, possible_transports=None):
3170
 
        path, kind = bedding._config_dir()
 
3439
        (path, kind) = _config_dir()
3171
3440
        t = transport.get_transport_from_path(
3172
3441
            path, possible_transports=possible_transports)
3173
 
        super(GlobalStore, self).__init__(t, kind + '.conf')
 
3442
        filename = {'bazaar': 'bazaar.conf', 'breezy': 'breezy.conf'}[kind]
 
3443
        super(GlobalStore, self).__init__(t, filename)
3174
3444
        self.id = 'breezy'
3175
3445
 
3176
3446
 
3182
3452
 
3183
3453
    def __init__(self, possible_transports=None):
3184
3454
        t = transport.get_transport_from_path(
3185
 
            bedding.config_dir(), possible_transports=possible_transports)
 
3455
            config_dir(), possible_transports=possible_transports)
3186
3456
        super(LocationStore, self).__init__(t, 'locations.conf')
3187
3457
        self.id = 'locations'
3188
3458
 
3204
3474
 
3205
3475
    def __init__(self, bzrdir):
3206
3476
        super(ControlStore, self).__init__(bzrdir.transport,
3207
 
                                           'control.conf',
 
3477
                                          'control.conf',
3208
3478
                                           lock_dir_name='branch_lock')
3209
3479
        self.id = 'control'
3210
3480
 
3321
3591
                # the location is already a local path or URL, convert the
3322
3592
                # section id to the same format
3323
3593
                section_path = urlutils.local_path_from_url(section_path)
3324
 
            if (self.location.startswith(section_path) or
3325
 
                    fnmatch.fnmatch(self.location, section_path)):
 
3594
            if (self.location.startswith(section_path)
 
3595
                or fnmatch.fnmatch(self.location, section_path)):
3326
3596
                section_parts = section_path.rstrip('/').split('/')
3327
3597
                extra_path = '/'.join(location_parts[len(section_parts):])
3328
3598
                yield store, LocationSection(section, extra_path)
3401
3671
_shared_stores = {}
3402
3672
_shared_stores_at_exit_installed = False
3403
3673
 
3404
 
 
3405
3674
class Stack(object):
3406
3675
    """A stack of configurations where an option can be defined"""
3407
3676
 
3453
3722
        """
3454
3723
        # FIXME: No caching of options nor sections yet -- vila 20110503
3455
3724
        value = None
3456
 
        found_store = None  # Where the option value has been found
 
3725
        found_store = None # Where the option value has been found
3457
3726
        # If the option is registered, it may provide additional info about
3458
3727
        # value handling
3459
3728
        try:
3467
3736
            # None or ends up being None during expansion or conversion.
3468
3737
            if val is not None:
3469
3738
                if expand:
3470
 
                    if isinstance(val, str):
 
3739
                    if isinstance(val, string_types):
3471
3740
                        val = self._expand_options_in_string(val)
3472
3741
                    else:
3473
3742
                        trace.warning('Cannot expand "%s":'
3619
3888
        if state is None:
3620
3889
            global _shared_stores_at_exit_installed
3621
3890
            stores = _shared_stores
3622
 
 
3623
3891
            def save_config_changes():
3624
3892
                for k, store in stores.items():
3625
3893
                    store.save_changes()
3874
4142
        # http://pad.lv/788991 -- vila 20101115
3875
4143
        commands.Option('scope', help='Reduce the scope to the specified'
3876
4144
                        ' configuration file.',
3877
 
                        type=str),
 
4145
                        type=text_type),
3878
4146
        commands.Option('all',
3879
 
                        help='Display all the defined values for the matching options.',
3880
 
                        ),
 
4147
            help='Display all the defined values for the matching options.',
 
4148
            ),
3881
4149
        commands.Option('remove', help='Remove the option from'
3882
4150
                        ' the configuration file.'),
3883
4151
        ]
4003
4271
 
4004
4272
    def _remove_config_option(self, name, directory, scope):
4005
4273
        if name is None:
4006
 
            raise errors.CommandError(
 
4274
            raise errors.BzrCommandError(
4007
4275
                '--remove expects an option to remove.')
4008
4276
        conf = self._get_stack(directory, scope, write_access=True)
4009
4277
        try: