~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/xml8.py

  • Committer: Jelmer Vernooij
  • Date: 2010-08-28 11:19:49 UTC
  • mto: This revision was merged to the branch mainline in revision 5418.
  • Revision ID: jelmer@samba.org-20100828111949-6ke9opiop2oomr4f
Move get_config to ControlDir.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
    cache_utf8,
22
22
    errors,
23
23
    inventory,
24
 
    lazy_regex,
25
24
    revision as _mod_revision,
26
25
    trace,
27
26
    )
46
45
    ">":">",
47
46
    }
48
47
 
49
 
_xml_unescape_map = {
50
 
    'apos':"'",
51
 
    'quot':'"',
52
 
    'amp':'&',
53
 
    'lt':'<',
54
 
    'gt':'>'
55
 
}
56
 
 
57
 
 
58
 
def _unescaper(match, _map=_xml_unescape_map):
59
 
    code = match.group(1)
60
 
    try:
61
 
        return _map[code]
62
 
    except KeyError:
63
 
        if not code.startswith('#'):
64
 
            raise
65
 
        return unichr(int(code[1:])).encode('utf8')
66
 
 
67
 
 
68
 
_unescape_re = None
69
 
 
70
 
 
71
 
def _unescape_xml(data):
72
 
    """Unescape predefined XML entities in a string of data."""
73
 
    global _unescape_re
74
 
    if _unescape_re is None:
75
 
        _unescape_re = re.compile('\&([^;]*);')
76
 
    return _unescape_re.sub(_unescaper, data)
77
 
 
78
48
 
79
49
def _ensure_utf8_re():
80
50
    """Make sure the _utf8_re and _unicode_re regexes have been compiled."""
191
161
    format_num = '8'
192
162
    revision_format_num = None
193
163
 
194
 
    # The search regex used by xml based repositories to determine what things
195
 
    # where changed in a single commit.
196
 
    _file_ids_altered_regex = lazy_regex.lazy_compile(
197
 
        r'file_id="(?P<file_id>[^"]+)"'
198
 
        r'.* revision="(?P<revision_id>[^"]+)"'
199
 
        )
200
 
 
201
164
    def _check_revisions(self, inv):
202
165
        """Extension point for subclasses to check during serialisation.
203
166
 
569
532
                raise AssertionError("repeated property %r" % name)
570
533
            rev.properties[name] = value
571
534
 
572
 
    def _find_text_key_references(self, line_iterator):
573
 
        """Core routine for extracting references to texts from inventories.
574
 
 
575
 
        This performs the translation of xml lines to revision ids.
576
 
 
577
 
        :param line_iterator: An iterator of lines, origin_version_id
578
 
        :return: A dictionary mapping text keys ((fileid, revision_id) tuples)
579
 
            to whether they were referred to by the inventory of the
580
 
            revision_id that they contain. Note that if that revision_id was
581
 
            not part of the line_iterator's output then False will be given -
582
 
            even though it may actually refer to that key.
583
 
        """
584
 
        if not self.support_altered_by_hack:
585
 
            raise AssertionError(
586
 
                "_find_text_key_references only "
587
 
                "supported for branches which store inventory as unnested xml"
588
 
                ", not on %r" % self)
589
 
        result = {}
590
 
 
591
 
        # this code needs to read every new line in every inventory for the
592
 
        # inventories [revision_ids]. Seeing a line twice is ok. Seeing a line
593
 
        # not present in one of those inventories is unnecessary but not
594
 
        # harmful because we are filtering by the revision id marker in the
595
 
        # inventory lines : we only select file ids altered in one of those
596
 
        # revisions. We don't need to see all lines in the inventory because
597
 
        # only those added in an inventory in rev X can contain a revision=X
598
 
        # line.
599
 
        unescape_revid_cache = {}
600
 
        unescape_fileid_cache = {}
601
 
 
602
 
        # jam 20061218 In a big fetch, this handles hundreds of thousands
603
 
        # of lines, so it has had a lot of inlining and optimizing done.
604
 
        # Sorry that it is a little bit messy.
605
 
        # Move several functions to be local variables, since this is a long
606
 
        # running loop.
607
 
        search = self._file_ids_altered_regex.search
608
 
        unescape = _unescape_xml
609
 
        setdefault = result.setdefault
610
 
        for line, line_key in line_iterator:
611
 
            match = search(line)
612
 
            if match is None:
613
 
                continue
614
 
            # One call to match.group() returning multiple items is quite a
615
 
            # bit faster than 2 calls to match.group() each returning 1
616
 
            file_id, revision_id = match.group('file_id', 'revision_id')
617
 
 
618
 
            # Inlining the cache lookups helps a lot when you make 170,000
619
 
            # lines and 350k ids, versus 8.4 unique ids.
620
 
            # Using a cache helps in 2 ways:
621
 
            #   1) Avoids unnecessary decoding calls
622
 
            #   2) Re-uses cached strings, which helps in future set and
623
 
            #      equality checks.
624
 
            # (2) is enough that removing encoding entirely along with
625
 
            # the cache (so we are using plain strings) results in no
626
 
            # performance improvement.
627
 
            try:
628
 
                revision_id = unescape_revid_cache[revision_id]
629
 
            except KeyError:
630
 
                unescaped = unescape(revision_id)
631
 
                unescape_revid_cache[revision_id] = unescaped
632
 
                revision_id = unescaped
633
 
 
634
 
            # Note that unconditionally unescaping means that we deserialise
635
 
            # every fileid, which for general 'pull' is not great, but we don't
636
 
            # really want to have some many fulltexts that this matters anyway.
637
 
            # RBC 20071114.
638
 
            try:
639
 
                file_id = unescape_fileid_cache[file_id]
640
 
            except KeyError:
641
 
                unescaped = unescape(file_id)
642
 
                unescape_fileid_cache[file_id] = unescaped
643
 
                file_id = unescaped
644
 
 
645
 
            key = (file_id, revision_id)
646
 
            setdefault(key, False)
647
 
            if revision_id == line_key[-1]:
648
 
                result[key] = True
649
 
        return result
650
 
 
651
535
 
652
536
serializer_v8 = Serializer_v8()