86
77
"""Returns whether version is present."""
87
78
raise NotImplementedError(self.has_version)
89
def add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
90
"""Add a text to the versioned file via a pregenerated delta.
92
:param version_id: The version id being added.
93
:param parents: The parents of the version_id.
94
:param delta_parent: The parent this delta was created against.
95
:param sha1: The sha1 of the full text.
96
:param delta: The delta instructions. See get_delta for details.
98
version_id = osutils.safe_revision_id(version_id)
99
parents = [osutils.safe_revision_id(v) for v in parents]
100
self._check_write_ok()
101
if self.has_version(version_id):
102
raise errors.RevisionAlreadyPresent(version_id, self)
103
return self._add_delta(version_id, parents, delta_parent, sha1, noeol, delta)
105
def _add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
106
"""Class specific routine to add a delta.
108
This generic version simply applies the delta to the delta_parent and
111
# strip annotation from delta
113
for start, stop, delta_len, delta_lines in delta:
114
new_delta.append((start, stop, delta_len, [text for origin, text in delta_lines]))
115
if delta_parent is not None:
116
parent_full = self.get_lines(delta_parent)
119
new_full = self._apply_delta(parent_full, new_delta)
120
# its impossible to have noeol on an empty file
121
if noeol and new_full[-1][-1] == '\n':
122
new_full[-1] = new_full[-1][:-1]
123
self.add_lines(version_id, parents, new_full)
125
def add_lines(self, version_id, parents, lines, parent_texts=None):
80
def add_lines(self, version_id, parents, lines, parent_texts=None,
81
left_matching_blocks=None, nostore_sha=None, random_id=False,
126
83
"""Add a single text on top of the versioned file.
128
85
Must raise RevisionAlreadyPresent if the new version is
131
88
Must raise RevisionNotPresent if any of the given parents are
132
89
not present in file history.
91
:param lines: A list of lines. Each line must be a bytestring. And all
92
of them except the last must be terminated with \n and contain no
93
other \n's. The last line may either contain no \n's or a single
94
terminated \n. If the lines list does meet this constraint the add
95
routine may error or may succeed - but you will be unable to read
96
the data back accurately. (Checking the lines have been split
97
correctly is expensive and extremely unlikely to catch bugs so it
98
is not done at runtime unless check_content is True.)
133
99
:param parent_texts: An optional dictionary containing the opaque
134
representations of some or all of the parents of
135
version_id to allow delta optimisations.
136
VERY IMPORTANT: the texts must be those returned
137
by add_lines or data corruption can be caused.
138
:return: An opaque representation of the inserted version which can be
139
provided back to future add_lines calls in the parent_texts
100
representations of some or all of the parents of version_id to
101
allow delta optimisations. VERY IMPORTANT: the texts must be those
102
returned by add_lines or data corruption can be caused.
103
:param left_matching_blocks: a hint about which areas are common
104
between the text and its left-hand-parent. The format is
105
the SequenceMatcher.get_matching_blocks format.
106
:param nostore_sha: Raise ExistingContent and do not add the lines to
107
the versioned file if the digest of the lines matches this.
108
:param random_id: If True a random id has been selected rather than
109
an id determined by some deterministic process such as a converter
110
from a foreign VCS. When True the backend may choose not to check
111
for uniqueness of the resulting key within the versioned file, so
112
this should only be done when the result is expected to be unique
114
:param check_content: If True, the lines supplied are verified to be
115
bytestrings that are correctly formed lines.
116
:return: The text sha1, the number of bytes in the text, and an opaque
117
representation of the inserted version which can be provided
118
back to future add_lines calls in the parent_texts dictionary.
142
120
version_id = osutils.safe_revision_id(version_id)
143
121
parents = [osutils.safe_revision_id(v) for v in parents]
144
122
self._check_write_ok()
145
return self._add_lines(version_id, parents, lines, parent_texts)
123
return self._add_lines(version_id, parents, lines, parent_texts,
124
left_matching_blocks, nostore_sha, random_id, check_content)
147
def _add_lines(self, version_id, parents, lines, parent_texts):
126
def _add_lines(self, version_id, parents, lines, parent_texts,
127
left_matching_blocks, nostore_sha, random_id, check_content):
148
128
"""Helper to do the class specific add_lines."""
149
129
raise NotImplementedError(self.add_lines)
151
131
def add_lines_with_ghosts(self, version_id, parents, lines,
132
parent_texts=None, nostore_sha=None, random_id=False,
153
134
"""Add lines to the versioned file, allowing ghosts to be present.
155
This takes the same parameters as add_lines.
136
This takes the same parameters as add_lines and returns the same.
157
138
version_id = osutils.safe_revision_id(version_id)
158
139
parents = [osutils.safe_revision_id(v) for v in parents]
159
140
self._check_write_ok()
160
141
return self._add_lines_with_ghosts(version_id, parents, lines,
142
parent_texts, nostore_sha, random_id, check_content)
163
def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts):
144
def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts,
145
nostore_sha, random_id, check_content):
164
146
"""Helper to do class specific add_lines_with_ghosts."""
165
147
raise NotImplementedError(self.add_lines_with_ghosts)
244
226
"""Helper for fix_parents."""
245
227
raise NotImplementedError(self.fix_parents)
247
def get_delta(self, version):
248
"""Get a delta for constructing version from some other version.
250
:return: (delta_parent, sha1, noeol, delta)
251
Where delta_parent is a version id or None to indicate no parent.
253
raise NotImplementedError(self.get_delta)
255
def get_deltas(self, version_ids):
256
"""Get multiple deltas at once for constructing versions.
258
:return: dict(version_id:(delta_parent, sha1, noeol, delta))
259
Where delta_parent is a version id or None to indicate no parent, and
260
version_id is the version_id created by that delta.
263
for version_id in version_ids:
264
result[version_id] = self.get_delta(version_id)
229
def get_format_signature(self):
230
"""Get a text description of the data encoding in this file.
234
raise NotImplementedError(self.get_format_signature)
236
def make_mpdiffs(self, version_ids):
237
"""Create multiparent diffs for specified versions"""
238
knit_versions = set()
239
for version_id in version_ids:
240
knit_versions.add(version_id)
241
knit_versions.update(self.get_parents(version_id))
242
lines = dict(zip(knit_versions,
243
self._get_lf_split_line_list(knit_versions)))
245
for version_id in version_ids:
246
target = lines[version_id]
247
parents = [lines[p] for p in self.get_parents(version_id)]
249
left_parent_blocks = self._extract_blocks(version_id,
252
left_parent_blocks = None
253
diffs.append(multiparent.MultiParent.from_lines(target, parents,
257
def _extract_blocks(self, version_id, source, target):
260
def add_mpdiffs(self, records):
261
"""Add mpdiffs to this versionedfile
263
Records should be iterables of version, parents, expected_sha1,
264
mpdiff. mpdiff should be a MultiParent instance.
267
mpvf = multiparent.MultiMemoryVersionedFile()
269
for version, parent_ids, expected_sha1, mpdiff in records:
270
versions.append(version)
271
mpvf.add_diff(mpdiff, version, parent_ids)
272
needed_parents = set()
273
for version, parent_ids, expected_sha1, mpdiff in records:
274
needed_parents.update(p for p in parent_ids
275
if not mpvf.has_version(p))
276
for parent_id, lines in zip(needed_parents,
277
self._get_lf_split_line_list(needed_parents)):
278
mpvf.add_version(lines, parent_id, [])
279
for (version, parent_ids, expected_sha1, mpdiff), lines in\
280
zip(records, mpvf.get_line_list(versions)):
281
if len(parent_ids) == 1:
282
left_matching_blocks = list(mpdiff.get_matching_blocks(0,
283
mpvf.get_diff(parent_ids[0]).num_lines()))
285
left_matching_blocks = None
286
_, _, version_text = self.add_lines(version, parent_ids, lines,
287
vf_parents, left_matching_blocks=left_matching_blocks)
288
vf_parents[version] = version_text
289
for (version, parent_ids, expected_sha1, mpdiff), sha1 in\
290
zip(records, self.get_sha1s(versions)):
291
if expected_sha1 != sha1:
292
raise errors.VersionedFileInvalidChecksum(version)
267
294
def get_sha1(self, version_id):
268
295
"""Get the stored sha1 sum for the given revision.
444
471
raise NotImplementedError(self.iter_lines_added_or_present_in_versions)
473
def iter_parents(self, version_ids):
474
"""Iterate through the parents for many version ids.
476
:param version_ids: An iterable yielding version_ids.
477
:return: An iterator that yields (version_id, parents). Requested
478
version_ids not present in the versioned file are simply skipped.
479
The order is undefined, allowing for different optimisations in
480
the underlying implementation.
482
for version_id in version_ids:
484
yield version_id, tuple(self.get_parents(version_id))
485
except errors.RevisionNotPresent:
446
488
def transaction_finished(self):
447
489
"""The transaction that this file was opened in has finished.
452
494
self.finished = True
454
@deprecated_method(zero_eight)
455
def walk(self, version_ids=None):
456
"""Walk the versioned file as a weave-like structure, for
457
versions relative to version_ids. Yields sequence of (lineno,
458
insert, deletes, text) for each relevant line.
460
Must raise RevisionNotPresent if any of the specified versions
461
are not present in the file history.
463
:param version_ids: the version_ids to walk with respect to. If not
464
supplied the entire weave-like structure is walked.
466
walk is deprecated in favour of iter_lines_added_or_present_in_versions
468
raise NotImplementedError(self.walk)
470
@deprecated_method(zero_eight)
471
def iter_names(self):
472
"""Walk the names list."""
473
return iter(self.versions())
475
496
def plan_merge(self, ver_a, ver_b):
476
497
"""Return pseudo-annotation indicating how the two versions merge.
628
649
# TODO: remove parent texts when they are not relevant any more for
629
650
# memory pressure reduction. RBC 20060313
630
651
# pb.update('Converting versioned data', 0, len(order))
631
# deltas = self.source.get_deltas(order)
632
652
for index, version in enumerate(order):
633
653
pb.update('Converting versioned data', index, len(order))
634
parent_text = target.add_lines(version,
654
_, _, parent_text = target.add_lines(version,
635
655
self.source.get_parents(version),
636
656
self.source.get_lines(version),
637
657
parent_texts=parent_texts)
638
658
parent_texts[version] = parent_text
639
#delta_parent, sha1, noeol, delta = deltas[version]
640
#target.add_delta(version,
641
# self.source.get_parents(version),
646
#target.get_lines(version)
648
660
# this should hit the native code path for target
649
661
if target is not self.target: