/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-11-16 23:19:12 UTC
  • mfrom: (7180 work)
  • mto: This revision was merged to the branch mainline in revision 7294.
  • Revision ID: jelmer@jelmer.uk-20181116231912-e043vpq22bdkxa6q
Merge trunk.

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
94
94
    controldir,
95
95
    debug,
96
96
    directory_service,
97
 
    lazy_regex,
98
97
    lock,
99
98
    lockdir,
100
99
    mergetools,
123
122
    )
124
123
 
125
124
 
126
 
CHECK_IF_POSSIBLE=0
127
 
CHECK_ALWAYS=1
128
 
CHECK_NEVER=2
129
 
 
130
 
 
131
 
SIGN_WHEN_REQUIRED=0
132
 
SIGN_ALWAYS=1
133
 
SIGN_NEVER=2
 
125
CHECK_IF_POSSIBLE = 0
 
126
CHECK_ALWAYS = 1
 
127
CHECK_NEVER = 2
 
128
 
 
129
 
 
130
SIGN_WHEN_REQUIRED = 0
 
131
SIGN_ALWAYS = 1
 
132
SIGN_NEVER = 2
134
133
 
135
134
 
136
135
POLICY_NONE = 0
236
235
class NoWhoami(errors.BzrError):
237
236
 
238
237
    _fmt = ('Unable to determine your name.\n'
239
 
        "Please, set your name with the 'whoami' command.\n"
240
 
        'E.g. brz whoami "Your Name <name@example.com>"')
 
238
            "Please, set your name with the 'whoami' command.\n"
 
239
            'E.g. brz whoami "Your Name <name@example.com>"')
241
240
 
242
241
 
243
242
def signature_policy_from_unicode(signature_string):
628
627
        # This should be done through the proposed config defaults mechanism
629
628
        # when it becomes available in the future.
630
629
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
631
 
                                             expand=False)
632
 
                        or mergetools.known_merge_tools.get(name, None))
 
630
                                             expand=False) or
 
631
                        mergetools.known_merge_tools.get(name, None))
633
632
        return command_line
634
633
 
635
634
 
665
664
                      'Invoked when a config option is removed.'
666
665
                      ' The signature is (stack, name).',
667
666
                      (2, 4))
 
667
 
 
668
 
668
669
ConfigHooks = _ConfigHooks()
669
670
 
670
671
 
678
679
        These are all empty initially, because by default nothing should get
679
680
        notified.
680
681
        """
681
 
        super(_OldConfigHooks, self).__init__('breezy.config', 'OldConfigHooks')
 
682
        super(_OldConfigHooks, self).__init__(
 
683
            'breezy.config', 'OldConfigHooks')
682
684
        self.add_hook('load',
683
685
                      'Invoked when a config store is loaded.'
684
686
                      ' The signature is (config).',
700
702
                      'Invoked when a config option is removed.'
701
703
                      ' The signature is (config, name).',
702
704
                      (2, 4))
 
705
 
 
706
 
703
707
OldConfigHooks = _OldConfigHooks()
704
708
 
705
709
 
721
725
    def from_string(cls, str_or_unicode, file_name=None, save=False):
722
726
        """Create a config object from a string.
723
727
 
724
 
        :param str_or_unicode: A string representing the file content. This will
725
 
            be utf-8 encoded.
 
728
        :param str_or_unicode: A string representing the file content. This
 
729
            will be utf-8 encoded.
726
730
 
727
731
        :param file_name: The configuration file path.
728
732
 
817
821
            which sections should be searched. This is a list of (name,
818
822
            configobj) tuples.
