7
7
# it under the terms of the GNU General Public License as published by
8
8
# the Free Software Foundation; either version 2 of the License, or
9
9
# (at your option) any later version.
11
11
# This program is distributed in the hope that it will be useful,
12
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
# GNU General Public License for more details.
16
16
# You should have received a copy of the GNU General Public License
17
17
# along with this program; if not, write to the Free Software
18
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
20
"""Versioned text file storage api."""
22
from bzrlib.lazy_import import lazy_import
23
lazy_import(globals(), """
32
from bzrlib.transport.memory import MemoryTransport
23
from copy import deepcopy
24
from unittest import TestSuite
27
import bzrlib.errors as errors
35
28
from bzrlib.inter import InterObject
29
from bzrlib.symbol_versioning import *
36
30
from bzrlib.textmerge import TextMerge
37
from bzrlib.symbol_versioning import (deprecated_function,
31
from bzrlib.transport.memory import MemoryTransport
32
from bzrlib.tsort import topo_sort
43
36
class VersionedFile(object):
58
51
self.finished = False
59
52
self._access_mode = access_mode
62
def check_not_reserved_id(version_id):
63
revision.check_not_reserved_id(version_id)
65
54
def copy_to(self, name, transport):
66
55
"""Copy this versioned file to name on transport."""
67
56
raise NotImplementedError(self.copy_to)
69
58
@deprecated_method(zero_eight)
71
60
"""Return a list of all the versions in this versioned file.
95
84
:param sha1: The sha1 of the full text.
96
85
: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
87
self._check_write_ok()
101
88
if self.has_version(version_id):
102
89
raise errors.RevisionAlreadyPresent(version_id, self)
139
126
provided back to future add_lines calls in the parent_texts
142
version_id = osutils.safe_revision_id(version_id)
143
parents = [osutils.safe_revision_id(v) for v in parents]
144
129
self._check_write_ok()
145
130
return self._add_lines(version_id, parents, lines, parent_texts)
155
140
This takes the same parameters as add_lines.
157
version_id = osutils.safe_revision_id(version_id)
158
parents = [osutils.safe_revision_id(v) for v in parents]
159
142
self._check_write_ok()
160
143
return self._add_lines_with_ghosts(version_id, parents, lines,
187
170
if self._access_mode != 'w':
188
171
raise errors.ReadOnlyObjectDirtiedError(self)
190
def enable_cache(self):
191
"""Tell this versioned file that it should cache any data it reads.
193
This is advisory, implementations do not have to support caching.
197
173
def clear_cache(self):
198
"""Remove any data cached in the versioned file object.
200
This only needs to be supported if caches are supported
174
"""Remove any data cached in the versioned file object."""
204
176
def clone_text(self, new_version_id, old_version_id, parents):
205
177
"""Add an identical text to old_version_id as new_version_id.
210
182
Must raise RevisionAlreadyPresent if the new version is
211
183
already present in file history."""
212
new_version_id = osutils.safe_revision_id(new_version_id)
213
old_version_id = osutils.safe_revision_id(old_version_id)
214
184
self._check_write_ok()
215
185
return self._clone_text(new_version_id, old_version_id, parents)
228
198
raise NotImplementedError(self.create_empty)
230
def fix_parents(self, version_id, new_parents):
200
def fix_parents(self, version, new_parents):
231
201
"""Fix the parents list for version.
233
203
This is done by appending a new version to the index
235
205
the parents list must be a superset of the current
238
version_id = osutils.safe_revision_id(version_id)
239
new_parents = [osutils.safe_revision_id(p) for p in new_parents]
240
208
self._check_write_ok()
241
return self._fix_parents(version_id, new_parents)
209
return self._fix_parents(version, new_parents)
243
def _fix_parents(self, version_id, new_parents):
211
def _fix_parents(self, version, new_parents):
244
212
"""Helper for fix_parents."""
245
213
raise NotImplementedError(self.fix_parents)
253
221
raise NotImplementedError(self.get_delta)
255
def get_deltas(self, version_ids):
223
def get_deltas(self, versions):
256
224
"""Get multiple deltas at once for constructing versions.
258
226
:return: dict(version_id:(delta_parent, sha1, noeol, delta))
260
228
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)
231
for version in versions:
232
result[version] = self.get_delta(version)
267
235
def get_sha1(self, version_id):
284
252
return ''.join(self.get_lines(version_id))
285
253
get_string = get_text
287
def get_texts(self, version_ids):
288
"""Return the texts of listed versions as a list of strings.
290
Raises RevisionNotPresent if version is not present in
293
return [''.join(self.get_lines(v)) for v in version_ids]
295
255
def get_lines(self, version_id):
296
256
"""Return version contents as a sequence of lines.
301
261
raise NotImplementedError(self.get_lines)
303
def get_ancestry(self, version_ids, topo_sorted=True):
263
def get_ancestry(self, version_ids):
304
264
"""Return a list of all ancestors of given version(s). This
305
265
will not include the null revision.
307
This list will not be topologically sorted if topo_sorted=False is
310
267
Must raise RevisionNotPresent if any of the given versions are
311
268
not present in file history."""
312
269
if isinstance(version_ids, basestring):
331
288
Ghosts are not listed or referenced in the graph.
332
289
:param version_ids: Versions to select.
333
None means retrieve all versions.
290
None means retreive all versions.
336
293
if version_ids is None:
337
294
for version in self.versions():
338
295
result[version] = self.get_parents(version)
340
pending = set(osutils.safe_revision_id(v) for v in version_ids)
297
pending = set(version_ids)
342
299
version = pending.pop()
343
300
if version in result:
427
def iter_lines_added_or_present_in_versions(self, version_ids=None,
384
def iter_lines_added_or_present_in_versions(self, version_ids=None):
429
385
"""Iterate over the lines in the versioned file from version_ids.
431
387
This may return lines from other versions, and does not return the
432
388
specific version marker at this point. The api may be changed
433
389
during development to include the version that the versioned file
434
390
thinks is relevant, but given that such hints are just guesses,
435
its better not to have it if we don't need it.
437
If a progress bar is supplied, it may be used to indicate progress.
438
The caller is responsible for cleaning up progress bars (because this
391
its better not to have it if we dont need it.
441
393
NOTES: Lines are normalised: they will all have \n terminators.
442
394
Lines are returned in arbitrary order.
495
447
raise NotImplementedError(VersionedFile.plan_merge)
497
def weave_merge(self, plan, a_marker=TextMerge.A_MARKER,
449
def weave_merge(self, plan, a_marker=TextMerge.A_MARKER,
498
450
b_marker=TextMerge.B_MARKER):
499
451
return PlanWeaveMerge(plan, a_marker, b_marker).merge_lines()[0]
532
484
# We previously considered either 'unchanged' or 'killed-both' lines
533
485
# to be possible places to resynchronize. However, assuming agreement
534
# on killed-both lines may be too aggressive. -- mbp 20060324
486
# on killed-both lines may be too agressive. -- mbp 20060324
535
487
for state, line in self.plan:
536
488
if state == 'unchanged':
537
489
# resync and flush queued conflicts changes if any
584
536
InterVersionedFile.get(other).method_name(parameters).
588
540
"""The available optimised InterVersionedFile types."""
590
542
def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
611
563
target = temp_source
612
564
version_ids = self._get_source_version_ids(version_ids, ignore_missing)
613
565
graph = self.source.get_graph(version_ids)
614
order = tsort.topo_sort(graph.items())
566
order = topo_sort(graph.items())
615
567
pb = ui.ui_factory.nested_progress_bar()
616
568
parent_texts = {}
683
634
new_version_ids.add(version)
684
635
return new_version_ids
638
class InterVersionedFileTestProviderAdapter(object):
639
"""A tool to generate a suite testing multiple inter versioned-file classes.
641
This is done by copying the test once for each interversionedfile provider
642
and injecting the transport_server, transport_readonly_server,
643
versionedfile_factory and versionedfile_factory_to classes into each copy.
644
Each copy is also given a new id() to make it easy to identify.
647
def __init__(self, transport_server, transport_readonly_server, formats):
648
self._transport_server = transport_server
649
self._transport_readonly_server = transport_readonly_server
650
self._formats = formats
652
def adapt(self, test):
654
for (interversionedfile_class,
655
versionedfile_factory,
656
versionedfile_factory_to) in self._formats:
657
new_test = deepcopy(test)
658
new_test.transport_server = self._transport_server
659
new_test.transport_readonly_server = self._transport_readonly_server
660
new_test.interversionedfile_class = interversionedfile_class
661
new_test.versionedfile_factory = versionedfile_factory
662
new_test.versionedfile_factory_to = versionedfile_factory_to
663
def make_new_test_id():
664
new_id = "%s(%s)" % (new_test.id(), interversionedfile_class.__name__)
665
return lambda: new_id
666
new_test.id = make_new_test_id()
667
result.addTest(new_test)
671
def default_test_list():
672
"""Generate the default list of interversionedfile permutations to test."""
673
from bzrlib.weave import WeaveFile
674
from bzrlib.knit import KnitVersionedFile
676
# test the fallback InterVersionedFile from annotated knits to weave
677
result.append((InterVersionedFile,
680
for optimiser in InterVersionedFile._optimisers:
681
result.append((optimiser,
682
optimiser._matching_file_from_factory,
683
optimiser._matching_file_to_factory
685
# if there are specific combinations we want to use, we can add them