~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Jelmer Vernooij
  • Date: 2011-04-15 10:31:18 UTC
  • mfrom: (5786 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5787.
  • Revision ID: jelmer@samba.org-20110415103118-70384bxb040x5z3t
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
967
967
        super(LockableConfig, self).remove_user_option(option_name,
968
968
                                                       section_name)
969
969
 
 
970
def _iter_for_location_by_parts(sections, location):
 
971
    """Keep only the sessions matching the specified location.
 
972
 
 
973
    :param sections: An iterable of section names.
 
974
 
 
975
    :param location: An url or a local path to match against.
 
976
 
 
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
 
980
        name.
 
981
    """
 
982
    location_parts = location.rstrip('/').split('/')
 
983
 
 
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.
 
987
 
 
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
 
990
 
 
991
        # This also avoids having file:///path be a more exact
 
992
        # match than '/path'.
 
993
 
 
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
 
1000
 
 
1001
        if section.startswith('file://'):
 
1002
            section_path = urlutils.local_path_from_url(section)
 
1003
        else:
 
1004
            section_path = section
 
1005
        section_parts = section_path.rstrip('/').split('/')
 
1006
 
 
1007
        matched = True
 
1008
        if len(section_parts) > len(location_parts):
 
1009
            # More path components in the section, they can't match
 
1010
            matched = False
 
1011
        else:
 
1012
            # Rely on zip truncating in length to the length of the shortest
 
1013
            # argument sequence.
 
1014
            names = zip(location_parts, section_parts)
 
1015
            for name in names:
 
1016
                if not fnmatch.fnmatch(name[0], name[1]):
 
1017
                    matched = False
 
1018
                    break
 
1019
        if not matched:
 
1020
            continue
 
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)
 
1024
 
970
1025
 
971
1026
class LocationConfig(LockableConfig):
972
1027
    """A configuration object that gives the policy for a location."""
1001
1056
 
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]
1008
 
        matches=[]
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)
1016
 
            else:
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)
1022
 
            matched = True
1023
 
            for name in names:
1024
 
                if not fnmatch.fnmatch(name[0], name[1]):
1025
 
                    matched = False
1026
 
                    break
1027
 
            if not matched:
1028
 
                continue
1029
 
            # so, for the common prefix they matched.
1030
 
            # if section is longer, no match.
1031
 
            if len(section_names) > len(location_names):
1032
 
                continue
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(),
 
1060
                                                   self.location))
1035
1061
        # put the longest (aka more specific) locations first
1036
 
        matches.sort(reverse=True)
1037
 
        sections = []
1038
 
        for (length, section, extra_path) in matches:
1039
 
            sections.append((section, extra_path))
 
1062
        matches.sort(
 
1063
            key=lambda (section, extra_path, length): (length, section),
 
1064
            reverse=True)
 
1065
        for (section, extra_path, length) in matches:
 
1066
            yield section, extra_path
1040
1067
            # should we stop looking for parent configs here?
1041
1068
            try:
1042
1069
                if self._get_parser()[section].as_bool('ignore_parents'):
1043
1070
                    break
1044
1071
            except KeyError:
1045
1072
                pass
1046
 
        return sections
1047
1073
 
1048
1074
    def _get_sections(self, name=None):
1049
1075
        """See IniBasedConfig._get_sections()."""