261
261
__contains__ = has_version
263
def get_delta(self, version_id):
264
"""See VersionedFile.get_delta."""
265
return self.get_deltas([version_id])[version_id]
267
def get_deltas(self, version_ids):
268
"""See VersionedFile.get_deltas."""
269
version_ids = self.get_ancestry(version_ids)
270
for version_id in version_ids:
271
if not self.has_version(version_id):
272
raise RevisionNotPresent(version_id, self)
273
# try extracting all versions; parallel extraction is used
274
nv = self.num_versions()
280
last_parent_lines = {}
282
parent_inclusions = {}
287
# its simplest to generate a full set of prepared variables.
289
name = self._names[i]
290
sha1s[name] = self.get_sha1(name)
291
parents_list = self.get_parents(name)
293
parent = parents_list[0]
294
parents[name] = parent
295
parent_inclusions[name] = inclusions[parent]
298
parent_inclusions[name] = set()
299
# we want to emit start, finish, replacement_length, replacement_lines tuples.
300
diff_hunks[name] = []
301
current_hunks[name] = [0, 0, 0, []] # #start, finish, repl_length, repl_tuples
302
parent_linenums[name] = 0
304
parent_noeols[name] = False
305
last_parent_lines[name] = None
306
new_inc = set([name])
307
for p in self._parents[i]:
308
new_inc.update(inclusions[self._idx_to_name(p)])
309
# debug only, known good so far.
310
#assert set(new_inc) == set(self.get_ancestry(name)), \
311
# 'failed %s != %s' % (set(new_inc), set(self.get_ancestry(name)))
312
inclusions[name] = new_inc
314
nlines = len(self._weave)
316
for lineno, inserted, deletes, line in self._walk_internal():
317
# a line is active in a version if:
318
# insert is in the versions inclusions
320
# deleteset & the versions inclusions is an empty set.
321
# so - if we have a included by mapping - version is included by
322
# children, we get a list of children to examine for deletes affect
323
# ing them, which is less than the entire set of children.
324
for version_id in version_ids:
325
# The active inclusion must be an ancestor,
326
# and no ancestors must have deleted this line,
327
# because we don't support resurrection.
328
parent_inclusion = parent_inclusions[version_id]
329
inclusion = inclusions[version_id]
330
parent_active = inserted in parent_inclusion and not (deletes & parent_inclusion)
331
version_active = inserted in inclusion and not (deletes & inclusion)
332
if not parent_active and not version_active:
333
# unrelated line of ancestry
335
elif parent_active and version_active:
337
parent_linenum = parent_linenums[version_id]
338
if current_hunks[version_id] != [parent_linenum, parent_linenum, 0, []]:
339
diff_hunks[version_id].append(tuple(current_hunks[version_id]))
341
current_hunks[version_id] = [parent_linenum, parent_linenum, 0, []]
342
parent_linenums[version_id] = parent_linenum
345
noeols[version_id] = True
348
elif parent_active and not version_active:
350
current_hunks[version_id][1] += 1
351
parent_linenums[version_id] += 1
352
last_parent_lines[version_id] = line
353
elif not parent_active and version_active:
355
# noeol only occurs at the end of a file because we
356
# diff linewise. We want to show noeol changes as a
357
# empty diff unless the actual eol-less content changed.
360
if last_parent_lines[version_id][-1] != '\n':
361
parent_noeols[version_id] = True
362
except (TypeError, IndexError):
365
if theline[-1] != '\n':
366
noeols[version_id] = True
370
parent_should_go = False
372
if parent_noeols[version_id] == noeols[version_id]:
373
# no noeol toggle, so trust the weaves statement
374
# that this line is changed.
376
if parent_noeols[version_id]:
377
theline = theline + '\n'
378
elif parent_noeols[version_id]:
379
# parent has no eol, we do:
380
# our line is new, report as such..
382
elif noeols[version_id]:
383
# append a eol so that it looks like
385
theline = theline + '\n'
386
if parents[version_id] is not None:
387
#if last_parent_lines[version_id] is not None:
388
parent_should_go = True
389
if last_parent_lines[version_id] != theline:
392
#parent_should_go = False
394
current_hunks[version_id][2] += 1
395
current_hunks[version_id][3].append((inserted, theline))
397
# last hunk last parent line is not eaten
398
current_hunks[version_id][1] -= 1
399
if current_hunks[version_id][1] < 0:
400
current_hunks[version_id][1] = 0
401
# import pdb;pdb.set_trace()
402
# assert current_hunks[version_id][1] >= 0
406
version = self._idx_to_name(i)
407
if current_hunks[version] != [0, 0, 0, []]:
408
diff_hunks[version].append(tuple(current_hunks[version]))
410
for version_id in version_ids:
411
result[version_id] = (
415
diff_hunks[version_id],
263
419
def get_parents(self, version_id):
264
420
"""See VersionedFile.get_parent."""
265
421
return map(self._idx_to_name, self._parents[self._lookup(version_id)])
580
737
WFE = WeaveFormatError
740
# 449 0 4474.6820 2356.5590 bzrlib.weave:556(_extract)
741
# +285282 0 1676.8040 1676.8040 +<isinstance>
742
# 1.6 seconds in 'isinstance'.
743
# changing the first isinstance:
744
# 449 0 2814.2660 1577.1760 bzrlib.weave:556(_extract)
745
# +140414 0 762.8050 762.8050 +<isinstance>
746
# note that the inline time actually dropped (less function calls)
747
# and total processing time was halved.
748
# we're still spending ~1/4 of the method in isinstance though.
749
# so lets hard code the acceptable string classes we expect:
750
# 449 0 1202.9420 786.2930 bzrlib.weave:556(_extract)
751
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
753
# yay, down to ~1/4 the initial extract time, and our inline time
754
# has shrunk again, with isinstance no longer dominating.
755
# tweaking the stack inclusion test to use a set gives:
756
# 449 0 1122.8030 713.0080 bzrlib.weave:556(_extract)
757
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
759
# - a 5% win, or possibly just noise. However with large istacks that
760
# 'in' test could dominate, so I'm leaving this change in place -
761
# when its fast enough to consider profiling big datasets we can review.
582
766
for l in self._weave:
583
if isinstance(l, tuple):
767
if l.__class__ == tuple:
587
assert v not in istack
775
iset.remove(istack.pop())
592
777
if v in included:
593
778
assert v not in dset
636
821
return self._lookup(name_or_index)
638
def _get_iter(self, version_id):
639
"""Yield lines for the specified version."""
640
incls = [self._maybe_lookup(version_id)]
645
# We don't have sha1 sums for multiple entries
647
for origin, lineno, line in self._extract(incls):
652
expected_sha1 = self._sha1s[index]
653
measured_sha1 = cur_sha.hexdigest()
654
if measured_sha1 != expected_sha1:
655
raise errors.WeaveInvalidChecksum(
656
'file %s, revision %s, expected: %s, measured %s'
657
% (self._weave_name, self._names[index],
658
expected_sha1, measured_sha1))
660
823
@deprecated_method(zero_eight)
661
824
def get(self, version_id):
662
825
"""Please use either Weave.get_text or Weave.get_lines as desired."""