265
267
stored and retrieved.
268
def __init__(self, relpath, transport, file_mode=None, access_mode=None, factory=None,
269
basis_knit=None, delta=True, create=False):
270
def __init__(self, relpath, transport, file_mode=None, access_mode=None,
271
factory=None, basis_knit=None, delta=True, create=False):
270
272
"""Construct a knit at location specified by relpath.
272
274
:param create: If not True, only open an existing knit.
510
512
diff_hunks.append((op[1], op[2], op[4]-op[3], new_content._lines[op[3]:op[4]]))
511
513
return diff_hunks
515
def _get_component_versions(self, version_id):
516
basis = self.basis_knit
523
if basis and basis._index.has_version(cursor):
525
basis_versions.append(cursor)
526
method = picked_knit._index.get_method(cursor)
527
needed_versions.append((method, cursor))
528
if method == 'fulltext':
530
cursor = picked_knit.get_parents(cursor)[0]
531
return needed_versions, basis_versions
533
def _get_component_positions(self, version_id):
534
needed_versions, basis_versions = \
535
self._get_component_versions(version_id)
536
assert len(basis_versions) == 0
538
for method, comp_id in needed_versions:
539
data_pos, data_size = self._index.get_position(comp_id)
540
positions.append((method, comp_id, data_pos, data_size))
513
543
def _get_components(self, version_id):
514
544
"""Return a list of (version_id, method, data) tuples that
515
545
makes up version specified by version_id of the knit.
533
563
# basis_revisions is a list of versions that needs to be
534
564
# fetched but exists in the basis knit.
536
basis = self.basis_knit
543
if basis and basis._index.has_version(cursor):
545
basis_versions.append(cursor)
546
method = picked_knit._index.get_method(cursor)
547
needed_versions.append((method, cursor))
548
if method == 'fulltext':
550
cursor = picked_knit.get_parents(cursor)[0]
566
needed_versions, basis_versions = \
567
self._get_component_versions(version_id)
553
570
if basis_versions:
571
assert False, "I am broken"
572
basis = self.basis_knit
555
574
for comp_id in basis_versions:
556
575
data_pos, data_size = basis._index.get_data_position(comp_id)
718
736
def _clone_text(self, new_version_id, old_version_id, parents):
719
737
"""See VersionedFile.clone_text()."""
720
# FIXME RBC 20060228 make fast by only inserting an index with null delta.
738
# FIXME RBC 20060228 make fast by only inserting an index with null
721
740
self.add_lines(new_version_id, parents, self.get_lines(old_version_id))
723
742
def get_lines(self, version_id):
724
743
"""See VersionedFile.get_lines()."""
725
return self._get_content(version_id).text()
744
return self.get_line_list([version_id])[0]
746
def _get_version_components(self, position_map):
748
for version_id, positions in position_map.iteritems():
749
for method, comp_id, position, size in positions:
750
records.append((comp_id, position, size))
751
record_map = self._data.read_records(records)
754
for version_id, positions in position_map.iteritems():
756
for method, comp_id, position, size in positions:
757
data, digest = record_map[comp_id]
758
components.append((comp_id, method, data, digest))
759
component_map[version_id] = components
762
def get_text(self, version_id):
763
"""See VersionedFile.get_text"""
764
return self.get_texts([version_id])[0]
766
def get_texts(self, version_ids):
767
return [''.join(l) for l in self.get_line_list(version_ids)]
769
def get_line_list(self, version_ids):
770
"""Return the texts of listed versions as a list of strings."""
772
for version_id in version_ids:
773
if not self.has_version(version_id):
774
raise RevisionNotPresent(version_id, self.filename)
775
position_map[version_id] = \
776
self._get_component_positions(version_id)
778
version_components = self._get_version_components(position_map).items()
781
for version_id, components in version_components:
783
for component_id, method, data, digest in reversed(components):
784
version_idx = self._index.lookup(component_id)
785
if method == 'fulltext':
786
assert content is None
787
content = self.factory.parse_fulltext(data, version_idx)
788
elif method == 'line-delta':
789
delta = self.factory.parse_line_delta(data, version_idx)
790
content._lines = self._apply_delta(content._lines, delta)
792
if 'no-eol' in self._index.get_options(version_id):
793
line = content._lines[-1][1].rstrip('\n')
794
content._lines[-1] = (content._lines[-1][0], line)
796
# digest here is the digest from the last applied component.
797
if sha_strings(content.text()) != digest:
798
raise KnitCorrupt(self.filename,
799
'sha-1 does not match %s' % version_id)
801
text_map[version_id] = content.text()
802
return [text_map[v] for v in version_ids]
727
804
def iter_lines_added_or_present_in_versions(self, version_ids=None):
728
805
"""See VersionedFile.iter_lines_added_or_present_in_versions()."""
1373
1450
needed_records.append((version_id, pos, size))
1375
1452
if len(needed_records):
1453
needed_records.sort(key=operator.itemgetter(1))
1376
1454
# We take it that the transport optimizes the fetching as good
1377
1455
# as possible (ie, reads continuous ranges.)
1378
1456
response = self._transport.readv(self._filename,
1379
1457
[(pos, size) for version_id, pos, size in needed_records])
1381
for (record_id, pos, size), (pos, data) in izip(iter(needed_records), response):
1459
for (record_id, pos, size), (pos, data) in \
1460
izip(iter(needed_records), response):
1382
1461
content, digest = self._parse_record(record_id, data)
1383
1462
self._records[record_id] = (digest, content)