~bzr-pqm/bzr/bzr.dev

1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
1
# Copyright (C) 2005 by Canonical Ltd
2
#
3
# Authors:
4
#   Johan Rydberg <jrydberg@gnu.org>
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20
# Remaing to do is to figure out if get_graph should return a simple
21
# map, or a graph object of some kind.
22
23
24
"""Versioned text file storage api."""
25
26
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
27
from copy import deepcopy
28
from unittest import TestSuite
29
30
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
31
import bzrlib.errors as errors
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
32
from bzrlib.inter import InterObject
1563.2.11 by Robert Collins
Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.
33
from bzrlib.symbol_versioning import *
1563.2.13 by Robert Collins
InterVersionedFile implemented.
34
from bzrlib.transport.memory import MemoryTransport
35
from bzrlib.tsort import topo_sort
1563.2.33 by Robert Collins
Nicer progress updates during conversion to knits.
36
from bzrlib import ui
1563.2.11 by Robert Collins
Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.
37
38
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
39
class VersionedFile(object):
40
    """Versioned text file storage.
41
    
42
    A versioned file manages versions of line-based text files,
43
    keeping track of the originating version for each line.
44
45
    To clients the "lines" of the file are represented as a list of
46
    strings. These strings will typically have terminal newline
47
    characters, but this is not required.  In particular files commonly
48
    do not have a newline at the end of the file.
49
50
    Texts are identified by a version-id string.
51
    """
52
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
53
    def __init__(self, access_mode):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
54
        self.finished = False
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
55
        self._access_mode = access_mode
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
56
1563.2.15 by Robert Collins
remove the weavestore assumptions about the number and nature of files it manages.
57
    def copy_to(self, name, transport):
58
        """Copy this versioned file to name on transport."""
59
        raise NotImplementedError(self.copy_to)
60
    
1563.2.11 by Robert Collins
Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.
61
    @deprecated_method(zero_eight)
62
    def names(self):
63
        """Return a list of all the versions in this versioned file.
64
65
        Please use versionedfile.versions() now.
66
        """
67
        return self.versions()
68
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
69
    def versions(self):
70
        """Return a unsorted list of versions."""
71
        raise NotImplementedError(self.versions)
72
1594.2.8 by Robert Collins
add ghost aware apis to knits.
73
    def has_ghost(self, version_id):
74
        """Returns whether version is present as a ghost."""
75
        raise NotImplementedError(self.has_ghost)
76
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
77
    def has_version(self, version_id):
78
        """Returns whether version is present."""
79
        raise NotImplementedError(self.has_version)
80
81
    def add_lines(self, version_id, parents, lines):
82
        """Add a single text on top of the versioned file.
83
84
        Must raise RevisionAlreadyPresent if the new version is
85
        already present in file history.
86
87
        Must raise RevisionNotPresent if any of the given parents are
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
88
        not present in file history.
89
        """
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
90
        self._check_write_ok()
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
91
        return self._add_lines(version_id, parents, lines)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
92
93
    def _add_lines(self, version_id, parents, lines):
94
        """Helper to do the class specific add_lines."""
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
95
        raise NotImplementedError(self.add_lines)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
96
1594.2.8 by Robert Collins
add ghost aware apis to knits.
97
    def add_lines_with_ghosts(self, version_id, parents, lines):
98
        """Add lines to the versioned file, allowing ghosts to be present."""
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
99
        self._check_write_ok()
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
100
        return self._add_lines_with_ghosts(version_id, parents, lines)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
101
102
    def _add_lines_with_ghosts(self, version_id, parents, lines):
103
        """Helper to do class specific add_lines_with_ghosts."""
1594.2.8 by Robert Collins
add ghost aware apis to knits.
104
        raise NotImplementedError(self.add_lines_with_ghosts)
105
1563.2.19 by Robert Collins
stub out a check for knits.
106
    def check(self, progress_bar=None):
107
        """Check the versioned file for integrity."""
108
        raise NotImplementedError(self.check)
109
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
110
    def _check_write_ok(self):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
111
        """Is the versioned file marked as 'finished' ? Raise if it is."""