819
823
        """
820
 
        opts = []
821
824
        if sections is None:
822
825
            parser = self._get_parser()
823
826
            sections = []
950
953
    If several processes try to write the config file, the accesses need to be
951
954
    serialized.
952
955
 
953
 
    Daughter classes should use the self.lock_write() decorator method when they 
954
 
    upate a config (they call, directly or indirectly, the
 
956
    Daughter classes should use the self.lock_write() decorator method when
 
957
    they upate a config (they call, directly or indirectly, the
955
958
    ``_write_config_file()`` method. These methods (typically ``set_option()``
956
959
    and variants must reload the config file from disk before calling
957
960
    ``_write_config_file()``), this can be achieved by calling the
1009
1012
    def remove_user_option(self, option_name, section_name=None):
1010
1013
        with self.lock_write():
1011
1014
            super(LockableConfig, self).remove_user_option(
1012
 
                    option_name, section_name)
 
1015
                option_name, section_name)
1013
1016
 
1014
1017
    def _write_config_file(self):
1015
1018
        if self._lock is None or not self._lock.is_held:
1096
1099
            # We need to avoid the LockableConfig implementation or we'll lock
1097
1100
            # twice
1098
1101
            super(LockableConfig, self).remove_user_option(
1099
 
                    option_name, section_name)
 
1102
                option_name, section_name)
1100
1103
 
1101
1104
 
1102
1105
def _iter_for_location_by_parts(sections, location):
1351
1354
                yield section
1352
1355
 
1353
1356
    def _get_options(self, sections=None):
1354
 
        opts = []
1355
1357
        # First the locations options
1356
1358
        for option in self._get_location_config()._get_options():
1357
1359
            yield option
1371
1373
            yield option
1372
1374
 
1373
1375
    def set_user_option(self, name, value, store=STORE_BRANCH,
1374
 
        warn_masked=False):
 
1376
                        warn_masked=False):
1375
1377
        if store == STORE_BRANCH:
1376
1378
            self._get_branch_data_config().set_option(value, name)
1377
1379
        elif store == STORE_GLOBAL:
1440
1442
        if sys.platform == 'win32':
1441
1443
            parent_dir = os.path.dirname(path)
1442
1444
            if not os.path.isdir(parent_dir):
1443
 
                trace.mutter('creating config parent directory: %r', parent_dir)
 
1445
                trace.mutter(
 
1446
                    'creating config parent directory: %r', parent_dir)
1444
1447
                os.mkdir(parent_dir)
1445
1448
        trace.mutter('creating config directory: %r', path)
1446
1449
        os.mkdir(path)
1451
1454
    """Return per-user configuration directory as unicode string
1452
1455
 
1453
1456
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1454
 
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1455
 
    that will be used instead.
 
1457
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar
 
1458
    directory, that will be used instead
1456
1459
 
1457
1460
    TODO: Global option --config-dir to override this.
1458
1461
    """
1577
1580
        return None
1578
1581
    try:
1579
1582
        f = open(mailname_file)
1580
 
    except (IOError, OSError) as e:
 
1583
    except (IOError, OSError):
1581
1584
        return None
1582
1585
    try:
1583
1586
        domain = f.readline().strip()
1613
1616
 
1614
1617
    Only used when none is set in the environment or the id file.
1615
1618
 
1616
 
    This only returns an email address if we can be fairly sure the 
 
1619
    This only returns an email address if we can be fairly sure the
1617
1620
    address is reasonable, ie if /etc/mailname is set on unix.
1618
1621
 
1619
 
    This doesn't use the FQDN as the default domain because that may be 
1620
 
    slow, and it doesn't use the hostname alone because that's not normally 
 
1622
    This doesn't use the FQDN as the default domain because that may be
 
1623
    slow, and it doesn't use the hostname alone because that's not normally
1621
1624
    a reasonable address.
1622
1625
    """
1623
1626
    if sys.platform == 'win32':
1650
1653
            try:
1651
1654
                encoding = osutils.get_user_encoding()
1652
1655
                gecos = gecos.decode(encoding)
1653
 
            except UnicodeError as e:
 
1656
            except UnicodeError:
1654
1657
                trace.mutter("cannot decode passwd entry %s" % w)
1655
1658
                return None, None
1656
1659
 
1658
1661
    if isinstance(username, bytes):
1659
1662
        try:
1660
1663
            username = username.decode(encoding)
1661
 
        except UnicodeError as e:
 
1664
        except UnicodeError:
1662
1665
            trace.mutter("cannot decode passwd entry %s" % w)
1663
1666
            return None, None
1664
1667
 
1699
1702
class TreeConfig(IniBasedConfig):
1700
1703
    """Branch configuration data associated with its contents, not location"""
1701
1704
 
