/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: 2020-05-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

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 check_signatures
57
 
                   turns on create_signatures.
 
56
                   present.  Currently it is unused except that
 
57
                   check_signatures 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
78
77
import os
79
78
import sys
80
79
 
81
80
import configobj
 
81
from io import BytesIO
82
82
 
83
83
import breezy
84
84
from .lazy_import import lazy_import
91
91
 
92
92
from breezy import (
93
93
    atomicfile,
 
94
    cmdline,
94
95
    controldir,
95
96
    debug,
96
97
    directory_service,
97
 
    lazy_regex,
98
 
    library_state,
99
98
    lock,
100
99
    lockdir,
101
100
    mergetools,
110
109
""")
111
110
from . import (
112
111
    commands,
 
112
    bedding,
113
113
    errors,
114
114
    hooks,
115
115
    lazy_regex,
116
116
    registry,
117
117
    )
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
 
118
 
 
119
 
 
120
CHECK_IF_POSSIBLE = 0
 
121
CHECK_ALWAYS = 1
 
122
CHECK_NEVER = 2
 
123
 
 
124
 
 
125
SIGN_WHEN_REQUIRED = 0
 
126
SIGN_ALWAYS = 1
 
127
SIGN_NEVER = 2
135
128
 
136
129
 
137
130
POLICY_NONE = 0
234
227
        errors.BzrError.__init__(self, option_name=option_name)
235
228
 
236
229
 
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
 
 
244
230
def signature_policy_from_unicode(signature_string):
245
231
    """Convert a string to a signing policy."""
246
232
    if signature_string.lower() == 'check-available':
265
251
                     % signature_string)
266
252
 
267
253
 
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
 
 
281
254
def _has_triplequote_bug():
282
255
    """True if triple quote logic is reversed, see lp:710410."""
283
256
    conf = configobj.ConfigObj()
295
268
                                        interpolation=False,
296
269
                                        **kwargs)
297
270
 
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
 
 
304
271
    if _has_triplequote_bug():
305
272
        def _get_triple_quote(self, value):
306
273
            quot = super(ConfigObj, self)._get_triple_quote(value)
336
303
        cmd = self._get_change_editor()
337
304
        if cmd is None:
338
305
            return None
 
306
        cmd = cmd.replace('@old_path', '{old_path}')
 
307
        cmd = cmd.replace('@new_path', '{new_path}')
 
308
        cmd = cmdline.split(cmd)
 
309
        if '{old_path}' not in cmd:
 
310
            cmd.extend(['{old_path}', '{new_path}'])
339
311
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
340
312
                                             sys.stdout)
341
313
 
522
494
            otherwise.
523
495
        """
524
496
        l = self.get_user_option(option_name, expand=expand)
525
 
        if isinstance(l, string_types):
 
497
        if isinstance(l, str):
526
498
            # A single value, most probably the user forgot (or didn't care to
527
499
            # add) the final ','
528
500
            l = [l]
558
530
 
559
531
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
560
532
 
561
 
        $BRZ_EMAIL can be set to override this, then
 
533
        $BRZ_EMAIL or $BZR_EMAIL can be set to override this, then
562
534
        the concrete policy type is checked, and finally
563
535
        $EMAIL is examined.
564
536
        If no username can be found, NoWhoami exception is raised.
565
537
        """
566
 
        v = os.environ.get('BRZ_EMAIL')
 
538
        v = os.environ.get('BRZ_EMAIL') or os.environ.get('BZR_EMAIL')
567
539
        if v:
568
 
            if not PY3:
569
 
                v = v.decode(osutils.get_user_encoding())
570
540
            return v
571
541
        v = self._get_user_id()
572
542
        if v:
573
543
            return v
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
        return bedding.default_email()
582
545
 
583
546
    def get_alias(self, value):
584
547
        return self._get_alias(value)
629
592
        # This should be done through the proposed config defaults mechanism
630
593
        # when it becomes available in the future.
631
594
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
632
 
                                             expand=False)
633
 
                        or mergetools.known_merge_tools.get(name, None))
 
595
                                             expand=False) or
 
596
                        mergetools.known_merge_tools.get(name, None))
634
597
        return command_line
635
598
 
636
599
 
666
629
                      'Invoked when a config option is removed.'
667
630
                      ' The signature is (stack, name).',
668
631
                      (2, 4))
 
632
 
 
633
 
669
634
ConfigHooks = _ConfigHooks()
670
635
 
671
636
 
679
644
        These are all empty initially, because by default nothing should get
680
645
        notified.
681
646
        """
682
 
        super(_OldConfigHooks, self).__init__('breezy.config', 'OldConfigHooks')
 
647
        super(_OldConfigHooks, self).__init__(
 
648
            'breezy.config', 'OldConfigHooks')
683
649
        self.add_hook('load',
684
650
                      'Invoked when a config store is loaded.'
685
651
                      ' The signature is (config).',
701
667
                      'Invoked when a config option is removed.'
702
668
                      ' The signature is (config, name).',
703
669
                      (2, 4))
 
670
 
 
671
 
704
672
OldConfigHooks = _OldConfigHooks()
705
673
 
706
674
 
722
690
    def from_string(cls, str_or_unicode, file_name=None, save=False):
723
691
        """Create a config object from a string.
724
692
 
725
 
        :param str_or_unicode: A string representing the file content. This will
726
 
            be utf-8 encoded.
 
693
        :param str_or_unicode: A string representing the file content. This
 
694
            will be utf-8 encoded.
727
695
 
728
696
        :param file_name: The configuration file path.
729
697
 
734
702
        return conf
735
703
 
736
704
    def _create_from_string(self, str_or_unicode, save):
737
 
        self._content = BytesIO(str_or_unicode.encode('utf-8'))
 
705
        if isinstance(str_or_unicode, str):
 
706
            str_or_unicode = str_or_unicode.encode('utf-8')
 
707
        self._content = BytesIO(str_or_unicode)
738
708
        # Some tests use in-memory configs, some other always need the config
739
709
        # file to exist on disk.
740
710
        if save:
816
786
            which sections should be searched. This is a list of (name,
817
787
            configobj) tuples.
818
788
        """
819
 
        opts = []
820
789
        if sections is None:
821
790
            parser = self._get_parser()
822
791
            sections = []
840
809
        return POLICY_NONE
841
810
 
842
811
    def _get_change_editor(self):
843
 
        return self.get_user_option('change_editor')
 
812
        return self.get_user_option('change_editor', expand=False)
844
813
 
845
814
    def _get_signature_checking(self):
846
815
        """See Config._get_signature_checking."""
935
904
        if self.file_name is None:
936
905
            raise AssertionError('We cannot save, self.file_name is None')
937
906
        conf_dir = os.path.dirname(self.file_name)
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()
 
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)
943
910
        osutils.copy_ownership_from_path(self.file_name)
944
911
        for hook in OldConfigHooks['save']:
945
912
            hook(self)
951
918
    If several processes try to write the config file, the accesses need to be
952
919
    serialized.
953
920
 
954
 
    Daughter classes should use the self.lock_write() decorator method when they 
955
 
    upate a config (they call, directly or indirectly, the
 
921
    Daughter classes should use the self.lock_write() decorator method when
 
922
    they upate a config (they call, directly or indirectly, the
956
923
    ``_write_config_file()`` method. These methods (typically ``set_option()``
957
924
    and variants must reload the config file from disk before calling
958
925
    ``_write_config_file()``), this can be achieved by calling the
997
964
 
998
965
        If the directory doesn't exist it is created.
999
966
        """
1000
 
        ensure_config_dir_exists(self.dir)
 
967
        bedding.ensure_config_dir_exists(self.dir)
1001
968
        token = self._lock.lock_write(token)
1002
969
        return lock.LogicalLockResult(self.unlock, token)
1003
970
 
1010
977
    def remove_user_option(self, option_name, section_name=None):
1011
978
        with self.lock_write():
1012
979
            super(LockableConfig, self).remove_user_option(
1013
 
                    option_name, section_name)
 
980
                option_name, section_name)
1014
981
 
1015
982
    def _write_config_file(self):
1016
983
        if self._lock is None or not self._lock.is_held:
1024
991
    """The configuration that should be used for a specific location."""
1025
992
 
1026
993
    def __init__(self):
1027
 
        super(GlobalConfig, self).__init__(file_name=config_filename())
 
994
        super(GlobalConfig, self).__init__(file_name=bedding.config_path())
1028
995
 
1029
996
    def config_id(self):
1030
997
        return 'breezy'
1097
1064
            # We need to avoid the LockableConfig implementation or we'll lock
1098
1065
            # twice
1099
1066
            super(LockableConfig, self).remove_user_option(
1100
 
                    option_name, section_name)
 
1067
                option_name, section_name)
1101
1068
 
1102
1069
 
1103
1070
def _iter_for_location_by_parts(sections, location):
1156
1123
 
1157
1124
    def __init__(self, location):
1158
1125
        super(LocationConfig, self).__init__(
1159
 
            file_name=locations_config_filename())
 
1126
            file_name=bedding.locations_config_path())
1160
1127
        # local file locations are looked up by local path, rather than
1161
1128
        # by file url. This is because the config file is a user
1162
1129
        # file, and we would rather not expose the user to file urls.
1352
1319
                yield section
1353
1320
 
1354
1321
    def _get_options(self, sections=None):
1355
 
        opts = []
1356
1322
        # First the locations options
1357
1323
        for option in self._get_location_config()._get_options():
1358
1324
            yield option
1372
1338
            yield option
1373
1339
 
1374
1340
    def set_user_option(self, name, value, store=STORE_BRANCH,
1375
 
        warn_masked=False):
 
1341
                        warn_masked=False):
1376
1342
        if store == STORE_BRANCH:
1377
1343
            self._get_branch_data_config().set_option(value, name)
1378
1344
        elif store == STORE_GLOBAL:
1429
1395
        return self._get_best_value('_acceptable_keys')
1430
1396
 
1431
1397
 
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
 
 
1675
1398
def parse_username(username):
1676
1399
    """Parse e-mail username and return a (name, address) tuple."""
1677
1400
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1678
1401
    if match is None:
1679
1402
        return (username, '')
1680
 
    else:
1681
 
        return (match.group(1), match.group(2))
 
1403
    return (match.group(1), match.group(2))
1682
1404
 
1683
1405
 
1684
1406
def extract_email_address(e):
1700
1422
class TreeConfig(IniBasedConfig):
1701
1423
    """Branch configuration data associated with its contents, not location"""
1702
1424
 
1703
 
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
 
1425
    # XXX: Really needs a better name, as this is not part of the tree!
 
1426
    # -- mbp 20080507
1704
1427
 
1705
1428
    def __init__(self, branch):
1706
1429
        self._config = branch._get_config()
1740
1463
    """
1741
1464
 
1742
1465
    def __init__(self, _file=None):
1743
 
        self._config = None # The ConfigObj
 
1466
        self._config = None  # The ConfigObj
1744
1467
        if _file is None:
1745
 
            self._filename = authentication_config_filename()
1746
 
            self._input = self._filename = authentication_config_filename()
 
1468
            self._input = self._filename = bedding.authentication_config_path()
1747
1469
            self._check_permissions()
1748
1470
        else:
1749
1471
            # Tests can provide a string as _file
1776
1498
                trace.mutter('Unable to stat %r: %r', self._filename, e)
1777
1499
            return
1778
1500
        mode = stat.S_IMODE(st.st_mode)
1779
 
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP |
1780
 
             stat.S_IWGRP | stat.S_IRGRP ) & mode):
 
1501
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP
 
1502
             | stat.S_IWGRP | stat.S_IRGRP) & mode):
1781
1503
            # Only warn once
1782
 
            if (not self._filename in _authentication_config_permission_errors
1783
 
                and not GlobalConfig().suppress_warning(
 
1504
            if (self._filename not in _authentication_config_permission_errors and
 
1505
                not GlobalConfig().suppress_warning(
1784
1506
                    'insecure_permissions')):
1785
1507
                trace.warning("The file '%s' has insecure "
1786
 
                        "file permissions. Saved passwords may be accessible "
1787
 
                        "by other users.", self._filename)
 
1508
                              "file permissions. Saved passwords may be accessible "
 
1509
                              "by other users.", self._filename)
1788
1510
                _authentication_config_permission_errors.add(self._filename)
1789
1511
 
1790
1512
    def _save(self):
1791
1513
        """Save the config file, only tests should use it for now."""
1792
1514
        conf_dir = os.path.dirname(self._filename)
1793
 
        ensure_config_dir_exists(conf_dir)
1794
 
        fd = os.open(self._filename, os.O_RDWR|os.O_CREAT, 0o600)
 
1515
        bedding.ensure_config_dir_exists(conf_dir)
 
1516
        fd = os.open(self._filename, os.O_RDWR | os.O_CREAT, 0o600)
1795
1517
        try:
1796
1518
            f = os.fdopen(fd, 'wb')
1797
1519
            self._get_config().write(f)
1842
1564
        credentials = None
1843
1565
        for auth_def_name, auth_def in self._get_config().iteritems():
1844
1566
            if not isinstance(auth_def, configobj.Section):
1845
 
                raise ValueError("%s defined outside a section" % auth_def_name)
 
1567
                raise ValueError("%s defined outside a section" %
 
1568
                                 auth_def_name)
1846
1569
 
1847
1570
            a_scheme, a_host, a_user, a_path = map(
1848
1571
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1865
1588
            if a_scheme is not None and scheme != a_scheme:
1866
1589
                continue
1867
1590
            if a_host is not None:
1868
 
                if not (host == a_host
1869
 
                        or (a_host.startswith('.') and host.endswith(a_host))):
 
1591
                if not (host == a_host or
 
1592
                        (a_host.startswith('.') and host.endswith(a_host))):
1870
1593
                    continue
1871
1594
            if a_port is not None and port != a_port:
1872
1595
                continue
1873
 
            if (a_path is not None and path is not None
1874
 
                and not path.startswith(a_path)):
 
1596
            if (a_path is not None and path is not None and
 
1597
                    not path.startswith(a_path)):
1875
1598
                continue
1876
 
            if (a_user is not None and user is not None
1877
 
                and a_user != user):
 
1599
            if (a_user is not None and user is not None and
 
1600
                    a_user != user):
1878
1601
                # Never contradict the caller about the user to be used
1879
1602
                continue
1880
1603
            if a_user is None:
1941
1664
        if realm is not None:
1942
1665
            values['realm'] = realm
1943
1666
        config = self._get_config()
1944
 
        for_deletion = []
1945
1667
        for section, existing_values in config.iteritems():
1946
1668
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1947
1669
                if existing_values.get(key) != values.get(key):
1965
1687
 
1966
1688
        :param path: the absolute path on the server (optional)
1967
1689
 
1968
 
        :param ask: Ask the user if there is no explicitly configured username 
 
1690
        :param ask: Ask the user if there is no explicitly configured username
1969
1691
                    (optional)
1970
1692
 
1971
1693
        :param default: The username returned if none is defined (optional).
2015
1737
                                           realm)
2016
1738
        if credentials is not None:
2017
1739
            password = credentials['password']
2018
 
            if password is not None and scheme is 'ssh':
 
1740
            if password is not None and scheme == 'ssh':
2019
1741
                trace.warning('password ignored in section [%s],'
2020
1742
                              ' use an ssh agent instead'
2021
1743
                              % credentials['name'])
2026
1748
        if password is None:
2027
1749
            if prompt is None:
2028
1750
                # Create a default prompt suitable for most cases
2029
 
                prompt = u'%s' % scheme.upper() + u' %(user)s@%(host)s password'
 
1751
                prompt = (u'%s' %
 
1752
                          scheme.upper() + u' %(user)s@%(host)s password')
2030
1753
            # Special handling for optional fields in the prompt
2031
1754
            if port is not None:
2032
1755
                prompt_host = '%s:%d' % (host, port)
2101
1824
        :param override_existing: Raise KeyErorr if False and something has
2102
1825
                already been registered for that key. If True, ignore if there
2103
1826
                is an existing key (always register the new value).
2104
 
        :param fallback: Whether this credential store should be 
 
1827
        :param fallback: Whether this credential store should be
2105
1828
                used as fallback.
2106
1829
        """
2107
1830
        return super(CredentialStoreRegistry,
2121
1844
        :param override_existing: If True, replace the existing object
2122
1845
                with the new one. If False, if there is already something
2123
1846
                registered with the same key, raise a KeyError
2124
 
        :param fallback: Whether this credential store should be 
 
1847
        :param fallback: Whether this credential store should be
2125
1848
                used as fallback.
2126
1849
        """
2127
1850
        return super(CredentialStoreRegistry, self).register_lazy(
2148
1871
        raise NotImplementedError(self.get_credentials)
2149
1872
 
2150
1873
 
2151
 
 
2152
1874
class PlainTextCredentialStore(CredentialStore):
2153
1875
    __doc__ = """Plain text credential store for the authentication.conf file"""
2154
1876
 
2169
1891
        """See CredentialStore.decode_password."""
2170
1892
        # GZ 2012-07-28: Will raise binascii.Error if password is not base64,
2171
1893
        #                should probably propogate as something more useful.
2172
 
        return base64.decodestring(credentials['password'])
 
1894
        return base64.standard_b64decode(credentials['password'])
 
1895
 
2173
1896
 
2174
1897
credential_store_registry.register('base64', Base64CredentialStore,
2175
1898
                                   help=Base64CredentialStore.__doc__)
2280
2003
            return f
2281
2004
        except errors.NoSuchFile:
2282
2005
            return BytesIO()
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"))
 
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"))
2287
2013
            return BytesIO()
2288
2014
 
2289
2015
    def _external_url(self):
2375
2101
                raise AssertionError(
2376
2102
                    'Only empty lists are supported as default values')
2377
2103
            self.default = u','
2378
 
        elif isinstance(default, (binary_type, text_type, bool, int, float)):
 
2104
        elif isinstance(default, (bytes, str, bool, int, float)):
2379
2105
            # Rely on python to convert strings, booleans and integers
2380
2106
            self.default = u'%s' % (default,)
2381
2107
        elif callable(default):
2421
2147
        for var in self.override_from_env:
2422
2148
            try:
2423
2149
                # If the env variable is defined, its value takes precedence
2424
 
                value = os.environ[var].decode(osutils.get_user_encoding())
 
2150
                value = os.environ[var]
2425
2151
                break
2426
2152
            except KeyError:
2427
2153
                continue
2433
2159
            try:
2434
2160
                # If the env variable is defined, its value is the default one
2435
2161
                value = os.environ[var]
2436
 
                if not PY3:
2437
 
                    value = value.decode(osutils.get_user_encoding())
2438
2162
                break
2439
2163
            except KeyError:
2440
2164
                continue
2442
2166
            # Otherwise, fallback to the value defined at registration
2443
2167
            if callable(self.default):
2444
2168
                value = self.default()
2445
 
                if not isinstance(value, text_type):
 
2169
                if not isinstance(value, str):
2446
2170
                    raise AssertionError(
2447
2171
                        "Callable default value for '%s' should be unicode"
2448
2172
                        % (self.name))
2474
2198
 
2475
2199
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2476
2200
 
 
2201
 
2477
2202
def int_SI_from_store(unicode_str):
2478
2203
    """Convert a human readable size in SI units, e.g 10MB into an integer.
2479
2204
 
2481
2206
    by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2482
2207
    pedantic.
2483
2208
 
2484
 
    :return Integer, expanded to its base-10 value if a proper SI unit is 
 
2209
    :return Integer, expanded to its base-10 value if a proper SI unit is
2485
2210
        found, None otherwise.
2486
2211
    """
2487
2212
    regexp = "^(\\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2495
2220
            try:
2496
2221
                coeff = _unit_suffixes[unit.upper()]
2497
2222
            except KeyError:
2498
 
                raise ValueError(gettext('{0} is not an SI unit.').format(unit))
 
2223
                raise ValueError(
 
2224
                    gettext('{0} is not an SI unit.').format(unit))
2499
2225
            val *= coeff
2500
2226
    return val
2501
2227
 
2525
2251
            invalid=invalid, unquote=False)
2526
2252
 
2527
2253
    def from_unicode(self, unicode_str):
2528
 
        if not isinstance(unicode_str, string_types):
 
2254
        if not isinstance(unicode_str, str):
2529
2255
            raise TypeError
2530
2256
        # Now inject our string directly as unicode. All callers got their
2531
2257
        # value from configobj, so values that need to be quoted are already
2533
2259
        _list_converter_config.reset()
2534
2260
        _list_converter_config._parse([u"list=%s" % (unicode_str,)])
2535
2261
        maybe_list = _list_converter_config['list']
2536
 
        if isinstance(maybe_list, string_types):
 
2262
        if isinstance(maybe_list, str):
2537
2263
            if maybe_list:
2538
2264
                # A single value, most probably the user forgot (or didn't care
2539
2265
                # to add) the final ','
2558
2284
        can take quoting into account.
2559
2285
        """
2560
2286
        super(RegistryOption, self).__init__(
2561
 
            name, default=lambda: unicode(registry.default_key),
 
2287
            name, default=lambda: registry.default_key,
2562
2288
            default_from_env=default_from_env,
2563
2289
            from_unicode=self.from_unicode, help=help,
2564
2290
            invalid=invalid, unquote=False)
2565
2291
        self.registry = registry
2566
2292
 
2567
2293
    def from_unicode(self, unicode_str):
2568
 
        if not isinstance(unicode_str, string_types):
 
2294
        if not isinstance(unicode_str, str):
2569
2295
            raise TypeError
2570
2296
        try:
2571
2297
            return self.registry.get(unicode_str)
2573
2299
            raise ValueError(
2574
2300
                "Invalid value %s for %s."
2575
2301
                "See help for a list of possible values." % (unicode_str,
2576
 
                    self.name))
 
2302
                                                             self.name))
2577
2303
 
2578
2304
    @property
2579
2305
    def help(self):
2592
2318
for '{bar{baz}}' we will get '{baz}'
2593
2319
"""
2594
2320
 
 
2321
 
2595
2322
def iter_option_refs(string):
2596
2323
    # Split isolate refs so every other chunk is a ref
2597
2324
    is_ref = False
2598
 
    for chunk  in _option_ref_re.split(string):
 
2325
    for chunk in _option_ref_re.split(string):
2599
2326
        yield is_ref, chunk
2600
2327
        is_ref = not is_ref
2601
2328
 
2632
2359
 
2633
2360
        :param module_name: the python path to the module. Such as 'os.path'.
2634
2361
 
2635
 
        :param member_name: the member of the module to return.  If empty or 
 
2362
        :param member_name: the member of the module to return.  If empty or
2636
2363
                None, get() will return the module itself.
2637
2364
        """
2638
2365
        self._check_option_name(key)
2664
2391
'''))
2665
2392
option_registry.register(
2666
2393
    ListOption('acceptable_keys',
2667
 
           default=None,
2668
 
           help="""\
 
2394
               default=None,
 
2395
               help="""\
2669
2396
List of GPG key patterns which are acceptable for verification.
2670
2397
"""))
2671
2398
option_registry.register(
2701
2428
See also: bound.
2702
2429
"""))
2703
2430
option_registry.register(
2704
 
    Option('branch.fetch_tags', default=False,  from_unicode=bool_from_store,
 
2431
    Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
2705
2432
           help="""\
2706
2433
Whether revisions associated with tags should be fetched.
2707
2434
"""))
2708
2435
option_registry.register_lazy(
2709
 
    'bzr.transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
 
2436
    'transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
2710
2437
option_registry.register(
2711
2438
    Option('bzr.workingtree.worth_saving_limit', default=10,
2712
 
           from_unicode=int_from_store,  invalid='warning',
 
2439
           from_unicode=int_from_store, invalid='warning',
2713
2440
           help='''\
2714
2441
How many changes before saving the dirstate.
2715
2442
 
2729
2456
bug tracker was specified.
2730
2457
'''))
2731
2458
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(
2732
2469
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2733
2470
           from_unicode=signature_policy_from_unicode,
2734
2471
           help='''\
2769
2506
'''))
2770
2507
option_registry.register(
2771
2508
    ListOption('debug_flags', default=[],
2772
 
           help='Debug flags to activate.'))
 
2509
               help='Debug flags to activate.'))
2773
2510
option_registry.register(
2774
2511
    Option('default_format', default='2a',
2775
2512
           help='Format used when creating branches.'))
2776
2513
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(
2787
2514
    Option('editor',
2788
2515
           help='The command called to launch an editor to enter a message.'))
2789
2516
option_registry.register(
2790
 
    Option('email', override_from_env=['BRZ_EMAIL'], default=default_email,
2791
 
           help='The users identity'))
 
2517
    Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
 
2518
           default=bedding.default_email, help='The users identity'))
2792
2519
option_registry.register(
2793
2520
    Option('gpg_signing_key',
2794
2521
           default=None,
2801
2528
    Option('language',
2802
2529
           help='Language to translate messages into.'))
2803
2530
option_registry.register(
2804
 
    Option('locks.steal_dead', default=False, from_unicode=bool_from_store,
 
2531
    Option('locks.steal_dead', default=True, from_unicode=bool_from_store,
2805
2532
           help='''\
2806
2533
Steal locks that appears to be dead.
2807
2534
 
2814
2541
'''))
2815
2542
option_registry.register(
2816
2543
    Option('log_format', default='long',
2817
 
           help= '''\
 
2544
           help='''\
2818
2545
Log format to use when displaying revisions.
2819
2546
 
2820
2547
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2821
2548
may be provided by plugins.
2822
2549
'''))
2823
2550
option_registry.register_lazy('mail_client', 'breezy.mail_client',
2824
 
    'opt_mail_client')
 
2551
                              'opt_mail_client')
2825
2552
option_registry.register(
2826
2553
    Option('output_encoding',
2827
 
           help= 'Unicode encoding for output'
 
2554
           help='Unicode encoding for output'
2828
2555
           ' (terminal encoding if not specified).'))
2829
2556
option_registry.register(
2830
2557
    Option('parent_location',
2883
2610
lost if the machine crashes.  See also dirstate.fdatasync.
2884
2611
'''))
2885
2612
option_registry.register_lazy('smtp_server',
2886
 
    'breezy.smtp_connection', 'smtp_server')
 
2613
                              'breezy.smtp_connection', 'smtp_server')
2887
2614
option_registry.register_lazy('smtp_password',
2888
 
    'breezy.smtp_connection', 'smtp_password')
 
2615
                              'breezy.smtp_connection', 'smtp_password')
2889
2616
option_registry.register_lazy('smtp_username',
2890
 
    'breezy.smtp_connection', 'smtp_username')
 
2617
                              'breezy.smtp_connection', 'smtp_username')
2891
2618
option_registry.register(
2892
2619
    Option('selftest.timeout',
2893
 
        default='600',
2894
 
        from_unicode=int_from_store,
2895
 
        help='Abort selftest if one test takes longer than this many seconds',
2896
 
        ))
 
2620
           default='600',
 
2621
           from_unicode=int_from_store,
 
2622
           help='Abort selftest if one test takes longer than this many seconds',
 
2623
           ))
2897
2624
 
2898
2625
option_registry.register(
2899
2626
    Option('send_strict', default=None,
2911
2638
           help="If we wait for a new request from a client for more than"
2912
2639
                " X seconds, consider the client idle, and hangup."))
2913
2640
option_registry.register(
 
2641
    Option('ssh',
 
2642
           default=None, override_from_env=['BRZ_SSH'],
 
2643
           help='SSH vendor to use.'))
 
2644
option_registry.register(
2914
2645
    Option('stacked_on_location',
2915
2646
           default=None,
2916
2647
           help="""The location where this branch is stacked on."""))
2928
2659
           help='''Where submissions from this branch are mailed to.'''))
2929
2660
option_registry.register(
2930
2661
    ListOption('suppress_warnings',
2931
 
           default=[],
2932
 
           help="List of warning classes to suppress."))
 
2662
               default=[],
 
2663
               help="List of warning classes to suppress."))
2933
2664
option_registry.register(
2934
2665
    Option('validate_signatures_in_log', default=False,
2935
2666
           from_unicode=bool_from_store, invalid='warning',
2936
2667
           help='''Whether to validate signatures in brz log.'''))
2937
2668
option_registry.register_lazy('ssl.ca_certs',
2938
 
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
 
2669
                              'breezy.transport.http', 'opt_ssl_ca_certs')
2939
2670
 
2940
2671
option_registry.register_lazy('ssl.cert_reqs',
2941
 
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
 
2672
                              'breezy.transport.http', 'opt_ssl_cert_reqs')
2942
2673
 
2943
2674
 
2944
2675
class Section(object):
3027
2758
                # Someone changed the value since we get it from the persistent
3028
2759
                # storage.
3029
2760
                trace.warning(gettext(
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)))
 
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)))
3034
2765
        # No need to keep track of these changes
3035
2766
        self.reset_changes()
3036
2767
 
3182
2913
        return 'cmdline'
3183
2914
 
3184
2915
    def get_sections(self):
3185
 
        yield self,  self.readonly_section_class(None, self.options)
 
2916
        yield self, self.readonly_section_class(None, self.options)
3186
2917
 
3187
2918
 
3188
2919
class IniFileStore(Store):
3199
2930
        self._config_obj = None
3200
2931
 
3201
2932
    def is_loaded(self):
3202
 
        return self._config_obj != None
 
2933
        return self._config_obj is not None
3203
2934
 
3204
2935
    def unload(self):
3205
2936
        self._config_obj = None
3319
3050
            self._config_obj.list_values = False
3320
3051
 
3321
3052
    def unquote(self, value):
3322
 
        if value and isinstance(value, string_types):
 
3053
        if value and isinstance(value, str):
3323
3054
            # _unquote doesn't handle None nor empty strings nor anything that
3324
3055
            # is not a string, really.
3325
3056
            value = self._config_obj._unquote(value)
3436
3167
    """
3437
3168
 
3438
3169
    def __init__(self, possible_transports=None):
3439
 
        (path, kind) = _config_dir()
 
3170
        path, kind = bedding._config_dir()
3440
3171
        t = transport.get_transport_from_path(
3441
3172
            path, possible_transports=possible_transports)
3442
 
        filename = {'bazaar': 'bazaar.conf', 'breezy': 'breezy.conf'}[kind]
3443
 
        super(GlobalStore, self).__init__(t, filename)
 
3173
        super(GlobalStore, self).__init__(t, kind + '.conf')
3444
3174
        self.id = 'breezy'
3445
3175
 
3446
3176
 
3452
3182
 
3453
3183
    def __init__(self, possible_transports=None):
3454
3184
        t = transport.get_transport_from_path(
3455
 
            config_dir(), possible_transports=possible_transports)
 
3185
            bedding.config_dir(), possible_transports=possible_transports)
3456
3186
        super(LocationStore, self).__init__(t, 'locations.conf')
3457
3187
        self.id = 'locations'
3458
3188
 
3474
3204
 
3475
3205
    def __init__(self, bzrdir):
3476
3206
        super(ControlStore, self).__init__(bzrdir.transport,
3477
 
                                          'control.conf',
 
3207
                                           'control.conf',
3478
3208
                                           lock_dir_name='branch_lock')
3479
3209
        self.id = 'control'
3480
3210
 
3591
3321
                # the location is already a local path or URL, convert the
3592
3322
                # section id to the same format
3593
3323
                section_path = urlutils.local_path_from_url(section_path)
3594
 
            if (self.location.startswith(section_path)
3595
 
                or fnmatch.fnmatch(self.location, section_path)):
 
3324
            if (self.location.startswith(section_path) or
 
3325
                    fnmatch.fnmatch(self.location, section_path)):
3596
3326
                section_parts = section_path.rstrip('/').split('/')
3597
3327
                extra_path = '/'.join(location_parts[len(section_parts):])
3598
3328
                yield store, LocationSection(section, extra_path)
3671
3401
_shared_stores = {}
3672
3402
_shared_stores_at_exit_installed = False
3673
3403
 
 
3404
 
3674
3405
class Stack(object):
3675
3406
    """A stack of configurations where an option can be defined"""
3676
3407
 
3722
3453
        """
3723
3454
        # FIXME: No caching of options nor sections yet -- vila 20110503
3724
3455
        value = None
3725
 
        found_store = None # Where the option value has been found
 
3456
        found_store = None  # Where the option value has been found
3726
3457
        # If the option is registered, it may provide additional info about
3727
3458
        # value handling
3728
3459
        try:
3736
3467
            # None or ends up being None during expansion or conversion.
3737
3468
            if val is not None:
3738
3469
                if expand:
3739
 
                    if isinstance(val, string_types):
 
3470
                    if isinstance(val, str):
3740
3471
                        val = self._expand_options_in_string(val)
3741
3472
                    else:
3742
3473
                        trace.warning('Cannot expand "%s":'
3888
3619
        if state is None:
3889
3620
            global _shared_stores_at_exit_installed
3890
3621
            stores = _shared_stores
 
3622
 
3891
3623
            def save_config_changes():
3892
3624
                for k, store in stores.items():
3893
3625
                    store.save_changes()
4142
3874
        # http://pad.lv/788991 -- vila 20101115
4143
3875
        commands.Option('scope', help='Reduce the scope to the specified'
4144
3876
                        ' configuration file.',
4145
 
                        type=text_type),
 
3877
                        type=str),
4146
3878
        commands.Option('all',
4147
 
            help='Display all the defined values for the matching options.',
4148
 
            ),
 
3879
                        help='Display all the defined values for the matching options.',
 
3880
                        ),
4149
3881
        commands.Option('remove', help='Remove the option from'
4150
3882
                        ' the configuration file.'),
4151
3883
        ]