112
        if self.finished:
113
            raise errors.OutSideTransaction()
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
114
        if self._access_mode != 'w':
115
            raise errors.ReadOnlyObjectDirtiedError(self)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
116
1563.2.7 by Robert Collins
add versioned file clear_cache entry.
117
    def clear_cache(self):
118
        """Remove any data cached in the versioned file object."""
119
1563.2.5 by Robert Collins
Remove unused transaction references from knit.py and the versionedfile interface.
120
    def clone_text(self, new_version_id, old_version_id, parents):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
121
        """Add an identical text to old_version_id as new_version_id.
122
123
        Must raise RevisionNotPresent if the old version or any of the
124
        parents are not present in file history.
125
126
        Must raise RevisionAlreadyPresent if the new version is
127
        already present in file history."""
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
128
        self._check_write_ok()
129
        return self._clone_text(new_version_id, old_version_id, parents)
130
131
    def _clone_text(self, new_version_id, old_version_id, parents):
132
        """Helper function to do the _clone_text work."""
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
133
        raise NotImplementedError(self.clone_text)
134
1563.2.13 by Robert Collins
InterVersionedFile implemented.
135
    def create_empty(self, name, transport, mode=None):
136
        """Create a new versioned file of this exact type.
137
138
        :param name: the file name
139
        :param transport: the transport
140
        :param mode: optional file mode.
141
        """
142
        raise NotImplementedError(self.create_empty)
143
1594.2.7 by Robert Collins
Add versionedfile.fix_parents api for correcting data post hoc.
144
    def fix_parents(self, version, new_parents):
145
        """Fix the parents list for version.
146
        
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
150
        list.
151
        """
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
152
        self._check_write_ok()
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
153
        return self._fix_parents(version, new_parents)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
154
155
    def _fix_parents(self, version, new_parents):
156
        """Helper for fix_parents."""
1594.2.7 by Robert Collins
Add versionedfile.fix_parents api for correcting data post hoc.
157
        raise NotImplementedError(self.fix_parents)
158
1563.2.15 by Robert Collins
remove the weavestore assumptions about the number and nature of files it manages.
159
    def get_suffixes(self):
160
        """Return the file suffixes associated with this versioned file."""
161
        raise NotImplementedError(self.get_suffixes)
162
    
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
163
    def get_text(self, version_id):
164
        """Return version contents as a text string.
165
166
        Raises RevisionNotPresent if version is not present in
167
        file history.
168
        """
169
        return ''.join(self.get_lines(version_id))
170
    get_string = get_text
171
172
    def get_lines(self, version_id):
173
        """Return version contents as a sequence of lines.
174
175
        Raises RevisionNotPresent if version is not present in
176
        file history.
177
        """
178
        raise NotImplementedError(self.get_lines)
179
180
    def get_ancestry(self, version_ids):
181
        """Return a list of all ancestors of given version(s). This
182
        will not include the null revision.
183
184
        Must raise RevisionNotPresent if any of the given versions are
185
        not present in file history."""
186
        if isinstance(version_ids, basestring):
187
            version_ids = [version_ids]
188
        raise NotImplementedError(self.get_ancestry)
189
        
1594.2.8 by Robert Collins
add ghost aware apis to knits.
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.
193
194
        Must raise RevisionNotPresent if any of the given versions are
195
        not present in file history.
196
        
197
        Ghosts that are known about will be included in ancestry list,
198
        but are not explicitly marked.
199
        """
200
        raise NotImplementedError(self.get_ancestry_with_ghosts)
201
        
1563.2.13 by Robert Collins
InterVersionedFile implemented.
202
    def get_graph(self):
1594.2.8 by Robert Collins
add ghost aware apis to knits.
203
        """Return a graph for the entire versioned file.
204
        
205
        Ghosts are not listed or referenced in the graph.
206
        """
1563.2.13 by Robert Collins
InterVersionedFile implemented.
207
        result = {}
208
        for version in self.versions():
209
            result[version] = self.get_parents(version)
210
        return result
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
211
1594.2.8 by Robert Collins
add ghost aware apis to knits.
212
    def get_graph_with_ghosts(self):
213
        """Return a graph for the entire versioned file.
214
        
215
        Ghosts are referenced in parents list but are not
216
        explicitly listed.
217
        """
218
        raise NotImplementedError(self.get_graph_with_ghosts)
219
1563.2.11 by Robert Collins
Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.
220
    @deprecated_method(zero_eight)
221
    def parent_names(self, version):
222
        """Return version names for parents of a version.
223
        
224
        See get_parents for the current api.
225
        """
226
        return self.get_parents(version)
227
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
228
    def get_parents(self, version_id):
229
        """Return version names for parents of a version.
230
231
        Must raise RevisionNotPresent if version is not present in
232
        file history.
233
        """
234
        raise NotImplementedError(self.get_parents)
235
1594.2.8 by Robert Collins
add ghost aware apis to knits.
236
    def get_parents_with_ghosts(self, version_id):
237
        """Return version names for parents of version_id.
238
239
        Will raise RevisionNotPresent if version_id is not present
240
        in the history.
241
242
        Ghosts that are known about will be included in the parent list,
243
        but are not explicitly marked.
244
        """
245
        raise NotImplementedError(self.get_parents_with_ghosts)
246
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
247
    def annotate_iter(self, version_id):
248
        """Yield list of (version-id, line) pairs for the specified
249
        version.
250
251
        Must raise RevisionNotPresent if any of the given versions are
252
        not present in file history.
253
        """
254
        raise NotImplementedError(self.annotate_iter)
255
256
    def annotate(self, version_id):
257
        return list(self.annotate_iter(version_id))
258
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
259
    def join(self, other, pb=None, msg=None, version_ids=None,
260
             ignore_missing=False):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
261
        """Integrate versions from other into this versioned file.
262
263
        If version_ids is None all versions from other should be
264
        incorporated into this versioned file.
265
266
        Must raise RevisionNotPresent if any of the specified versions
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
267
        are not present in the other files history unless ignore_missing
268
        is supplied when they are silently skipped.
269
        """
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
270
        self._check_write_ok()
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
271
        return InterVersionedFile.get(other, self).join(
272
            pb,
273
            msg,
274
            version_ids,
275
            ignore_missing)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
276
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
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.
279
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.
285
286
        NOTES: Lines are normalised: they will all have \n terminators.
287
               Lines are returned in arbitrary order.
288
        """
289
        raise NotImplementedError(self.iter_lines_added_or_present_in_versions)
290
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
291
    def transaction_finished(self):
292
        """The transaction that this file was opened in has finished.
293
294
        This records self.finished = True and should cause all mutating
295
        operations to error.
296
        """
297
        self.finished = True
298
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
299
    @deprecated_method(zero_eight)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
300
    def walk(self, version_ids=None):
301
        """Walk the versioned file as a weave-like structure, for
302
        versions relative to version_ids.  Yields sequence of (lineno,
303
        insert, deletes, text) for each relevant line.
304
305
        Must raise RevisionNotPresent if any of the specified versions
306
        are not present in the file history.
307
308
        :param version_ids: the version_ids to walk with respect to. If not
309
                            supplied the entire weave-like structure is walked.
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
310
311
        walk is deprecated in favour of iter_lines_added_or_present_in_versions
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
312
        """
313
        raise NotImplementedError(self.walk)
314
1563.2.11 by Robert Collins
Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.
315
    @deprecated_method(zero_eight)
316
    def iter_names(self):
317
        """Walk the names list."""
318
        return iter(self.versions())
319
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
320
    def plan_merge(self, ver_a, ver_b):
321
        """Return pseudo-annotation indicating how the two versions merge.
322
323
        This is computed between versions a and b and their common
324
        base.
325
326
        Weave lines present in none of them are skipped entirely.
327
        """
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
328
        inc_a = set(self.get_ancestry([ver_a]))
329
        inc_b = set(self.get_ancestry([ver_b]))
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
330
        inc_c = inc_a & inc_b
331
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
332
        for lineno, insert, deleteset, line in self.walk([ver_a, ver_b]):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
333
            if deleteset & inc_c:
334
                # killed in parent; can't be in either a or b
335
                # not relevant to our work
336
                yield 'killed-base', line
337
            elif insert in inc_c:
338
                # was inserted in base
339
                killed_a = bool(deleteset & inc_a)
340
                killed_b = bool(deleteset & inc_b)
341
                if killed_a and killed_b:
342
                    yield 'killed-both', line
343
                elif killed_a:
344
                    yield 'killed-a', line
345
                elif killed_b:
346
                    yield 'killed-b', line
347
                else:
348
                    yield 'unchanged', line
349
            elif insert in inc_a:
350
                if deleteset & inc_a:
351
                    yield 'ghost-a', line
352
                else:
353
                    # new in A; not in B
354
                    yield 'new-a', line
355
            elif insert in inc_b:
356
                if deleteset & inc_b:
357
                    yield 'ghost-b', line
358
                else:
359
                    yield 'new-b', line
360
            else:
361
                # not in either revision
362
                yield 'irrelevant', line
363
364
        yield 'unchanged', ''           # terminator
365
1563.2.2 by Robert Collins
merge from bzr.dev
366
    def weave_merge(self, plan, a_marker='<<<<<<< \n', b_marker='>>>>>>> \n'):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
367
        lines_a = []
368
        lines_b = []
369
        ch_a = ch_b = False
370
        # TODO: Return a structured form of the conflicts (e.g. 2-tuples for
371
        # conflicted regions), rather than just inserting the markers.
372
        # 
373
        # TODO: Show some version information (e.g. author, date) on 
374
        # conflicted regions.
375
        for state, line in plan:
376
            if state == 'unchanged' or state == 'killed-both':
377
                # resync and flush queued conflicts changes if any
378
                if not lines_a and not lines_b:
379
                    pass
380
                elif ch_a and not ch_b:
381
                    # one-sided change:                    
382
                    for l in lines_a: yield l
383
                elif ch_b and not ch_a:
384
                    for l in lines_b: yield l
385
                elif lines_a == lines_b:
386
                    for l in lines_a: yield l
387
                else:
1563.2.2 by Robert Collins
merge from bzr.dev
388
                    yield a_marker
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
389
                    for l in lines_a: yield l
390
                    yield '=======\n'
391
                    for l in lines_b: yield l
1563.2.2 by Robert Collins
merge from bzr.dev
392
                    yield b_marker
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
393
394
                del lines_a[:]
395
                del lines_b[:]
396
                ch_a = ch_b = False
397
                
398
            if state == 'unchanged':
399
                if line:
400
                    yield line
401
            elif state == 'killed-a':
402
                ch_a = True
403
                lines_b.append(line)
404
            elif state == 'killed-b':
405
                ch_b = True
406
                lines_a.append(line)
407
            elif state == 'new-a':
408
                ch_a = True
409
                lines_a.append(line)
410
            elif state == 'new-b':
411
                ch_b = True
412
                lines_b.append(line)
413
            else:
414
                assert state in ('irrelevant', 'ghost-a', 'ghost-b', 'killed-base',
415
                                 'killed-both'), \
416
                       state
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
417
418
419
class InterVersionedFile(InterObject):
420
    """This class represents operations taking place between two versionedfiles..
421
422
    Its instances have methods like join, and contain
423
    references to the source and target versionedfiles these operations can be 
424
    carried out on.
425
426
    Often we will provide convenience methods on 'versionedfile' which carry out
427
    operations with another versionedfile - they will always forward to
428
    InterVersionedFile.get(other).method_name(parameters).
429
    """
430
431
    _optimisers = set()
432
    """The available optimised InterVersionedFile types."""
433
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
434
    def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
1563.2.13 by Robert Collins
InterVersionedFile implemented.
435
        """Integrate versions from self.source into self.target.
436
437
        If version_ids is None all versions from source should be
438
        incorporated into this versioned file.
439
440
        Must raise RevisionNotPresent if any of the specified versions
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
441
        are not present in the other files history unless ignore_missing is 
442
        supplied when they are silently skipped.
1563.2.13 by Robert Collins
InterVersionedFile implemented.
443
        """
444
        # the default join: 
1594.2.11 by Robert Collins
Setup fast-code paths for copying into empty weaves and weave->empty knit.
445
        # - if the target is empty, just add all the versions from 
446
        #   source to target, otherwise:
1563.2.13 by Robert Collins
InterVersionedFile implemented.
447
        # - make a temporary versioned file of type target
448
        # - insert the source content into it one at a time
449
        # - join them
1594.2.11 by Robert Collins
Setup fast-code paths for copying into empty weaves and weave->empty knit.
450
        if not self.target.versions():
451
            target = self.target
452
        else:
453
            # Make a new target-format versioned file. 
454
            temp_source = self.target.create_empty("temp", MemoryTransport())
455
            target = temp_source
1563.2.13 by Robert Collins
InterVersionedFile implemented.
456
        graph = self.source.get_graph()
457
        order = topo_sort(graph.items())
1563.2.37 by Robert Collins
Merge in nested progress bars
458
        pb = ui.ui_factory.nested_progress_bar()
459
        try:
460
            for index, version in enumerate(order):
461
                pb.update('Converting versioned data', index, len(order))
1594.2.11 by Robert Collins
Setup fast-code paths for copying into empty weaves and weave->empty knit.
462
                target.add_lines(version,
463
                                 self.source.get_parents(version),
464
                                 self.source.get_lines(version))
1563.2.37 by Robert Collins
Merge in nested progress bars
465
            
466
            # this should hit the native code path for target
1594.2.11 by Robert Collins
Setup fast-code paths for copying into empty weaves and weave->empty knit.
467
            if target is not self.target:
468
                return self.target.join(temp_source,
469
                                        pb,
470
                                        msg,
471
                                        version_ids,
472
                                        ignore_missing)
1563.2.37 by Robert Collins
Merge in nested progress bars
473
        finally:
474
            pb.finished()
1563.2.13 by Robert Collins
InterVersionedFile implemented.
475
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
476
477
class InterVersionedFileTestProviderAdapter(object):
478
    """A tool to generate a suite testing multiple inter versioned-file classes.
479
480
    This is done by copying the test once for each interversionedfile provider
481
    and injecting the transport_server, transport_readonly_server,
482
    versionedfile_factory and versionedfile_factory_to classes into each copy.
483
    Each copy is also given a new id() to make it easy to identify.
484
    """
485
486
    def __init__(self, transport_server, transport_readonly_server, formats):
487
        self._transport_server = transport_server
488
        self._transport_readonly_server = transport_readonly_server
489
        self._formats = formats
490
    
491
    def adapt(self, test):
492
        result = TestSuite()
493
        for (interversionedfile_class,
494
             versionedfile_factory,
495
             versionedfile_factory_to) in self._formats:
496
            new_test = deepcopy(test)
497
            new_test.transport_server = self._transport_server
498
            new_test.transport_readonly_server = self._transport_readonly_server
499
            new_test.interversionedfile_class = interversionedfile_class
500
            new_test.versionedfile_factory = versionedfile_factory
501
            new_test.versionedfile_factory_to = versionedfile_factory_to
502
            def make_new_test_id():
503
                new_id = "%s(%s)" % (new_test.id(), interversionedfile_class.__name__)
504
                return lambda: new_id
505
            new_test.id = make_new_test_id()
506
            result.addTest(new_test)
507
        return result
508
509
    @staticmethod
510
    def default_test_list():
511
        """Generate the default list of interversionedfile permutations to test."""
512
        from bzrlib.weave import WeaveFile
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
513
        from bzrlib.knit import KnitVersionedFile
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
514
        result = []
515
        # test the fallback InterVersionedFile from weave to annotated knits
516
        result.append((InterVersionedFile, 
517
                       WeaveFile,
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
518
                       KnitVersionedFile))
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
519
        for optimiser in InterVersionedFile._optimisers:
520
            result.append((optimiser,
521
                           optimiser._matching_file_factory,
522
                           optimiser._matching_file_factory
523
                           ))
524
        # if there are specific combinations we want to use, we can add them 
525
        # here.
526
        return result