Rev 6273: (vila) Switch ``bzr config`` to the stack-based config implementation in file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
Patch Queue Manager
pqm at pqm.ubuntu.com
Thu Nov 17 17:41:46 UTC 2011
At file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 6273 [merge]
revision-id: pqm at pqm.ubuntu.com-20111117174145-2nb7jko9c5t7llcb
parent: pqm at pqm.ubuntu.com-20111117163543-1wumacqhy65ii76k
parent: v.ladeuil+lp at free.fr-20111117171609-pzs107pdm0vndlf9
committer: Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2011-11-17 17:41:45 +0000
message:
(vila) Switch ``bzr config`` to the stack-based config implementation
(Vincent Ladeuil)
modified:
bzrlib/config.py config.py-20051011043216-070c74f4e9e338e8
bzrlib/library_state.py library_state.py-20100625053036-962zdkiik8k6m5jx-1
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/blackbox/test_config.py test_config.py-20100927150753-x6rf54uibd08r636-1
bzrlib/tests/test_config.py testconfig.py-20051011041908-742d0c15d8d8c8eb
bzrlib/tests/test_debug.py test_debug.py-20090303053802-01e8mlv24odmpgix-1
bzrlib/tests/test_msgeditor.py test_msgeditor.py-20051202041359-920315ec6011ee51
doc/en/release-notes/bzr-2.5.txt bzr2.5.txt-20110708125756-587p0hpw7oke4h05-1
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py 2011-10-31 22:11:59 +0000
+++ b/bzrlib/config.py 2011-11-16 17:19:13 +0000
@@ -2632,9 +2632,13 @@
# We re-use the dict-like object received
self.options = options
- def get(self, name, default=None):
+ def get(self, name, default=None, expand=True):
return self.options.get(name, default)
+ def iter_option_names(self):
+ for k in self.options.iterkeys():
+ yield k
+
def __repr__(self):
# Mostly for debugging use
return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
@@ -2665,31 +2669,6 @@
del self.options[name]
-class CommandLineSection(MutableSection):
- """A section used to carry command line overrides for the config options."""
-
- def __init__(self, opts=None):
- if opts is None:
- opts = {}
- super(CommandLineSection, self).__init__('cmdline-overrides', opts)
-
- def _reset(self):
- # The dict should be cleared but not replaced so it can be shared.
- self.options.clear()
-
- def _from_cmdline(self, overrides):
- # Reset before accepting new definitions
- self._reset()
- for over in overrides:
- try:
- name, value = over.split('=', 1)
- except ValueError:
- raise errors.BzrCommandError(
- gettext("Invalid '%s', should be of the form 'name=value'")
- % (over,))
- self.set(name, value)
-
-
class Store(object):
"""Abstract interface to persistent storage for configuration options."""
@@ -2734,14 +2713,14 @@
def get_sections(self):
"""Returns an ordered iterable of existing sections.
- :returns: An iterable of (name, dict).
+ :returns: An iterable of (store, section).
"""
raise NotImplementedError(self.get_sections)
- def get_mutable_section(self, section_name=None):
+ def get_mutable_section(self, section_id=None):
"""Returns the specified mutable section.
- :param section_name: The section identifier
+ :param section_id: The section identifier
"""
raise NotImplementedError(self.get_mutable_section)
@@ -2751,6 +2730,41 @@
self.external_url())
+class CommandLineStore(Store):
+ "A store to carry command line overrides for the config options."""
+
+ def __init__(self, opts=None):
+ super(CommandLineStore, self).__init__()
+ if opts is None:
+ opts = {}
+ self.options = {}
+
+ def _reset(self):
+ # The dict should be cleared but not replaced so it can be shared.
+ self.options.clear()
+
+ def _from_cmdline(self, overrides):
+ # Reset before accepting new definitions
+ self._reset()
+ for over in overrides:
+ try:
+ name, value = over.split('=', 1)
+ except ValueError:
+ raise errors.BzrCommandError(
+ gettext("Invalid '%s', should be of the form 'name=value'")
+ % (over,))
+ self.options[name] = value
+
+ def external_url(self):
+ # Not an url but it makes debugging easier and it never needed
+ # otherwise
+ return 'cmdline'
+
+ def get_sections(self):
+ yield self, self.readonly_section_class('cmdline_overrides',
+ self.options)
+
+
class IniFileStore(Store):
"""A config Store using ConfigObj for storage.
@@ -2833,7 +2847,7 @@
def get_sections(self):
"""Get the configobj section in the file order.
- :returns: An iterable of (name, dict).
+ :returns: An iterable of (store, section).
"""
# We need a loaded store
try:
@@ -2843,22 +2857,24 @@
return
cobj = self._config_obj
if cobj.scalars:
- yield self.readonly_section_class(None, cobj)
+ yield self, self.readonly_section_class(None, cobj)
for section_name in cobj.sections:
- yield self.readonly_section_class(section_name, cobj[section_name])
+ yield (self,
+ self.readonly_section_class(section_name,
+ cobj[section_name]))
- def get_mutable_section(self, section_name=None):
+ def get_mutable_section(self, section_id=None):
# We need a loaded store
try:
self.load()
except errors.NoSuchFile:
# The file doesn't exist, let's pretend it was empty
self._load_from_string('')
- if section_name is None:
+ if section_id is None:
section = self._config_obj
else:
- section = self._config_obj.setdefault(section_name, {})
- return self.mutable_section_class(section_name, section)
+ section = self._config_obj.setdefault(section_id, {})
+ return self.mutable_section_class(section_id, section)
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
@@ -2923,6 +2939,7 @@
t = transport.get_transport_from_path(
config_dir(), possible_transports=possible_transports)
super(GlobalStore, self).__init__(t, 'bazaar.conf')
+ self.id = 'bazaar'
class LocationStore(LockableIniFileStore):
@@ -2931,6 +2948,7 @@
t = transport.get_transport_from_path(
config_dir(), possible_transports=possible_transports)
super(LocationStore, self).__init__(t, 'locations.conf')
+ self.id = 'locations'
class BranchStore(IniFileStore):
@@ -2939,6 +2957,7 @@
super(BranchStore, self).__init__(branch.control_transport,
'branch.conf')
self.branch = branch
+ self.id = 'branch'
def lock_write(self, token=None):
return self.branch.lock_write(token)
@@ -2978,9 +2997,9 @@
# sections.
sections = self.store.get_sections()
# Walk the revisions in the order provided
- for s in sections:
+ for store, s in sections:
if self.match(s):
- yield s
+ yield store, s
def match(self, section):
"""Does the proposed section match.
@@ -3010,9 +3029,9 @@
self.extra_path = extra_path
self.locals = {'relpath': extra_path}
- def get(self, name, default=None):
+ def get(self, name, default=None, expand=True):
value = super(LocationSection, self).get(name, default)
- if value is not None:
+ if value is not None and expand:
policy_name = self.get(name + ':policy', None)
policy = _policy_value.get(policy_name, POLICY_NONE)
if policy == POLICY_APPENDPATH:
@@ -3049,7 +3068,7 @@
all_sections = []
# Filter out the no_name_section so _iter_for_location_by_parts can be
# used (it assumes all sections have a name).
- for section in self.store.get_sections():
+ for _, section in self.store.get_sections():
if section.id is None:
no_name_section = section
else:
@@ -3092,7 +3111,7 @@
if ignore:
break
# Finally, we have a valid section
- yield section
+ yield self.store, section
_option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
@@ -3115,7 +3134,7 @@
class Stack(object):
"""A stack of configurations where an option can be defined"""
- def __init__(self, sections_def, store=None, mutable_section_name=None):
+ def __init__(self, sections_def, store=None, mutable_section_id=None):
"""Creates a stack of sections with an optional store for changes.
:param sections_def: A list of Section or callables that returns an
@@ -3125,13 +3144,13 @@
:param store: The optional Store where modifications will be
recorded. If none is specified, no modifications can be done.
- :param mutable_section_name: The name of the MutableSection where
- changes are recorded. This requires the ``store`` parameter to be
+ :param mutable_section_id: The id of the MutableSection where changes
+ are recorded. This requires the ``store`` parameter to be
specified.
"""
self.sections_def = sections_def
self.store = store
- self.mutable_section_name = mutable_section_name
+ self.mutable_section_id = mutable_section_id
def get(self, name, expand=None):
"""Return the *first* option value found in the sections.
@@ -3156,13 +3175,8 @@
# implies querying the persistent storage) until it can't be avoided
# anymore by using callables to describe (possibly empty) section
# lists.
- for section_or_callable in self.sections_def:
- # Each section can expand to multiple ones when a callable is used
- if callable(section_or_callable):
- sections = section_or_callable()
- else:
- sections = [section_or_callable]
- for section in sections:
+ for sections in self.sections_def:
+ for store, section in sections():
value = section.get(name)
if value is not None:
break
@@ -3269,9 +3283,9 @@
This is where we guarantee that the mutable section is lazily loaded:
this means we won't load the corresponding store before setting a value
or deleting an option. In practice the store will often be loaded but
- this allows helps catching some programming errors.
+ this helps catching some programming errors.
"""
- section = self.store.get_mutable_section(self.mutable_section_name)
+ section = self.store.get_mutable_section(self.mutable_section_id)
return section
def set(self, name, value):
@@ -3295,7 +3309,7 @@
def _get_overrides(self):
# Hack around library_state.initialize never called
if bzrlib.global_state is not None:
- return [bzrlib.global_state.cmdline_overrides]
+ return bzrlib.global_state.cmdline_overrides.get_sections()
return []
@@ -3308,8 +3322,8 @@
One assumption made here is that the daughter classes will all use Stores
derived from LockableIniFileStore).
- It implements set() by re-loading the store before applying the
- modification and saving it.
+ It implements set() and remove () by re-loading the store before applying
+ the modification and saving it.
The long term plan being to implement a single write by store to save
all modifications, this class should not be used in the interim.
@@ -3322,6 +3336,13 @@
# Force a write to persistent storage
self.store.save()
+ def remove(self, name):
+ # Force a reload
+ self.store.unload()
+ super(_CompatibleStack, self).remove(name)
+ # Force a write to persistent storage
+ self.store.save()
+
class GlobalStack(_CompatibleStack):
"""Global options only stack."""
@@ -3330,8 +3351,8 @@
# Get a GlobalStore
gstore = GlobalStore()
super(GlobalStack, self).__init__(
- [self._get_overrides, gstore.get_sections],
- gstore)
+ [self._get_overrides, NameMatcher(gstore, 'DEFAULT').get_sections],
+ gstore, mutable_section_id='DEFAULT')
class LocationStack(_CompatibleStack):
@@ -3342,12 +3363,16 @@
:param location: A URL prefix to """
lstore = LocationStore()
+ if location is not None:
+ location = urlutils.normalize_url(location)
+ if location.startswith('file://'):
+ location = urlutils.local_path_from_url(location)
matcher = LocationMatcher(lstore, location)
gstore = GlobalStore()
super(LocationStack, self).__init__(
[self._get_overrides,
- matcher.get_sections, gstore.get_sections],
- lstore)
+ matcher.get_sections, NameMatcher(gstore, 'DEFAULT').get_sections],
+ lstore, mutable_section_id=location)
class BranchStack(_CompatibleStack):
@@ -3360,7 +3385,8 @@
gstore = GlobalStore()
super(BranchStack, self).__init__(
[self._get_overrides,
- matcher.get_sections, bstore.get_sections, gstore.get_sections],
+ matcher.get_sections, bstore.get_sections,
+ NameMatcher(gstore, 'DEFAULT').get_sections],
bstore)
self.branch = branch
@@ -3386,6 +3412,10 @@
bstore)
self.branch = branch
+# Use a an empty dict to initialize an empty configobj avoiding all
+# parsing and encoding checks
+_quoting_config = configobj.ConfigObj(
+ {}, encoding='utf-8', interpolation=False)
class cmd_config(commands.Command):
__doc__ = """Display, set or remove a configuration option.
@@ -3408,7 +3438,8 @@
takes_options = [
'directory',
# FIXME: This should be a registry option so that plugins can register
- # their own config files (or not) -- vila 20101002
+ # their own config files (or not) and will also address
+ # http://pad.lv/788991 -- vila 20101115
commands.Option('scope', help='Reduce the scope to the specified'
' configuration file',
type=unicode),
@@ -3452,53 +3483,44 @@
# Set the option value
self._set_config_option(name, value, directory, scope)
- def _get_configs(self, directory, scope=None):
- """Iterate the configurations specified by ``directory`` and ``scope``.
+ def _get_stack(self, directory, scope=None):
+ """Get the configuration stack specified by ``directory`` and ``scope``.
:param directory: Where the configurations are derived from.
:param scope: A specific config to start from.
"""
+ # FIXME: scope should allow access to plugin-specific stacks (even
+ # reduced to the plugin-specific store), related to
+ # http://pad.lv/788991 -- vila 2011-11-15
if scope is not None:
if scope == 'bazaar':
- yield GlobalConfig()
+ return GlobalStack()
elif scope == 'locations':
- yield LocationConfig(directory)
+ return LocationStack(directory)
elif scope == 'branch':
(_, br, _) = (
controldir.ControlDir.open_containing_tree_or_branch(
directory))
- yield br.get_config()
+ return br.get_config_stack()
+ raise errors.NoSuchConfig(scope)
else:
try:
(_, br, _) = (
controldir.ControlDir.open_containing_tree_or_branch(
directory))
- yield br.get_config()
+ return br.get_config_stack()
except errors.NotBranchError:
- yield LocationConfig(directory)
- yield GlobalConfig()
+ return LocationStack(directory)
def _show_value(self, name, directory, scope):
- displayed = False
- for c in self._get_configs(directory, scope):
- if displayed:
- break
- for (oname, value, section, conf_id, parser) in c._get_options():
- if name == oname:
- # Display only the first value and exit
-
- # FIXME: We need to use get_user_option to take policies
- # into account and we need to make sure the option exists
- # too (hence the two for loops), this needs a better API
- # -- vila 20101117
- value = c.get_user_option(name)
- # Quote the value appropriately
- value = parser._quote(value)
- self.outf.write('%s\n' % (value,))
- displayed = True
- break
- if not displayed:
+ conf = self._get_stack(directory, scope)
+ value = conf.get(name, expand=True)
+ if value is not None:
+ # Quote the value appropriately
+ value = _quoting_config._quote(value)
+ self.outf.write('%s\n' % (value,))
+ else:
raise errors.NoSuchConfigOption(name)
def _show_matching_options(self, name, directory, scope):
@@ -3507,55 +3529,43 @@
# avoid the delay introduced by the lazy regexp. But, we still do
# want the nicer errors raised by lazy_regex.
name._compile_and_collapse()
- cur_conf_id = None
+ cur_store_id = None
cur_section = None
- for c in self._get_configs(directory, scope):
- for (oname, value, section, conf_id, parser) in c._get_options():
- if name.search(oname):
- if cur_conf_id != conf_id:
- # Explain where the options are defined
- self.outf.write('%s:\n' % (conf_id,))
- cur_conf_id = conf_id
- cur_section = None
- if (section not in (None, 'DEFAULT')
- and cur_section != section):
- # Display the section if it's not the default (or only)
- # one.
- self.outf.write(' [%s]\n' % (section,))
- cur_section = section
- self.outf.write(' %s = %s\n' % (oname, value))
+ conf = self._get_stack(directory, scope)
+ for sections in conf.sections_def:
+ for store, section in sections():
+ for oname in section.iter_option_names():
+ if name.search(oname):
+ if cur_store_id != store.id:
+ # Explain where the options are defined
+ self.outf.write('%s:\n' % (store.id,))
+ cur_store_id = store.id
+ cur_section = None
+ if (section.id not in (None, 'DEFAULT')
+ and cur_section != section.id):
+ # Display the section if it's not the default (or
+ # only) one.
+ self.outf.write(' [%s]\n' % (section.id,))
+ cur_section = section.id
+ value = section.get(oname, expand=False)
+ value = _quoting_config._quote(value)
+ self.outf.write(' %s = %s\n' % (oname, value))
def _set_config_option(self, name, value, directory, scope):
- for conf in self._get_configs(directory, scope):
- conf.set_user_option(name, value)
- break
- else:
- raise errors.NoSuchConfig(scope)
+ conf = self._get_stack(directory, scope)
+ conf.set(name, value)
def _remove_config_option(self, name, directory, scope):
if name is None:
raise errors.BzrCommandError(
'--remove expects an option to remove.')
- removed = False
- for conf in self._get_configs(directory, scope):
- for (section_name, section, conf_id) in conf._get_sections():
- if scope is not None and conf_id != scope:
- # Not the right configuration file
- continue
- if name in section:
- if conf_id != conf.config_id():
- conf = self._get_configs(directory, conf_id).next()
- # We use the first section in the first config where the
- # option is defined to remove it
- conf.remove_user_option(name, section_name)
- removed = True
- break
- break
- else:
- raise errors.NoSuchConfig(scope)
- if not removed:
+ conf = self._get_stack(directory, scope)
+ try:
+ conf.remove(name)
+ except KeyError:
raise errors.NoSuchConfigOption(name)
+
# Test registries
#
# We need adapters that can build a Store or a Stack in a test context. Test
=== modified file 'bzrlib/library_state.py'
--- a/bzrlib/library_state.py 2011-09-26 15:40:02 +0000
+++ b/bzrlib/library_state.py 2011-11-16 15:57:14 +0000
@@ -67,7 +67,7 @@
self._trace = trace
# There is no overrides by default, they are set later when the command
# arguments are parsed.
- self.cmdline_overrides = config.CommandLineSection()
+ self.cmdline_overrides = config.CommandLineStore()
self.started = False
def __enter__(self):
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2011-11-07 10:14:38 +0000
+++ b/bzrlib/tests/__init__.py 2011-11-16 15:57:14 +0000
@@ -999,7 +999,7 @@
self._cleanEnvironment()
if bzrlib.global_state is not None:
self.overrideAttr(bzrlib.global_state, 'cmdline_overrides',
- config.CommandLineSection())
+ config.CommandLineStore())
self._silenceUI()
self._startLogFile()
self._benchcalls = []
=== modified file 'bzrlib/tests/blackbox/test_config.py'
--- a/bzrlib/tests/blackbox/test_config.py 2011-02-22 12:59:14 +0000
+++ b/bzrlib/tests/blackbox/test_config.py 2011-11-16 15:57:14 +0000
@@ -96,18 +96,22 @@
''')
def test_list_all_values(self):
+ # FIXME: we should register the option as a list or it's displayed as
+ # astring and as such, quoted.
self.bazaar_config.set_user_option('list', [1, 'a', 'with, a comma'])
script.run_script(self, '''\
$ bzr config -d tree
bazaar:
- list = 1, a, "with, a comma"
+ list = '1, a, "with, a comma"'
''')
def test_list_value_only(self):
+ # FIXME: we should register the option as a list or it's displayed as
+ # astring and as such, quoted.
self.bazaar_config.set_user_option('list', [1, 'a', 'with, a comma'])
script.run_script(self, '''\
$ bzr config -d tree list
- 1, a, "with, a comma"
+ '1, a, "with, a comma"'
''')
def test_bazaar_config(self):
@@ -189,7 +193,7 @@
# We need to delete the locations definition that overrides the branch
# one
script.run_script(self, '''\
- $ bzr config -d tree --remove file
+ $ bzr config -d tree --scope locations --remove file
$ bzr config -d tree file
branch
''')
@@ -291,7 +295,7 @@
def test_branch_config_default(self):
script.run_script(self, '''\
- $ bzr config -d tree --remove file
+ $ bzr config -d tree --scope locations --remove file
$ bzr config -d tree --all file
branch:
file = branch
@@ -316,7 +320,7 @@
file = bazaar
''')
script.run_script(self, '''\
- $ bzr config -d tree --remove file
+ $ bzr config -d tree --scope locations --remove file
$ bzr config -d tree --all file
bazaar:
file = bazaar
=== modified file 'bzrlib/tests/test_config.py'
--- a/bzrlib/tests/test_config.py 2011-10-31 22:11:59 +0000
+++ b/bzrlib/tests/test_config.py 2011-11-16 17:19:13 +0000
@@ -2565,9 +2565,6 @@
scenarios = [('mutable',
{'get_section':
lambda opts: config.MutableSection('myID', opts)},),
- ('cmdline',
- {'get_section':
- lambda opts: config.CommandLineSection(opts)},),
]
def test_set(self):
@@ -2615,43 +2612,52 @@
self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
-class TestCommandLineSection(tests.TestCase):
+class TestCommandLineStore(tests.TestCase):
def setUp(self):
- super(TestCommandLineSection, self).setUp()
- self.section = config.CommandLineSection()
+ super(TestCommandLineStore, self).setUp()
+ self.store = config.CommandLineStore()
+
+ def get_section(self):
+ """Get the unique section for the command line overrides."""
+ sections = list(self.store.get_sections())
+ self.assertLength(1, sections)
+ store, section = sections[0]
+ self.assertEquals(self.store, store)
+ return section
def test_no_override(self):
- self.section._from_cmdline([])
- # FIXME: we want some iterator over all options, failing that, we peek
- # under the cover -- vila 2011-09026
- self.assertLength(0, self.section.options)
+ self.store._from_cmdline([])
+ section = self.get_section()
+ self.assertLength(0, list(section.iter_option_names()))
def test_simple_override(self):
- self.section._from_cmdline(['a=b'])
- self.assertEqual('b', self.section.get('a'))
+ self.store._from_cmdline(['a=b'])
+ section = self.get_section()
+ self.assertEqual('b', section.get('a'))
def test_list_override(self):
- self.section._from_cmdline(['l=1,2,3'])
- val = self.section.get('l')
+ self.store._from_cmdline(['l=1,2,3'])
+ val = self.get_section().get('l')
self.assertEqual('1,2,3', val)
- # Reminder: lists should registered as such explicitely, otherwise the
- # conversion needs to be done afterwards.
+ # Reminder: lists should be registered as such explicitely, otherwise
+ # the conversion needs to be done afterwards.
self.assertEqual(['1', '2', '3'], config.list_from_store(val))
def test_multiple_overrides(self):
- self.section._from_cmdline(['a=b', 'x=y'])
- self.assertEquals('b', self.section.get('a'))
- self.assertEquals('y', self.section.get('x'))
+ self.store._from_cmdline(['a=b', 'x=y'])
+ section = self.get_section()
+ self.assertEquals('b', section.get('a'))
+ self.assertEquals('y', section.get('x'))
def test_wrong_syntax(self):
self.assertRaises(errors.BzrCommandError,
- self.section._from_cmdline, ['a=b', 'c'])
+ self.store._from_cmdline, ['a=b', 'c'])
class TestStore(tests.TestCaseWithTransport):
- def assertSectionContent(self, expected, section):
+ def assertSectionContent(self, expected, (store, section)):
"""Assert that some options have the proper values in a section."""
expected_name, expected_options = expected
self.assertEquals(expected_name, section.id)
@@ -2983,13 +2989,13 @@
def setUp(self):
super(TestConcurrentStoreUpdates, self).setUp()
- self._content = 'one=1\ntwo=2\n'
self.stack = self.get_stack(self)
if not isinstance(self.stack, config._CompatibleStack):
raise tests.TestNotApplicable(
'%s is not meant to be compatible with the old config design'
% (self.stack,))
- self.stack.store._load_from_string(self._content)
+ self.stack.set('one', '1')
+ self.stack.set('two', '2')
# Flush the store
self.stack.store.save()
@@ -3170,9 +3176,9 @@
''')
self.assertEquals(['/foo', '/foo/baz', '/foo/bar', '/foo/bar/baz',
'/quux/quux'],
- [section.id for section in store.get_sections()])
+ [section.id for _, section in store.get_sections()])
matcher = config.LocationMatcher(store, '/foo/bar/quux')
- sections = list(matcher.get_sections())
+ sections = [section for s, section in matcher.get_sections()]
self.assertEquals([3, 2],
[section.length for section in sections])
self.assertEquals(['/foo/bar', '/foo'],
@@ -3189,9 +3195,9 @@
section=/foo/bar
''')
self.assertEquals(['/foo', '/foo/bar'],
- [section.id for section in store.get_sections()])
+ [section.id for _, section in store.get_sections()])
matcher = config.LocationMatcher(store, '/foo/bar/baz')
- sections = list(matcher.get_sections())
+ sections = [section for s, section in matcher.get_sections()]
self.assertEquals([3, 2],
[section.length for section in sections])
self.assertEquals(['/foo/bar', '/foo'],
@@ -3210,7 +3216,7 @@
matcher = config.LocationMatcher(store, 'dir/subdir')
sections = list(matcher.get_sections())
self.assertLength(1, sections)
- self.assertEquals('bar/dir/subdir', sections[0].get('foo'))
+ self.assertEquals('bar/dir/subdir', sections[0][1].get('foo'))
def test_file_urls_are_normalized(self):
store = self.get_store(self)
@@ -3333,7 +3339,7 @@
self.assertEquals(None, self.conf.get('foo'))
def test_get_hook(self):
- self.conf.store._load_from_string('foo=bar')
+ self.conf.set('foo', 'bar')
calls = []
def hook(*args):
calls.append(args)
@@ -3345,12 +3351,17 @@
self.assertEquals((self.conf, 'foo', 'bar'), calls[0])
-class TestStackGetWithConverter(TestStackGet):
+class TestStackGetWithConverter(tests.TestCaseWithTransport):
def setUp(self):
super(TestStackGetWithConverter, self).setUp()
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
self.registry = config.option_registry
+ # We just want a simple stack with a simple store so we can inject
+ # whatever content the tests need without caring about what section
+ # names are valid for a given store/stack.
+ store = config.IniFileStore(self.get_transport(), 'foo.conf')
+ self.conf = config.Stack([store.get_sections], store)
def register_bool_option(self, name, default=None, default_from_env=None):
b = config.Option(name, help='A boolean.',
@@ -3722,8 +3733,7 @@
def test_simple_set(self):
conf = self.get_stack(self)
- conf.store._load_from_string('foo=bar')
- self.assertEquals('bar', conf.get('foo'))
+ self.assertEquals(None, conf.get('foo'))
conf.set('foo', 'baz')
# Did we get it back ?
self.assertEquals('baz', conf.get('foo'))
=== modified file 'bzrlib/tests/test_debug.py'
--- a/bzrlib/tests/test_debug.py 2011-08-12 16:25:56 +0000
+++ b/bzrlib/tests/test_debug.py 2011-11-16 17:19:13 +0000
@@ -34,7 +34,7 @@
def assertDebugFlags(self, expected_flags, conf_bytes):
conf = config.GlobalStack()
- conf.store._load_from_string(conf_bytes)
+ conf.store._load_from_string('[DEFAULT]\n' + conf_bytes)
conf.store.save()
self.overrideAttr(debug, 'debug_flags', set())
debug.set_debug_flags_from_config()
=== modified file 'bzrlib/tests/test_msgeditor.py'
--- a/bzrlib/tests/test_msgeditor.py 2011-06-14 01:26:41 +0000
+++ b/bzrlib/tests/test_msgeditor.py 2011-11-16 17:19:13 +0000
@@ -252,9 +252,9 @@
self.overrideEnv('VISUAL', 'visual')
self.overrideEnv('EDITOR', 'editor')
- conf = config.GlobalConfig.from_string('editor = config_editor\n',
- save=True)
-
+ conf = config.GlobalStack()
+ conf.store._load_from_string('[DEFAULT]\neditor = config_editor\n')
+ conf.store.save()
editors = list(msgeditor._get_editor())
editors = [editor for (editor, cfg_src) in editors]
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- a/doc/en/release-notes/bzr-2.5.txt 2011-11-17 14:46:42 +0000
+++ b/doc/en/release-notes/bzr-2.5.txt 2011-11-17 17:16:09 +0000
@@ -64,6 +64,9 @@
.. Major internal changes, unlikely to be visible to users or plugin
developers, but interesting for bzr developers.
+* ``bzr config`` uses the new configuration implementation.
+ (Vincent Ladeuil)
+
* New HPSS calls ``Repository.has_signature_for_revision_id`` and
``Repository.make_working_trees``. (Jelmer Vernooij)
More information about the bazaar-commits
mailing list