246
246
__contains__ = has_version
248
def get_delta(self, version_id):
249
"""See VersionedFile.get_delta."""
250
return self.get_deltas([version_id])[version_id]
252
def get_deltas(self, version_ids):
253
"""See VersionedFile.get_deltas."""
254
version_ids = self.get_ancestry(version_ids)
255
for version_id in version_ids:
256
if not self.has_version(version_id):
257
raise RevisionNotPresent(version_id, self)
258
# try extracting all versions; parallel extraction is used
259
nv = self.num_versions()
265
last_parent_lines = {}
267
parent_inclusions = {}
272
# its simplest to generate a full set of prepared variables.
274
name = self._names[i]
275
sha1s[name] = self.get_sha1(name)
276
parents_list = self.get_parents(name)
278
parent = parents_list[0]
279
parents[name] = parent
280
parent_inclusions[name] = inclusions[parent]
283
parent_inclusions[name] = set()
284
# we want to emit start, finish, replacement_length, replacement_lines tuples.
285
diff_hunks[name] = []
286
current_hunks[name] = [0, 0, 0, []] # #start, finish, repl_length, repl_tuples
287
parent_linenums[name] = 0
289
parent_noeols[name] = False
290
last_parent_lines[name] = None
291
new_inc = set([name])
292
for p in self._parents[i]:
293
new_inc.update(inclusions[self._idx_to_name(p)])
294
# debug only, known good so far.
295
#assert set(new_inc) == set(self.get_ancestry(name)), \
296
# 'failed %s != %s' % (set(new_inc), set(self.get_ancestry(name)))
297
inclusions[name] = new_inc
299
nlines = len(self._weave)
301
for lineno, inserted, deletes, line in self._walk_internal():
302
# a line is active in a version if:
303
# insert is in the versions inclusions
305
# deleteset & the versions inclusions is an empty set.
306
# so - if we have a included by mapping - version is included by
307
# children, we get a list of children to examine for deletes affect
308
# ing them, which is less than the entire set of children.
309
for version_id in version_ids:
310
# The active inclusion must be an ancestor,
311
# and no ancestors must have deleted this line,
312
# because we don't support resurrection.
313
parent_inclusion = parent_inclusions[version_id]
314
inclusion = inclusions[version_id]
315
parent_active = inserted in parent_inclusion and not (deletes & parent_inclusion)
316
version_active = inserted in inclusion and not (deletes & inclusion)
317
if not parent_active and not version_active:
318
# unrelated line of ancestry
320
elif parent_active and version_active:
322
parent_linenum = parent_linenums[version_id]
323
if current_hunks[version_id] != [parent_linenum, parent_linenum, 0, []]:
324
diff_hunks[version_id].append(tuple(current_hunks[version_id]))
326
current_hunks[version_id] = [parent_linenum, parent_linenum, 0, []]
327
parent_linenums[version_id] = parent_linenum
330
noeols[version_id] = True
333
elif parent_active and not version_active:
335
current_hunks[version_id][1] += 1
336
parent_linenums[version_id] += 1
337
last_parent_lines[version_id] = line
338
elif not parent_active and version_active:
340
# noeol only occurs at the end of a file because we
341
# diff linewise. We want to show noeol changes as a
342
# empty diff unless the actual eol-less content changed.
345
if last_parent_lines[version_id][-1] != '\n':
346
parent_noeols[version_id] = True
347
except (TypeError, IndexError):
350
if theline[-1] != '\n':
351
noeols[version_id] = True
355
parent_should_go = False
357
if parent_noeols[version_id] == noeols[version_id]:
358
# no noeol toggle, so trust the weaves statement
359
# that this line is changed.
361
if parent_noeols[version_id]:
362
theline = theline + '\n'
363
elif parent_noeols[version_id]:
364
# parent has no eol, we do:
365
# our line is new, report as such..
367
elif noeols[version_id]:
368
# append a eol so that it looks like
370
theline = theline + '\n'
371
if parents[version_id] is not None:
372
#if last_parent_lines[version_id] is not None:
373
parent_should_go = True
374
if last_parent_lines[version_id] != theline:
377
#parent_should_go = False
379
current_hunks[version_id][2] += 1
380
current_hunks[version_id][3].append((inserted, theline))
382
# last hunk last parent line is not eaten
383
current_hunks[version_id][1] -= 1
384
if current_hunks[version_id][1] < 0:
385
current_hunks[version_id][1] = 0
386
# import pdb;pdb.set_trace()
387
# assert current_hunks[version_id][1] >= 0
391
version = self._idx_to_name(i)
392
if current_hunks[version] != [0, 0, 0, []]:
393
diff_hunks[version].append(tuple(current_hunks[version]))
395
for version_id in version_ids:
396
result[version_id] = (
400
diff_hunks[version_id],
404
248
def get_parents(self, version_id):
405
249
"""See VersionedFile.get_parent."""
406
250
return map(self._idx_to_name, self._parents[self._lookup(version_id)])
419
263
def _add_lines(self, version_id, parents, lines, parent_texts,
420
left_matching_blocks=None):
264
left_matching_blocks, nostore_sha):
421
265
"""See VersionedFile.add_lines."""
422
idx = self._add(version_id, lines, map(self._lookup, parents))
266
idx = self._add(version_id, lines, map(self._lookup, parents),
267
nostore_sha=nostore_sha)
423
268
return sha_strings(lines), sum(map(len, lines)), idx
425
def _add(self, version_id, lines, parents, sha1=None):
270
def _add(self, version_id, lines, parents, sha1=None, nostore_sha=None):
426
271
"""Add a single text on top of the weave.
428
273
Returns the index number of the newly added version.