Rev 5785: (jelmer) Clarify and split up LocationConfig._get_matching_sections. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Thu Apr 14 12:25:51 UTC 2011
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 5785 [merge]
revision-id: pqm at pqm.ubuntu.com-20110414122541-7taevmis2q3cjcur
parent: pqm at pqm.ubuntu.com-20110412235648-ezdrtqmgxot1ont2
parent: v.ladeuil+lp at free.fr-20110409200111-c5ivo0e8yl7tj23r
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2011-04-14 12:25:41 +0000
message:
(jelmer) Clarify and split up LocationConfig._get_matching_sections.
(Vincent Ladeuil)
modified:
bzrlib/config.py config.py-20051011043216-070c74f4e9e338e8
bzrlib/tests/test_config.py testconfig.py-20051011041908-742d0c15d8d8c8eb
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py 2011-04-05 14:47:26 +0000
+++ b/bzrlib/config.py 2011-04-09 20:01:11 +0000
@@ -967,6 +967,61 @@
super(LockableConfig, self).remove_user_option(option_name,
section_name)
+def _iter_for_location_by_parts(sections, location):
+ """Keep only the sessions matching the specified location.
+
+ :param sections: An iterable of section names.
+
+ :param location: An url or a local path to match against.
+
+ :returns: An iterator of (section, extra_path, nb_parts) where nb is the
+ number of path components in the section name, section is the section
+ name and extra_path is the difference between location and the section
+ name.
+ """
+ location_parts = location.rstrip('/').split('/')
+
+ for section in sections:
+ # location is a local path if possible, so we need
+ # to convert 'file://' urls to local paths if necessary.
+
+ # FIXME: I don't think the above comment is still up to date,
+ # LocationConfig is always instantiated with an url -- vila 2011-04-07
+
+ # This also avoids having file:///path be a more exact
+ # match than '/path'.
+
+ # FIXME: Not sure about the above either, but since the path components
+ # are compared in sync, adding two empty components (//) is likely to
+ # trick the comparison and also trick the check on the number of
+ # components, so we *should* take only the relevant part of the url. On
+ # the other hand, this means 'file://' urls *can't* be used in sections
+ # so more work is probably needed -- vila 2011-04-07
+
+ if section.startswith('file://'):
+ section_path = urlutils.local_path_from_url(section)
+ else:
+ section_path = section
+ section_parts = section_path.rstrip('/').split('/')
+
+ matched = True
+ if len(section_parts) > len(location_parts):
+ # More path components in the section, they can't match
+ matched = False
+ else:
+ # Rely on zip truncating in length to the length of the shortest
+ # argument sequence.
+ names = zip(location_parts, section_parts)
+ for name in names:
+ if not fnmatch.fnmatch(name[0], name[1]):
+ matched = False
+ break
+ if not matched:
+ continue
+ # build the path difference between the section and the location
+ extra_path = '/'.join(location_parts[len(section_parts):])
+ yield section, extra_path, len(section_parts)
+
class LocationConfig(LockableConfig):
"""A configuration object that gives the policy for a location."""
@@ -1001,49 +1056,20 @@
def _get_matching_sections(self):
"""Return an ordered list of section names matching this location."""
- sections = self._get_parser()
- location_names = self.location.split('/')
- if self.location.endswith('/'):
- del location_names[-1]
- matches=[]
- for section in sections:
- # location is a local path if possible, so we need
- # to convert 'file://' urls to local paths if necessary.
- # This also avoids having file:///path be a more exact
- # match than '/path'.
- if section.startswith('file://'):
- section_path = urlutils.local_path_from_url(section)
- else:
- section_path = section
- section_names = section_path.split('/')
- if section.endswith('/'):
- del section_names[-1]
- names = zip(location_names, section_names)
- matched = True
- for name in names:
- if not fnmatch.fnmatch(name[0], name[1]):
- matched = False
- break
- if not matched:
- continue
- # so, for the common prefix they matched.
- # if section is longer, no match.
- if len(section_names) > len(location_names):
- continue
- matches.append((len(section_names), section,
- '/'.join(location_names[len(section_names):])))
+ matches = list(_iter_for_location_by_parts(self._get_parser(),
+ self.location))
# put the longest (aka more specific) locations first
- matches.sort(reverse=True)
- sections = []
- for (length, section, extra_path) in matches:
- sections.append((section, extra_path))
+ matches.sort(
+ key=lambda (section, extra_path, length): (length, section),
+ reverse=True)
+ for (section, extra_path, length) in matches:
+ yield section, extra_path
# should we stop looking for parent configs here?
try:
if self._get_parser()[section].as_bool('ignore_parents'):
break
except KeyError:
pass
- return sections
def _get_sections(self, name=None):
"""See IniBasedConfig._get_sections()."""
=== modified file 'bzrlib/tests/test_config.py'
--- a/bzrlib/tests/test_config.py 2011-04-05 12:11:26 +0000
+++ b/bzrlib/tests/test_config.py 2011-04-09 20:01:11 +0000
@@ -1264,55 +1264,52 @@
self.failUnless(isinstance(global_config, config.GlobalConfig))
self.failUnless(global_config is my_config._get_global_config())
+ def assertLocationMatching(self, expected):
+ self.assertEqual(expected,
+ list(self.my_location_config._get_matching_sections()))
+
def test__get_matching_sections_no_match(self):
self.get_branch_config('/')
- self.assertEqual([], self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([])
def test__get_matching_sections_exact(self):
self.get_branch_config('http://www.example.com')
- self.assertEqual([('http://www.example.com', '')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('http://www.example.com', '')])
def test__get_matching_sections_suffix_does_not(self):
self.get_branch_config('http://www.example.com-com')
- self.assertEqual([], self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([])
def test__get_matching_sections_subdir_recursive(self):
self.get_branch_config('http://www.example.com/com')
- self.assertEqual([('http://www.example.com', 'com')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('http://www.example.com', 'com')])
def test__get_matching_sections_ignoreparent(self):
self.get_branch_config('http://www.example.com/ignoreparent')
- self.assertEqual([('http://www.example.com/ignoreparent', '')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('http://www.example.com/ignoreparent',
+ '')])
def test__get_matching_sections_ignoreparent_subdir(self):
self.get_branch_config(
'http://www.example.com/ignoreparent/childbranch')
- self.assertEqual([('http://www.example.com/ignoreparent',
- 'childbranch')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('http://www.example.com/ignoreparent',
+ 'childbranch')])
def test__get_matching_sections_subdir_trailing_slash(self):
self.get_branch_config('/b')
- self.assertEqual([('/b/', '')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('/b/', '')])
def test__get_matching_sections_subdir_child(self):
self.get_branch_config('/a/foo')
- self.assertEqual([('/a/*', ''), ('/a/', 'foo')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('/a/*', ''), ('/a/', 'foo')])
def test__get_matching_sections_subdir_child_child(self):
self.get_branch_config('/a/foo/bar')
- self.assertEqual([('/a/*', 'bar'), ('/a/', 'foo/bar')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('/a/*', 'bar'), ('/a/', 'foo/bar')])
def test__get_matching_sections_trailing_slash_with_children(self):
self.get_branch_config('/a/')
- self.assertEqual([('/a/', '')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('/a/', '')])
def test__get_matching_sections_explicit_over_glob(self):
# XXX: 2006-09-08 jamesh
@@ -1320,8 +1317,7 @@
# was a config section for '/a/?', it would get precedence
# over '/a/c'.
self.get_branch_config('/a/c')
- self.assertEqual([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')],
- self.my_location_config._get_matching_sections())
+ self.assertLocationMatching([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')])
def test__get_option_policy_normal(self):
self.get_branch_config('http://www.example.com')
More information about the bazaar-commits
mailing list