~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_annotator_py.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-06 18:59:24 UTC
  • mto: This revision was merged to the branch mainline in revision 4522.
  • Revision ID: john@arbash-meinel.com-20090706185924-qlhn1j607117lgdj
Start implementing an Annotator.add_special_text functionality.

The Python implementation supports it. Basically, it is meant to allow things
like WT and PreviewTree to insert the 'current' content into the graph, so that
we can get local modifications into the annotations.
There is also some work here to get support for texts that are already cached
in the annotator. So that we avoid extracting them, and can shortcut the
history.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
    def __init__(self, vf):
36
36
        """Create a new Annotator from a VersionedFile."""
37
37
        self._vf = vf
 
38
        self._special_keys = set()
38
39
        self._parent_map = {}
39
40
        self._text_cache = {}
40
41
        # Map from key => number of nexts that will be built from this key
42
43
        self._annotations_cache = {}
43
44
        self._heads_provider = None
44
45
 
 
46
    def _update_needed_children(self, key, parent_keys):
 
47
        for parent_key in parent_keys:
 
48
            if parent_key in self._num_needed_children:
 
49
                self._num_needed_children[parent_key] += 1
 
50
            else:
 
51
                self._num_needed_children[parent_key] = 1
 
52
 
45
53
    def _get_needed_keys(self, key):
46
 
        graph = _mod_graph.Graph(self._vf)
47
 
        parent_map = {}
 
54
        """Determine the texts we need to get from the backing vf.
 
55
 
 
56
        :return: (vf_keys_needed, ann_keys_needed)
 
57
            vf_keys_needed  These are keys that we need to get from the vf
 
58
            ann_keys_needed Texts which we have in self._text_cache but we
 
59
                            don't have annotations for. We need to yield these
 
60
                            in the proper order so that we can get proper
 
61
                            annotations.
 
62
        """
 
63
        parent_map = self._parent_map
48
64
        # We need 1 extra copy of the node we will be looking at when we are
49
65
        # done
50
66
        self._num_needed_children[key] = 1
51
 
        for key, parent_keys in graph.iter_ancestry([key]):
52
 
            if parent_keys is None:
53
 
                continue
54
 
            parent_map[key] = parent_keys
55
 
            for parent_key in parent_keys:
56
 
                if parent_key in self._num_needed_children:
57
 
                    self._num_needed_children[parent_key] += 1
 
67
        vf_keys_needed = set()
 
68
        ann_keys_needed = set()
 
69
        needed_keys = set([key])
 
70
        while needed_keys:
 
71
            parent_lookup = []
 
72
            next_parent_map = {}
 
73
            for key in needed_keys:
 
74
                if key in self._parent_map:
 
75
                    # We don't need to lookup this key in the vf
 
76
                    if key not in self._text_cache:
 
77
                        # Extract this text from the vf
 
78
                        vf_keys_needed.add(key)
 
79
                    elif key not in self._annotations_cache:
 
80
                        # We do need to annotate
 
81
                        ann_keys_needed.add(key)
 
82
                        next_parent_map[key] = self._parent_map[key]
58
83
                else:
59
 
                    self._num_needed_children[parent_key] = 1
60
 
        self._parent_map.update(parent_map)
61
 
        # _heads_provider does some graph caching, so it is only valid while
62
 
        # self._parent_map hasn't changed
63
 
        self._heads_provider = None
64
 
        keys = parent_map.keys()
65
 
        return keys
 
84
                    parent_lookup.append(key)
 
85
                    vf_keys_needed.add(key)
 
86
            needed_keys = set()
 
87
            next_parent_map.update(self._vf.get_parent_map(parent_lookup))
 
88
            for key, parent_keys in next_parent_map.iteritems():
 
89
                self._update_needed_children(key, parent_keys)
 
90
                needed_keys.update([key for key in parent_keys
 
91
                                         if key not in parent_map])
 
92
            parent_map.update(next_parent_map)
 
93
            # _heads_provider does some graph caching, so it is only valid while
 
94
            # self._parent_map hasn't changed
 
95
            self._heads_provider = None
 
96
        # self._parent_map.update(parent_map)
 
97
        return vf_keys_needed, ann_keys_needed
66
98
 
67
99
    def _get_needed_texts(self, key, pb=None):
68
100
        """Get the texts we need to properly annotate key.
73
105
            matcher object we are using. Currently it is always 'lines' but
74
106
            future improvements may change this to a simple text string.
75
107
        """
76
 
        keys = self._get_needed_keys(key)
 
108
        keys, ann_keys = self._get_needed_keys(key)
77
109
        if pb is not None:
78
110
            pb.update('getting stream', 0, len(keys))
79
111
        stream  = self._vf.get_record_stream(keys, 'topological', True)
80
112
        for idx, record in enumerate(stream):
81
113
            if pb is not None:
82
114
                pb.update('extracting', 0, len(keys))
 
115
            if record.storage_kind == 'absent':
 
116
                raise errors.RevisionNotPresent(record.key, self._vf)
83
117
            this_key = record.key
84
118
            lines = osutils.chunks_to_lines(record.get_bytes_as('chunked'))
85
119
            num_lines = len(lines)
86
120
            self._text_cache[this_key] = lines
87
121
            yield this_key, lines, num_lines
 
122
        for key in ann_keys:
 
123
            lines = self._text_cache[key]
 
124
            num_lines = len(lines)
 
125
            yield key, lines, num_lines
88
126
 
89
127
    def _get_parent_annotations_and_matches(self, key, text, parent_key):
90
128
        """Get the list of annotations for the parent, and the matching lines.
186
224
                                                this_annotation, parent)
187
225
        self._record_annotation(key, parent_keys, annotations)
188
226
 
 
227
    def add_special_text(self, key, parent_keys, text):
 
228
        """Add a specific text to the graph."""
 
229
        self._special_keys.add(key)
 
230
        self._parent_map[key] = parent_keys
 
231
        self._text_cache[key] = osutils.split_lines(text)
 
232
        self._heads_provider = None
 
233
 
189
234
    def annotate(self, key):
190
235
        """Return annotated fulltext for the given key."""
191
236
        pb = ui.ui_factory.nested_progress_bar()