~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/versionedfile.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
#
3
3
# Authors:
4
4
#   Johan Rydberg <jrydberg@gnu.org>
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.
10
 
 
 
10
#
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.
15
 
 
 
15
#
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
19
19
 
20
20
"""Versioned text file storage api."""
21
21
 
22
 
 
 
22
from bzrlib.lazy_import import lazy_import
 
23
lazy_import(globals(), """
23
24
from copy import deepcopy
24
 
from unittest import TestSuite
25
 
 
26
 
 
27
 
import bzrlib.errors as errors
 
25
import unittest
 
26
 
 
27
from bzrlib import (
 
28
    errors,
 
29
    osutils,
 
30
    tsort,
 
31
    revision,
 
32
    ui,
 
33
    )
 
34
from bzrlib.transport.memory import MemoryTransport
 
35
""")
 
36
 
28
37
from bzrlib.inter import InterObject
29
 
from bzrlib.symbol_versioning import *
30
38
from bzrlib.textmerge import TextMerge
31
 
from bzrlib.transport.memory import MemoryTransport
32
 
from bzrlib.tsort import topo_sort
33
 
from bzrlib import ui
 
39
from bzrlib.symbol_versioning import (deprecated_function,
 
40
        deprecated_method,
 
41
        zero_eight,
 
42
        )
34
43
 
35
44
 
36
45
class VersionedFile(object):
51
60
        self.finished = False
52
61
        self._access_mode = access_mode
53
62
 
 
63
    @staticmethod
 
64
    def check_not_reserved_id(version_id):
 
65
        revision.check_not_reserved_id(version_id)
 
66
 
54
67
    def copy_to(self, name, transport):
55
68
        """Copy this versioned file to name on transport."""
56
69
        raise NotImplementedError(self.copy_to)
57
 
    
 
70
 
58
71
    @deprecated_method(zero_eight)
59
72
    def names(self):
60
73
        """Return a list of all the versions in this versioned file.
84
97
        :param sha1: The sha1 of the full text.
85
98
        :param delta: The delta instructions. See get_delta for details.
86
99
        """
 
100
        version_id = osutils.safe_revision_id(version_id)
 
101
        parents = [osutils.safe_revision_id(v) for v in parents]
87
102
        self._check_write_ok()
88
103
        if self.has_version(version_id):
89
104
            raise errors.RevisionAlreadyPresent(version_id, self)
126
141
                 provided back to future add_lines calls in the parent_texts
127
142
                 dictionary.
128
143
        """
 
144
        version_id = osutils.safe_revision_id(version_id)
 
145
        parents = [osutils.safe_revision_id(v) for v in parents]
129
146
        self._check_write_ok()
130
147
        return self._add_lines(version_id, parents, lines, parent_texts)
131
148
 
139
156
        
140
157
        This takes the same parameters as add_lines.
141
158
        """
 
159
        version_id = osutils.safe_revision_id(version_id)
 
160
        parents = [osutils.safe_revision_id(v) for v in parents]
142
161
        self._check_write_ok()
143
162
        return self._add_lines_with_ghosts(version_id, parents, lines,
144
163
                                           parent_texts)
170
189
        if self._access_mode != 'w':
171
190
            raise errors.ReadOnlyObjectDirtiedError(self)
172
191
 
 
192
    def enable_cache(self):
 
193
        """Tell this versioned file that it should cache any data it reads.
 
194
        
 
195
        This is advisory, implementations do not have to support caching.
 
196
        """
 
197
        pass
 
198
    
173
199
    def clear_cache(self):
174
 
        """Remove any data cached in the versioned file object."""
 
200
        """Remove any data cached in the versioned file object.
 
201
 
 
202
        This only needs to be supported if caches are supported
 
203
        """
 
204
        pass
175
205
 
176
206
    def clone_text(self, new_version_id, old_version_id, parents):
177
207
        """Add an identical text to old_version_id as new_version_id.
181
211
 
182
212
        Must raise RevisionAlreadyPresent if the new version is
183
213
        already present in file history."""
 
214
        new_version_id = osutils.safe_revision_id(new_version_id)
 
215
        old_version_id = osutils.safe_revision_id(old_version_id)
184
216
        self._check_write_ok()
185
217
        return self._clone_text(new_version_id, old_version_id, parents)
186
218
 
197
229
        """
198
230
        raise NotImplementedError(self.create_empty)
199
231
 
200
 
    def fix_parents(self, version, new_parents):
 
232
    def fix_parents(self, version_id, new_parents):
201
233
        """Fix the parents list for version.
202
234
        
203
235
        This is done by appending a new version to the index
205
237
        the parents list must be a superset of the current
206
238
        list.
207
239
        """
 
240
        version_id = osutils.safe_revision_id(version_id)
 
241
        new_parents = [osutils.safe_revision_id(p) for p in new_parents]
208
242
        self._check_write_ok()
209
 
        return self._fix_parents(version, new_parents)
 
243
        return self._fix_parents(version_id, new_parents)
210
244
 
211
 
    def _fix_parents(self, version, new_parents):
 
245
    def _fix_parents(self, version_id, new_parents):
212
246
        """Helper for fix_parents."""
213
247
        raise NotImplementedError(self.fix_parents)
214
248
 
220
254
        """
221
255
        raise NotImplementedError(self.get_delta)
222
256
 
223
 
    def get_deltas(self, versions):
 
257
    def get_deltas(self, version_ids):
224
258
        """Get multiple deltas at once for constructing versions.
225
259
        
226
260
        :return: dict(version_id:(delta_parent, sha1, noeol, delta))
228
262
        version_id is the version_id created by that delta.
229
263
        """
230
264
        result = {}
231
 
        for version in versions:
232
 
            result[version] = self.get_delta(version)
 
265
        for version_id in version_ids:
 
266
            result[version_id] = self.get_delta(version_id)
233
267
        return result
234
268
 
235
269
    def get_sha1(self, version_id):
252
286
        return ''.join(self.get_lines(version_id))
253
287
    get_string = get_text
254
288
 
 
289
    def get_texts(self, version_ids):
 
290
        """Return the texts of listed versions as a list of strings.
 
291
 
 
292
        Raises RevisionNotPresent if version is not present in
 
293
        file history.
 
294
        """
 
295
        return [''.join(self.get_lines(v)) for v in version_ids]
 
296
 
255
297
    def get_lines(self, version_id):
256
298
        """Return version contents as a sequence of lines.
257
299
 
287
329
        
288
330
        Ghosts are not listed or referenced in the graph.
289
331
        :param version_ids: Versions to select.
290
 
                            None means retreive all versions.
 
332
                            None means retrieve all versions.
291
333
        """
292
334
        result = {}
293
335
        if version_ids is None:
294
336
            for version in self.versions():
295
337
                result[version] = self.get_parents(version)
296
338
        else:
297
 
            pending = set(version_ids)
 
339
            pending = set(osutils.safe_revision_id(v) for v in version_ids)
298
340
            while pending:
299
341
                version = pending.pop()
300
342
                if version in result:
381
423
            version_ids,
382
424
            ignore_missing)
383
425
 
384
 
    def iter_lines_added_or_present_in_versions(self, version_ids=None):
 
426
    def iter_lines_added_or_present_in_versions(self, version_ids=None, 
 
427
                                                pb=None):
385
428
        """Iterate over the lines in the versioned file from version_ids.
386
429
 
387
430
        This may return lines from other versions, and does not return the
388
431
        specific version marker at this point. The api may be changed
389
432
        during development to include the version that the versioned file
390
433
        thinks is relevant, but given that such hints are just guesses,
391
 
        its better not to have it if we dont need it.
 
434
        its better not to have it if we don't need it.
 
435
 
 
436
        If a progress bar is supplied, it may be used to indicate progress.
 
437
        The caller is responsible for cleaning up progress bars (because this
 
438
        is an iterator).
392
439
 
393
440
        NOTES: Lines are normalised: they will all have \n terminators.
394
441
               Lines are returned in arbitrary order.
446
493
        """
447
494
        raise NotImplementedError(VersionedFile.plan_merge)
448
495
        
449
 
    def weave_merge(self, plan, a_marker=TextMerge.A_MARKER, 
 
496
    def weave_merge(self, plan, a_marker=TextMerge.A_MARKER,
450
497
                    b_marker=TextMerge.B_MARKER):
451
498
        return PlanWeaveMerge(plan, a_marker, b_marker).merge_lines()[0]
452
499
 
483
530
       
484
531
        # We previously considered either 'unchanged' or 'killed-both' lines
485
532
        # to be possible places to resynchronize.  However, assuming agreement
486
 
        # on killed-both lines may be too agressive. -- mbp 20060324
 
533
        # on killed-both lines may be too aggressive. -- mbp 20060324
487
534
        for state, line in self.plan:
488
535
            if state == 'unchanged':
489
536
                # resync and flush queued conflicts changes if any
536
583
    InterVersionedFile.get(other).method_name(parameters).
537
584
    """
538
585
 
539
 
    _optimisers = set()
 
586
    _optimisers = []
540
587
    """The available optimised InterVersionedFile types."""
541
588
 
542
589
    def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
563
610
            target = temp_source
564
611
        version_ids = self._get_source_version_ids(version_ids, ignore_missing)
565
612
        graph = self.source.get_graph(version_ids)
566
 
        order = topo_sort(graph.items())
 
613
        order = tsort.topo_sort(graph.items())
567
614
        pb = ui.ui_factory.nested_progress_bar()
568
615
        parent_texts = {}
569
616
        try:
621
668
            # None cannot be in source.versions
622
669
            return set(self.source.versions())
623
670
        else:
 
671
            version_ids = [osutils.safe_revision_id(v) for v in version_ids]
624
672
            if ignore_missing:
625
673
                return set(self.source.versions()).intersection(set(version_ids))
626
674
            else:
638
686
class InterVersionedFileTestProviderAdapter(object):
639
687
    """A tool to generate a suite testing multiple inter versioned-file classes.
640
688
 
641
 
    This is done by copying the test once for each interversionedfile provider
 
689
    This is done by copying the test once for each InterVersionedFile provider
642
690
    and injecting the transport_server, transport_readonly_server,
643
691
    versionedfile_factory and versionedfile_factory_to classes into each copy.
644
692
    Each copy is also given a new id() to make it easy to identify.
650
698
        self._formats = formats
651
699
    
652
700
    def adapt(self, test):
653
 
        result = TestSuite()
 
701
        result = unittest.TestSuite()
654
702
        for (interversionedfile_class,
655
703
             versionedfile_factory,
656
704
             versionedfile_factory_to) in self._formats: