78
78
"""Returns whether version is present."""
79
79
raise NotImplementedError(self.has_version)
81
def add_lines(self, version_id, parents, lines):
81
def add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
82
"""Add a text to the versioned file via a pregenerated delta.
84
:param version_id: The version id being added.
85
:param parents: The parents of the version_id.
86
:param delta_parent: The parent this delta was created against.
87
:param sha1: The sha1 of the full text.
88
:param delta: The delta instructions. See get_delta for details.
90
self._check_write_ok()
91
if self.has_version(version_id):
92
raise errors.RevisionAlreadyPresent(version_id, self)
93
return self._add_delta(version_id, parents, delta_parent, sha1, noeol, delta)
95
def _add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
96
"""Class specific routine to add a delta.
98
This generic version simply applies the delta to the delta_parent and
101
# strip annotation from delta
103
for start, stop, delta_len, delta_lines in delta:
104
new_delta.append((start, stop, delta_len, [text for origin, text in delta_lines]))
105
if delta_parent is not None:
106
parent_full = self.get_lines(delta_parent)
109
new_full = self._apply_delta(parent_full, new_delta)
110
# its impossible to have noeol on an empty file
111
if noeol and new_full[-1][-1] == '\n':
112
new_full[-1] = new_full[-1][:-1]
113
self.add_lines(version_id, parents, new_full)
115
def add_lines(self, version_id, parents, lines, parent_texts=None):
82
116
"""Add a single text on top of the versioned file.
84
118
Must raise RevisionAlreadyPresent if the new version is
87
121
Must raise RevisionNotPresent if any of the given parents are
88
122
not present in file history.
123
:param parent_texts: An optional dictionary containing the opaque
124
representations of some or all of the parents of
125
version_id to allow delta optimisations.
126
VERY IMPORTANT: the texts must be those returned
127
by add_lines or data corruption can be caused.
128
:return: An opaque representation of the inserted version which can be
129
provided back to future add_lines calls in the parent_texts
90
132
self._check_write_ok()
91
return self._add_lines(version_id, parents, lines)
133
return self._add_lines(version_id, parents, lines, parent_texts)
93
def _add_lines(self, version_id, parents, lines):
135
def _add_lines(self, version_id, parents, lines, parent_texts):
94
136
"""Helper to do the class specific add_lines."""
95
137
raise NotImplementedError(self.add_lines)
97
def add_lines_with_ghosts(self, version_id, parents, lines):
98
"""Add lines to the versioned file, allowing ghosts to be present."""
139
def add_lines_with_ghosts(self, version_id, parents, lines,
141
"""Add lines to the versioned file, allowing ghosts to be present.
143
This takes the same parameters as add_lines.
99
145
self._check_write_ok()
100
return self._add_lines_with_ghosts(version_id, parents, lines)
146
return self._add_lines_with_ghosts(version_id, parents, lines,
102
def _add_lines_with_ghosts(self, version_id, parents, lines):
149
def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts):
103
150
"""Helper to do class specific add_lines_with_ghosts."""
104
151
raise NotImplementedError(self.add_lines_with_ghosts)
156
203
"""Helper for fix_parents."""
157
204
raise NotImplementedError(self.fix_parents)
206
def get_delta(self, version):
207
"""Get a delta for constructing version from some other version.
209
:return: (delta_parent, sha1, noeol, delta)
210
Where delta_parent is a version id or None to indicate no parent.
212
raise NotImplementedError(self.get_delta)
214
def get_deltas(self, versions):
215
"""Get multiple deltas at once for constructing versions.
217
:return: dict(version_id:(delta_parent, sha1, noeol, delta))
218
Where delta_parent is a version id or None to indicate no parent, and
219
version_id is the version_id created by that delta.
222
for version in versions:
223
result[version] = self.get_delta(version)
159
226
def get_suffixes(self):
160
227
"""Return the file suffixes associated with this versioned file."""
161
228
raise NotImplementedError(self.get_suffixes)
256
323
def annotate(self, version_id):
257
324
return list(self.annotate_iter(version_id))
326
def _apply_delta(self, lines, delta):
327
"""Apply delta to lines."""
330
for start, end, count, delta_lines in delta:
331
lines[offset+start:offset+end] = delta_lines
332
offset = offset + (start - end) + count
259
335
def join(self, other, pb=None, msg=None, version_ids=None,
260
336
ignore_missing=False):
261
337
"""Integrate versions from other into this versioned file.
456
532
graph = self.source.get_graph()
457
533
order = topo_sort(graph.items())
458
534
pb = ui.ui_factory.nested_progress_bar()
537
# TODO for incremental cross-format work:
538
# make a versioned file with the following content:
539
# all revisions we have been asked to join
540
# all their ancestors that are *not* in target already.
541
# the immediate parents of the above two sets, with
542
# empty parent lists - these versions are in target already
543
# and the incorrect version data will be ignored.
544
# TODO: for all ancestors that are present in target already,
545
# check them for consistent data, this requires moving sha1 from
547
# TODO: remove parent texts when they are not relevant any more for
548
# memory pressure reduction. RBC 20060313
549
# pb.update('Converting versioned data', 0, len(order))
550
# deltas = self.source.get_deltas(order)
460
551
for index, version in enumerate(order):
461
552
pb.update('Converting versioned data', index, len(order))
462
target.add_lines(version,
463
self.source.get_parents(version),
464
self.source.get_lines(version))
553
parent_text = target.add_lines(version,
554
self.source.get_parents(version),
555
self.source.get_lines(version),
556
parent_texts=parent_texts)
557
parent_texts[version] = parent_text
558
#delta_parent, sha1, noeol, delta = deltas[version]
559
#target.add_delta(version,
560
# self.source.get_parents(version),
565
#target.get_lines(version)
466
567
# this should hit the native code path for target
467
568
if target is not self.target: