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.
373
449
# TODO: Show some version information (e.g. author, date) on
374
450
# conflicted regions.
452
# We previously considered either 'unchanged' or 'killed-both' lines
453
# to be possible places to resynchronize. However, assuming agreement
454
# on killed-both lines may be too agressive. -- mbp 20060324
375
455
for state, line in plan:
376
if state == 'unchanged' or state == 'killed-both':
456
if state == 'unchanged':
377
457
# resync and flush queued conflicts changes if any
378
458
if not lines_a and not lines_b:
456
536
graph = self.source.get_graph()
457
537
order = topo_sort(graph.items())
458
538
pb = ui.ui_factory.nested_progress_bar()
541
# TODO for incremental cross-format work:
542
# make a versioned file with the following content:
543
# all revisions we have been asked to join
544
# all their ancestors that are *not* in target already.
545
# the immediate parents of the above two sets, with
546
# empty parent lists - these versions are in target already
547
# and the incorrect version data will be ignored.
548
# TODO: for all ancestors that are present in target already,
549
# check them for consistent data, this requires moving sha1 from
551
# TODO: remove parent texts when they are not relevant any more for
552
# memory pressure reduction. RBC 20060313
553
# pb.update('Converting versioned data', 0, len(order))
554
# deltas = self.source.get_deltas(order)
460
555
for index, version in enumerate(order):
461
556
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))
557
parent_text = target.add_lines(version,
558
self.source.get_parents(version),
559
self.source.get_lines(version),
560
parent_texts=parent_texts)
561
parent_texts[version] = parent_text
562
#delta_parent, sha1, noeol, delta = deltas[version]
563
#target.add_delta(version,
564
# self.source.get_parents(version),
569
#target.get_lines(version)
466
571
# this should hit the native code path for target
467
572
if target is not self.target: