28
28
from unittest import TestSuite
31
import bzrlib.errors as errors
31
32
from bzrlib.inter import InterObject
32
33
from bzrlib.symbol_versioning import *
33
34
from bzrlib.transport.memory import MemoryTransport
49
50
Texts are identified by a version-id string.
53
def __init__(self, access_mode):
55
self._access_mode = access_mode
52
57
def copy_to(self, name, transport):
53
58
"""Copy this versioned file to name on transport."""
54
59
raise NotImplementedError(self.copy_to)
65
70
"""Return a unsorted list of versions."""
66
71
raise NotImplementedError(self.versions)
73
def has_ghost(self, version_id):
74
"""Returns whether version is present as a ghost."""
75
raise NotImplementedError(self.has_ghost)
68
77
def has_version(self, version_id):
69
78
"""Returns whether version is present."""
70
79
raise NotImplementedError(self.has_version)
76
85
already present in file history.
78
87
Must raise RevisionNotPresent if any of the given parents are
79
not present in file history."""
88
not present in file history.
90
self._check_write_ok()
91
return self._add_lines(version_id, parents, lines)
93
def _add_lines(self, version_id, parents, lines):
94
"""Helper to do the class specific add_lines."""
80
95
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."""
99
self._check_write_ok()
100
return self._add_lines_with_ghosts(version_id, parents, lines)
102
def _add_lines_with_ghosts(self, version_id, parents, lines):
103
"""Helper to do class specific add_lines_with_ghosts."""
104
raise NotImplementedError(self.add_lines_with_ghosts)
82
106
def check(self, progress_bar=None):
83
107
"""Check the versioned file for integrity."""
84
108
raise NotImplementedError(self.check)
110
def _check_write_ok(self):
111
"""Is the versioned file marked as 'finished' ? Raise if it is."""
113
raise errors.OutSideTransaction()
114
if self._access_mode != 'w':
115
raise errors.ReadOnlyObjectDirtiedError(self)
86
117
def clear_cache(self):
87
118
"""Remove any data cached in the versioned file object."""
95
126
Must raise RevisionAlreadyPresent if the new version is
96
127
already present in file history."""
128
self._check_write_ok()
129
return self._clone_text(new_version_id, old_version_id, parents)
131
def _clone_text(self, new_version_id, old_version_id, parents):
132
"""Helper function to do the _clone_text work."""
97
133
raise NotImplementedError(self.clone_text)
99
135
def create_empty(self, name, transport, mode=None):
106
142
raise NotImplementedError(self.create_empty)
144
def fix_parents(self, version, new_parents):
145
"""Fix the parents list for version.
147
This is done by appending a new version to the index
148
with identical data except for the parents list.
149
the parents list must be a superset of the current
152
self._check_write_ok()
153
return self._fix_parents(version, new_parents)
155
def _fix_parents(self, version, new_parents):
156
"""Helper for fix_parents."""
157
raise NotImplementedError(self.fix_parents)
108
159
def get_suffixes(self):
109
160
"""Return the file suffixes associated with this versioned file."""
110
161
raise NotImplementedError(self.get_suffixes)
136
187
version_ids = [version_ids]
137
188
raise NotImplementedError(self.get_ancestry)
190
def get_ancestry_with_ghosts(self, version_ids):
191
"""Return a list of all ancestors of given version(s). This
192
will not include the null revision.
194
Must raise RevisionNotPresent if any of the given versions are
195
not present in file history.
197
Ghosts that are known about will be included in ancestry list,
198
but are not explicitly marked.
200
raise NotImplementedError(self.get_ancestry_with_ghosts)
139
202
def get_graph(self):
140
"""Return a graph for the entire versioned file."""
203
"""Return a graph for the entire versioned file.
205
Ghosts are not listed or referenced in the graph.
142
208
for version in self.versions():
143
209
result[version] = self.get_parents(version)
212
def get_graph_with_ghosts(self):
213
"""Return a graph for the entire versioned file.
215
Ghosts are referenced in parents list but are not
218
raise NotImplementedError(self.get_graph_with_ghosts)
146
220
@deprecated_method(zero_eight)
147
221
def parent_names(self, version):
148
222
"""Return version names for parents of a version.
160
234
raise NotImplementedError(self.get_parents)
236
def get_parents_with_ghosts(self, version_id):
237
"""Return version names for parents of version_id.
239
Will raise RevisionNotPresent if version_id is not present
242
Ghosts that are known about will be included in the parent list,
243
but are not explicitly marked.
245
raise NotImplementedError(self.get_parents_with_ghosts)
162
247
def annotate_iter(self, version_id):
163
248
"""Yield list of (version-id, line) pairs for the specified
182
267
are not present in the other files history unless ignore_missing
183
268
is supplied when they are silently skipped.
270
self._check_write_ok()
185
271
return InterVersionedFile.get(other, self).join(
277
def iter_lines_added_or_present_in_versions(self, version_ids=None):
278
"""Iterate over the lines in the versioned file from version_ids.
280
This may return lines from other versions, and does not return the
281
specific version marker at this point. The api may be changed
282
during development to include the version that the versioned file
283
thinks is relevant, but given that such hints are just guesses,
284
its better not to have it if we dont need it.
286
NOTES: Lines are normalised: they will all have \n terminators.
287
Lines are returned in arbitrary order.
289
raise NotImplementedError(self.iter_lines_added_or_present_in_versions)
291
def transaction_finished(self):
292
"""The transaction that this file was opened in has finished.
294
This records self.finished = True and should cause all mutating
299
@deprecated_method(zero_eight)
191
300
def walk(self, version_ids=None):
192
301
"""Walk the versioned file as a weave-like structure, for
193
302
versions relative to version_ids. Yields sequence of (lineno,
199
308
:param version_ids: the version_ids to walk with respect to. If not
200
309
supplied the entire weave-like structure is walked.
311
walk is deprecated in favour of iter_lines_added_or_present_in_versions
202
313
raise NotImplementedError(self.walk)
218
329
inc_b = set(self.get_ancestry([ver_b]))
219
330
inc_c = inc_a & inc_b
221
for lineno, insert, deleteset, line in self.walk():
332
for lineno, insert, deleteset, line in self.walk([ver_a, ver_b]):
222
333
if deleteset & inc_c:
223
334
# killed in parent; can't be in either a or b
224
335
# not relevant to our work
331
442
supplied when they are silently skipped.
333
444
# the default join:
445
# - if the target is empty, just add all the versions from
446
# source to target, otherwise:
334
447
# - make a temporary versioned file of type target
335
448
# - insert the source content into it one at a time
337
# Make a new target-format versioned file.
338
temp_source = self.target.create_empty("temp", MemoryTransport())
450
if not self.target.versions():
453
# Make a new target-format versioned file.
454
temp_source = self.target.create_empty("temp", MemoryTransport())
339
456
graph = self.source.get_graph()
340
457
order = topo_sort(graph.items())
341
458
pb = ui.ui_factory.nested_progress_bar()
343
460
for index, version in enumerate(order):
344
461
pb.update('Converting versioned data', index, len(order))
345
temp_source.add_lines(version,
346
self.source.get_parents(version),
347
self.source.get_lines(version))
462
target.add_lines(version,
463
self.source.get_parents(version),
464
self.source.get_lines(version))
349
466
# this should hit the native code path for target
350
return self.target.join(temp_source,
467
if target is not self.target:
468
return self.target.join(temp_source,