1702
 
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
 
1705
    # XXX: Really needs a better name, as this is not part of the tree!
 
1706
    # -- mbp 20080507
1703
1707
 
1704
1708
    def __init__(self, branch):
1705
1709
        self._config = branch._get_config()
1739
1743
    """
1740
1744
 
1741
1745
    def __init__(self, _file=None):
1742
 
        self._config = None # The ConfigObj
 
1746
        self._config = None  # The ConfigObj
1743
1747
        if _file is None:
1744
1748
            self._filename = authentication_config_filename()
1745
1749
            self._input = self._filename = authentication_config_filename()
1775
1779
                trace.mutter('Unable to stat %r: %r', self._filename, e)
1776
1780
            return
1777
1781
        mode = stat.S_IMODE(st.st_mode)
1778
 
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP |
1779
 
             stat.S_IWGRP | stat.S_IRGRP ) & mode):
 
1782
        if ((stat.S_IXOTH | stat.S_IWOTH | stat.S_IROTH | stat.S_IXGRP
 
1783
             | stat.S_IWGRP | stat.S_IRGRP) & mode):
1780
1784
            # Only warn once
1781
 
            if (not self._filename in _authentication_config_permission_errors
1782
 
                and not GlobalConfig().suppress_warning(
 
1785
            if (self._filename not in _authentication_config_permission_errors and
 
1786
                not GlobalConfig().suppress_warning(
1783
1787
                    'insecure_permissions')):
1784
1788
                trace.warning("The file '%s' has insecure "
1785
 
                        "file permissions. Saved passwords may be accessible "
1786
 
                        "by other users.", self._filename)
 
1789
                              "file permissions. Saved passwords may be accessible "
 
1790
                              "by other users.", self._filename)
1787
1791
                _authentication_config_permission_errors.add(self._filename)
1788
1792
 
1789
1793
    def _save(self):
1790
1794
        """Save the config file, only tests should use it for now."""
1791
1795
        conf_dir = os.path.dirname(self._filename)
1792
1796
        ensure_config_dir_exists(conf_dir)
1793
 
        fd = os.open(self._filename, os.O_RDWR|os.O_CREAT, 0o600)
 
1797
        fd = os.open(self._filename, os.O_RDWR | os.O_CREAT, 0o600)
1794
1798
        try:
1795
1799
            f = os.fdopen(fd, 'wb')
1796
1800
            self._get_config().write(f)
1841
1845
        credentials = None
1842
1846
        for auth_def_name, auth_def in self._get_config().iteritems():
1843
1847
            if not isinstance(auth_def, configobj.Section):
1844
 
                raise ValueError("%s defined outside a section" % auth_def_name)
 
1848
                raise ValueError("%s defined outside a section" %
 
1849
                                 auth_def_name)
1845
1850
 
1846
1851
            a_scheme, a_host, a_user, a_path = map(
1847
1852
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1864
1869
            if a_scheme is not None and scheme != a_scheme:
1865
1870
                continue
1866
1871
            if a_host is not None:
1867
 
                if not (host == a_host
1868
 
                        or (a_host.startswith('.') and host.endswith(a_host))):
 
1872
                if not (host == a_host or
 
1873
                        (a_host.startswith('.') and host.endswith(a_host))):
1869
1874
                    continue
1870
1875
            if a_port is not None and port != a_port:
1871
1876
                continue
1872
 
            if (a_path is not None and path is not None
1873
 
                and not path.startswith(a_path)):
 
1877
            if (a_path is not None and path is not None and
 
1878
                    not path.startswith(a_path)):
1874
1879
                continue
1875
 
            if (a_user is not None and user is not None
1876
 
                and a_user != user):
 
1880
            if (a_user is not None and user is not None and
 
1881
                    a_user != user):
1877
1882
                # Never contradict the caller about the user to be used
1878
1883
                continue
1879
1884
            if a_user is None:
1940
1945
        if realm is not None:
1941
1946
            values['realm'] = realm
1942
1947
        config = self._get_config()
1943
 
        for_deletion = []
1944
1948
        for section, existing_values in config.iteritems():
1945
1949
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1946
1950
                if existing_values.get(key) != values.get(key):
1964
1968
 
1965
1969
        :param path: the absolute path on the server (optional)
1966
1970
 
1967
 
        :param ask: Ask the user if there is no explicitly configured username 
 
1971
        :param ask: Ask the user if there is no explicitly configured username
1968
1972
                    (optional)
1969
1973
 
1970
1974
        :param default: The username returned if none is defined (optional).
2025
2029
        if password is None:
2026
2030
            if prompt is None:
2027
2031
                # Create a default prompt suitable for most cases
2028
 
                prompt = u'%s' % scheme.upper() + u' %(user)s@%(host)s password'
 
2032
                prompt = (u'%s' %
 
2033
                          scheme.upper() + u' %(user)s@%(host)s password')
2029
2034
            # Special handling for optional fields in the prompt
2030
2035
            if port is not None:
2031
2036
                prompt_host = '%s:%d' % (host, port)
2147
2152
        raise NotImplementedError(self.get_credentials)
2148
2153
 
2149
2154
 
2150
 
 
2151
2155
class PlainTextCredentialStore(CredentialStore):
2152
2156
    __doc__ = """Plain text credential store for the authentication.conf file"""
2153
2157
 
2170
2174
        #                should probably propogate as something more useful.
2171
2175
        return base64.standard_b64decode(credentials['password'])
2172
2176
 
 
2177
 
2173
2178
credential_store_registry.register('base64', Base64CredentialStore,
2174
2179
                                   help=Base64CredentialStore.__doc__)
2175
2180
 
2279
2284
            return f
2280
2285
        except errors.NoSuchFile:
2281
2286
            return BytesIO()
2282
 
        except errors.PermissionDenied as e:
2283
 
            trace.warning("Permission denied while trying to open "
2284
 
                "configuration file %s.", urlutils.unescape_for_display(
2285
 
                urlutils.join(self._transport.base, self._filename), "utf-8"))
 
2287
        except errors.PermissionDenied:
 
2288
            trace.warning(
 
2289
                "Permission denied while trying to open "
 
2290
                "configuration file %s.",
 
2291
                urlutils.unescape_for_display(
 
2292
                    urlutils.join(self._transport.base, self._filename),
 
2293
                    "utf-8"))
2286
2294
            return BytesIO()
2287
2295
 
2288
2296
    def _external_url(self):
2475
2483
 
2476
2484
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2477
2485
 
 
2486
 
2478
2487
def int_SI_from_store(unicode_str):
2479
2488
    """Convert a human readable size in SI units, e.g 10MB into an integer.
2480
2489
 
2482
2491
    by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2483
2492
    pedantic.
2484
2493
 
2485
 
    :return Integer, expanded to its base-10 value if a proper SI unit is 
 
2494
    :return Integer, expanded to its base-10 value if a proper SI unit is
2486
2495
        found, None otherwise.
2487
2496
    """
2488
2497
    regexp = "^(\\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2496
2505
            try:
2497
2506
                coeff = _unit_suffixes[unit.upper()]
2498
2507
            except KeyError:
2499
 
                raise ValueError(gettext('{0} is not an SI unit.').format(unit))
 
2508
                raise ValueError(
 
2509
                    gettext('{0} is not an SI unit.').format(unit))
2500
2510
            val *= coeff
2501
2511
    return val
2502
2512
 
2574
2584
            raise ValueError(
2575
2585
                "Invalid value %s for %s."
2576
2586
                "See help for a list of possible values." % (unicode_str,
2577
 
                    self.name))
 
2587
                                                             self.name))
2578
2588
 
2579
2589
    @property
2580
2590
    def help(self):
2593
2603
for '{bar{baz}}' we will get '{baz}'
2594
2604
"""
2595
2605
 
 
2606
 
2596
2607
def iter_option_refs(string):
2597
2608
    # Split isolate refs so every other chunk is a ref
2598
2609
    is_ref = False
2599
 
    for chunk  in _option_ref_re.split(string):
 
2610
    for chunk in _option_ref_re.split(string):
2600
2611
        yield is_ref, chunk
2601
2612
        is_ref = not is_ref
2602
2613
 
2633
2644
 
2634
2645
        :param module_name: the python path to the module. Such as 'os.path'.
2635
2646
 
2636
 
        :param member_name: the member of the module to return.  If empty or 
 
2647
        :param member_name: the member of the module to return.  If empty or
2637
2648
                None, get() will return the module itself.
2638
2649
        """
2639
2650
        self._check_option_name(key)
2665
2676
'''))
2666
2677
option_registry.register(
2667
2678
    ListOption('acceptable_keys',
2668
 
           default=None,
2669
 
           help="""\
 
2679
               default=None,
 
2680
               help="""\
2670
2681
List of GPG key patterns which are acceptable for verification.
2671
2682
"""))
2672
2683
option_registry.register(
2702
2713
See also: bound.
2703
2714
"""))
2704
2715
option_registry.register(
2705
 
    Option('branch.fetch_tags', default=False,  from_unicode=bool_from_store,
 
2716
    Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
2706
2717
           help="""\
2707
2718
Whether revisions associated with tags should be fetched.
2708
2719
"""))
2710
2721
    'transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
2711
2722
option_registry.register(
2712
2723
    Option('bzr.workingtree.worth_saving_limit', default=10,
2713
 
           from_unicode=int_from_store,  invalid='warning',
 
2724
           from_unicode=int_from_store, invalid='warning',
2714
2725
           help='''\
2715
2726
How many changes before saving the dirstate.
2716
2727
 
2770
2781
'''))
2771
2782
option_registry.register(
2772
2783
    ListOption('debug_flags', default=[],
2773
 
           help='Debug flags to activate.'))
 
2784
               help='Debug flags to activate.'))
2774
2785
option_registry.register(
2775
2786
    Option('default_format', default='2a',
2776
2787
           help='Format used when creating branches.'))
2805
2816
'''))
2806
2817
option_registry.register(
2807
2818
    Option('log_format', default='long',
2808
 
           help= '''\
 
2819
           help='''\
2809
2820
Log format to use when displaying revisions.
2810
2821
 
2811
2822
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2812
2823
may be provided by plugins.
2813
2824
'''))
2814
2825
option_registry.register_lazy('mail_client', 'breezy.mail_client',
2815
 
    'opt_mail_client')
 
2826
                              'opt_mail_client')
2816
2827
option_registry.register(
2817
2828
    Option('output_encoding',
2818
 
           help= 'Unicode encoding for output'
 
2829
           help='Unicode encoding for output'
2819
2830
           ' (terminal encoding if not specified).'))
2820
2831
option_registry.register(
2821
2832
    Option('parent_location',
2874
2885
lost if the machine crashes.  See also dirstate.fdatasync.
2875
2886
'''))
2876
2887
option_registry.register_lazy('smtp_server',
2877
 
    'breezy.smtp_connection', 'smtp_server')
 
2888
                              'breezy.smtp_connection', 'smtp_server')
2878
2889
option_registry.register_lazy('smtp_password',
2879
 
    'breezy.smtp_connection', 'smtp_password')
 
2890
                              'breezy.smtp_connection', 'smtp_password')
2880
2891
option_registry.register_lazy('smtp_username',
2881
 
    'breezy.smtp_connection', 'smtp_username')
 
2892
                              'breezy.smtp_connection', 'smtp_username')
2882
2893
option_registry.register(
2883
2894
    Option('selftest.timeout',
2884
 
        default='600',
2885
 
        from_unicode=int_from_store,
2886
 
        help='Abort selftest if one test takes longer than this many seconds',
2887
 
        ))
 
2895
           default='600',
 
2896
           from_unicode=int_from_store,
 
2897
           help='Abort selftest if one test takes longer than this many seconds',
 
2898
           ))
2888
2899
 
2889
2900
option_registry.register(
2890
2901
    Option('send_strict', default=None,
2919
2930
           help='''Where submissions from this branch are mailed to.'''))
2920
2931
option_registry.register(
2921
2932
    ListOption('suppress_warnings',
2922
 
           default=[],
2923
 
           help="List of warning classes to suppress."))
 
2933
               default=[],
 
2934
               help="List of warning classes to suppress."))
2924
2935
option_registry.register(
2925
2936
    Option('validate_signatures_in_log', default=False,
2926
2937
           from_unicode=bool_from_store, invalid='warning',
2927
2938
           help='''Whether to validate signatures in brz log.'''))
2928
2939
option_registry.register_lazy('ssl.ca_certs',
2929
 
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
 
2940
                              'breezy.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2930
2941
 
2931
2942
option_registry.register_lazy('ssl.cert_reqs',
2932
 
    'breezy.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
 
2943
                              'breezy.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2933
2944
 
2934
2945
 
2935
2946
class Section(object):
3018
3029
                # Someone changed the value since we get it from the persistent
3019
3030
                # storage.
3020
3031
                trace.warning(gettext(
3021
 
                        "Option {0} in section {1} of {2} was changed"
3022
 
                        " from {3} to {4}. The {5} value will be saved.".format(
3023
 
                            k, self.id, store.external_url(), expected,
3024
 
                            reloaded, actual)))
 
3032
                    "Option {0} in section {1} of {2} was changed"
 
3033
                    " from {3} to {4}. The {5} value will be saved.".format(
 
3034
                        k, self.id, store.external_url(), expected,
 
3035
                        reloaded, actual)))
3025
3036
        # No need to keep track of these changes
3026
3037
        self.reset_changes()
3027
3038
 
3173
3184
        return 'cmdline'
3174
3185
 
3175
3186
    def get_sections(self):
3176
 
        yield self,  self.readonly_section_class(None, self.options)
 
3187
        yield self, self.readonly_section_class(None, self.options)
3177
3188
 
3178
3189
 
3179
3190
class IniFileStore(Store):
3190
3201
        self._config_obj = None
3191
3202
 
3192
3203
    def is_loaded(self):
3193
 
        return self._config_obj != None
 
3204
        return self._config_obj is not None
3194
3205
 
3195
3206
    def unload(self):
3196
3207
        self._config_obj = None
3465
3476
 
3466
3477
    def __init__(self, bzrdir):
3467
3478
        super(ControlStore, self).__init__(bzrdir.transport,
3468
 
                                          'control.conf',
 
3479
                                           'control.conf',
3469
3480
                                           lock_dir_name='branch_lock')
3470
3481
        self.id = 'control'
3471
3482
 
3582
3593
                # the location is already a local path or URL, convert the
3583
3594
                # section id to the same format
3584
3595
                section_path = urlutils.local_path_from_url(section_path)
3585
 
            if (self.location.startswith(section_path)
3586
 
                or fnmatch.fnmatch(self.location, section_path)):
 
3596
            if (self.location.startswith(section_path) or
 
3597
                    fnmatch.fnmatch(self.location, section_path)):
3587
3598
                section_parts = section_path.rstrip('/').split('/')
3588
3599
                extra_path = '/'.join(location_parts[len(section_parts):])
3589
3600
                yield store, LocationSection(section, extra_path)
3662
3673
_shared_stores = {}
3663
3674
_shared_stores_at_exit_installed = False
3664
3675
 
 
3676
 
3665
3677
class Stack(object):
3666
3678
    """A stack of configurations where an option can be defined"""
3667
3679
 
3713
3725
        """
3714
3726
        # FIXME: No caching of options nor sections yet -- vila 20110503
3715
3727
        value = None
3716
 
        found_store = None # Where the option value has been found
 
3728
        found_store = None  # Where the option value has been found
3717
3729
        # If the option is registered, it may provide additional info about
3718
3730
        # value handling
3719
3731
        try:
3879
3891
        if state is None:
3880
3892
            global _shared_stores_at_exit_installed
3881
3893
            stores = _shared_stores
 
3894
 
3882
3895
            def save_config_changes():
3883
3896
                for k, store in stores.items():
3884
3897
                    store.save_changes()
4135
4148
                        ' configuration file.',
4136
4149
                        type=text_type),
4137
4150
        commands.Option('all',
4138
 
            help='Display all the defined values for the matching options.',
4139
 
            ),
 
4151
                        help='Display all the defined values for the matching options.',
 
4152
                        ),
4140
4153
        commands.Option('remove', help='Remove the option from'
4141
4154
                        ' the configuration file.'),
4142
4155
        ]