40
40
def annotate_file(branch, rev_id, file_id, verbose=False, full=False,
41
41
to_file=None, show_ids=False):
42
"""Annotate file_id at revision rev_id in branch.
44
The branch should already be read_locked() when annotate_file is called.
46
:param branch: The branch to look for revision numbers and history from.
47
:param rev_id: The revision id to annotate.
48
:param file_id: The file_id to annotate.
49
:param verbose: Show all details rather than truncating to ensure
50
reasonable text width.
51
:param full: XXXX Not sure what this does.
52
:param to_file: The file to output the annotation to; if None stdout is
54
:param show_ids: Show revision ids in the annotation output.
56
42
if to_file is None:
57
43
to_file = sys.stdout
168
154
the SequenceMatcher.get_matching_blocks format.
170
156
if len(parents_lines) == 0:
171
lines = [(new_revision_id, line) for line in new_lines]
157
for line in new_lines:
158
yield new_revision_id, line
172
159
elif len(parents_lines) == 1:
173
lines = _reannotate(parents_lines[0], new_lines, new_revision_id,
174
_left_matching_blocks)
175
elif len(parents_lines) == 2:
176
left = _reannotate(parents_lines[0], new_lines, new_revision_id,
177
_left_matching_blocks)
178
right = _reannotate(parents_lines[1], new_lines, new_revision_id)
180
for idx in xrange(len(new_lines)):
181
if left[idx][0] == right[idx][0]:
182
# The annotations match, just return the left one
183
lines.append(left[idx])
184
elif left[idx][0] == new_revision_id:
185
# The left parent claims a new value, return the right one
186
lines.append(right[idx])
187
elif right[idx][0] == new_revision_id:
188
# The right parent claims a new value, return the left one
189
lines.append(left[idx])
191
# Both claim different origins
192
lines.append((new_revision_id, left[idx][1]))
160
for data in _reannotate(parents_lines[0], new_lines, new_revision_id,
161
_left_matching_blocks):
194
reannotations = [_reannotate(parents_lines[0], new_lines,
195
new_revision_id, _left_matching_blocks)]
196
reannotations.extend(_reannotate(p, new_lines, new_revision_id)
197
for p in parents_lines[1:])
164
block_list = [_left_matching_blocks] + [None] * len(parents_lines)
165
reannotations = [list(_reannotate(p, new_lines, new_revision_id, b))
166
for p, b in zip(parents_lines, block_list)]
199
167
for annos in zip(*reannotations):
200
168
origins = set(a for a, l in annos)
201
170
if len(origins) == 1:
202
# All the parents agree, so just return the first one
203
lines.append(annos[0])
171
yield iter(origins).next(), line
172
elif len(origins) == 2 and new_revision_id in origins:
173
yield (x for x in origins if x != new_revision_id).next(), line
206
if len(origins) == 2 and new_revision_id in origins:
207
origins.remove(new_revision_id)
208
if len(origins) == 1:
209
lines.append((origins.pop(), line))
211
lines.append((new_revision_id, line))
175
yield new_revision_id, line
215
178
def _reannotate(parent_lines, new_lines, new_revision_id,
220
183
matcher = patiencediff.PatienceSequenceMatcher(None,
221
184
plain_parent_lines, new_lines)
222
185
matching_blocks = matcher.get_matching_blocks()
224
186
for i, j, n in matching_blocks:
225
187
for line in new_lines[new_cur:j]:
226
lines.append((new_revision_id, line))
227
lines.extend(parent_lines[i:i+n])
188
yield new_revision_id, line
189
for data in parent_lines[i:i+n]: