967
967
super(LockableConfig, self).remove_user_option(option_name,
970
def _iter_for_location_by_parts(sections, location):
971
"""Keep only the sessions matching the specified location.
973
:param sections: An iterable of section names.
975
:param location: An url or a local path to match against.
977
:returns: An iterator of (section, extra_path, nb_parts) where nb is the
978
number of path components in the section name, section is the section
979
name and extra_path is the difference between location and the section
982
location_parts = location.rstrip('/').split('/')
984
for section in sections:
985
# location is a local path if possible, so we need
986
# to convert 'file://' urls to local paths if necessary.
988
# FIXME: I don't think the above comment is still up to date,
989
# LocationConfig is always instantiated with an url -- vila 2011-04-07
991
# This also avoids having file:///path be a more exact
992
# match than '/path'.
994
# FIXME: Not sure about the above either, but since the path components
995
# are compared in sync, adding two empty components (//) is likely to
996
# trick the comparison and also trick the check on the number of
997
# components, so we *should* take only the relevant part of the url. On
998
# the other hand, this means 'file://' urls *can't* be used in sections
999
# so more work is probably needed -- vila 2011-04-07
1001
if section.startswith('file://'):
1002
section_path = urlutils.local_path_from_url(section)
1004
section_path = section
1005
section_parts = section_path.rstrip('/').split('/')
1008
if len(section_parts) > len(location_parts):
1009
# More path components in the section, they can't match
1012
# Rely on zip truncating in length to the length of the shortest
1013
# argument sequence.
1014
names = zip(location_parts, section_parts)
1016
if not fnmatch.fnmatch(name[0], name[1]):
1021
# build the path difference between the section and the location
1022
extra_path = '/'.join(location_parts[len(section_parts):])
1023
yield section, extra_path, len(section_parts)
971
1026
class LocationConfig(LockableConfig):
972
1027
"""A configuration object that gives the policy for a location."""
1002
1057
def _get_matching_sections(self):
1003
1058
"""Return an ordered list of section names matching this location."""
1004
sections = self._get_parser()
1005
location_names = self.location.split('/')
1006
if self.location.endswith('/'):
1007
del location_names[-1]
1009
for section in sections:
1010
# location is a local path if possible, so we need
1011
# to convert 'file://' urls to local paths if necessary.
1012
# This also avoids having file:///path be a more exact
1013
# match than '/path'.
1014
if section.startswith('file://'):
1015
section_path = urlutils.local_path_from_url(section)
1017
section_path = section
1018
section_names = section_path.split('/')
1019
if section.endswith('/'):
1020
del section_names[-1]
1021
names = zip(location_names, section_names)
1024
if not fnmatch.fnmatch(name[0], name[1]):
1029
# so, for the common prefix they matched.
1030
# if section is longer, no match.
1031
if len(section_names) > len(location_names):
1033
matches.append((len(section_names), section,
1034
'/'.join(location_names[len(section_names):])))
1059
matches = list(_iter_for_location_by_parts(self._get_parser(),
1035
1061
# put the longest (aka more specific) locations first
1036
matches.sort(reverse=True)
1038
for (length, section, extra_path) in matches:
1039
sections.append((section, extra_path))
1063
key=lambda (section, extra_path, length): (length, section),
1065
for (section, extra_path, length) in matches:
1066
yield section, extra_path
1040
1067
# should we stop looking for parent configs here?
1042
1069
if self._get_parser()[section].as_bool('ignore_parents'):
1044
1071
except KeyError:
1048
1074
def _get_sections(self, name=None):
1049
1075
"""See IniBasedConfig._get_sections()."""