~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/versionedfile.py

  • Committer: Alexander Belchenko
  • Date: 2007-01-04 23:36:44 UTC
  • mfrom: (2224 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2225.
  • Revision ID: bialix@ukr.net-20070104233644-7znkxoj9b0y7ev28
merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
from bzrlib.lazy_import import lazy_import
23
23
lazy_import(globals(), """
 
24
from copy import deepcopy
 
25
import unittest
24
26
 
25
27
from bzrlib import (
26
28
    errors,
27
 
    osutils,
28
 
    multiparent,
29
29
    tsort,
30
 
    revision,
31
30
    ui,
32
31
    )
33
32
from bzrlib.transport.memory import MemoryTransport
34
33
""")
35
34
 
36
 
from cStringIO import StringIO
37
 
 
38
35
from bzrlib.inter import InterObject
39
36
from bzrlib.textmerge import TextMerge
40
37
from bzrlib.symbol_versioning import (deprecated_function,
61
58
        self.finished = False
62
59
        self._access_mode = access_mode
63
60
 
64
 
    @staticmethod
65
 
    def check_not_reserved_id(version_id):
66
 
        revision.check_not_reserved_id(version_id)
67
 
 
68
61
    def copy_to(self, name, transport):
69
62
        """Copy this versioned file to name on transport."""
70
63
        raise NotImplementedError(self.copy_to)
98
91
        :param sha1: The sha1 of the full text.
99
92
        :param delta: The delta instructions. See get_delta for details.
100
93
        """
101
 
        version_id = osutils.safe_revision_id(version_id)
102
 
        parents = [osutils.safe_revision_id(v) for v in parents]
103
94
        self._check_write_ok()
104
95
        if self.has_version(version_id):
105
96
            raise errors.RevisionAlreadyPresent(version_id, self)
142
133
                 provided back to future add_lines calls in the parent_texts
143
134
                 dictionary.
144
135
        """
145
 
        version_id = osutils.safe_revision_id(version_id)
146
 
        parents = [osutils.safe_revision_id(v) for v in parents]
147
136
        self._check_write_ok()
148
137
        return self._add_lines(version_id, parents, lines, parent_texts)
149
138
 
157
146
        
158
147
        This takes the same parameters as add_lines.
159
148
        """
160
 
        version_id = osutils.safe_revision_id(version_id)
161
 
        parents = [osutils.safe_revision_id(v) for v in parents]
162
149
        self._check_write_ok()
163
150
        return self._add_lines_with_ghosts(version_id, parents, lines,
164
151
                                           parent_texts)
212
199
 
213
200
        Must raise RevisionAlreadyPresent if the new version is
214
201
        already present in file history."""
215
 
        new_version_id = osutils.safe_revision_id(new_version_id)
216
 
        old_version_id = osutils.safe_revision_id(old_version_id)
217
202
        self._check_write_ok()
218
203
        return self._clone_text(new_version_id, old_version_id, parents)
219
204
 
230
215
        """
231
216
        raise NotImplementedError(self.create_empty)
232
217
 
233
 
    def fix_parents(self, version_id, new_parents):
 
218
    def fix_parents(self, version, new_parents):
234
219
        """Fix the parents list for version.
235
220
        
236
221
        This is done by appending a new version to the index
238
223
        the parents list must be a superset of the current
239
224
        list.
240
225
        """
241
 
        version_id = osutils.safe_revision_id(version_id)
242
 
        new_parents = [osutils.safe_revision_id(p) for p in new_parents]
243
226
        self._check_write_ok()
244
 
        return self._fix_parents(version_id, new_parents)
 
227
        return self._fix_parents(version, new_parents)
245
228
 
246
 
    def _fix_parents(self, version_id, new_parents):
 
229
    def _fix_parents(self, version, new_parents):
247
230
        """Helper for fix_parents."""
248
231
        raise NotImplementedError(self.fix_parents)
249
232
 
255
238
        """
256
239
        raise NotImplementedError(self.get_delta)
257
240
 
258
 
    def get_deltas(self, version_ids):
 
241
    def get_deltas(self, versions):
259
242
        """Get multiple deltas at once for constructing versions.
260
243
        
261
244
        :return: dict(version_id:(delta_parent, sha1, noeol, delta))
263
246
        version_id is the version_id created by that delta.
264
247
        """
265
248
        result = {}
266
 
        for version_id in version_ids:
267
 
            result[version_id] = self.get_delta(version_id)
 
249
        for version in versions:
 
250
            result[version] = self.get_delta(version)
268
251
        return result
269
252
 
270
 
    def make_mpdiffs(self, version_ids):
271
 
        """Create multiparent diffs for specified versions"""
272
 
        knit_versions = set()
273
 
        for version_id in version_ids:
274
 
            knit_versions.add(version_id)
275
 
            knit_versions.update(self.get_parents(version_id))
276
 
        lines = dict(zip(knit_versions,
277
 
            self._get_lf_split_line_list(knit_versions)))
278
 
        diffs = []
279
 
        for version_id in version_ids:
280
 
            target = lines[version_id]
281
 
            parents = [lines[p] for p in self.get_parents(version_id)]
282
 
            if len(parents) > 0:
283
 
                left_parent_blocks = self._extract_blocks(version_id,
284
 
                                                          parents[0], target)
285
 
            else:
286
 
                left_parent_blocks = None
287
 
            diffs.append(multiparent.MultiParent.from_lines(target, parents,
288
 
                         left_parent_blocks))
289
 
        return diffs
290
 
 
291
 
    def _extract_blocks(self, version_id, source, target):
292
 
        return None
293
 
 
294
 
    def add_mpdiffs(self, records):
295
 
        """Add mpdiffs to this versionedfile
296
 
 
297
 
        Records should be iterables of version, parents, expected_sha1,
298
 
        mpdiff.  mpdiff should be a MultiParent instance.
299
 
        """
300
 
        vf_parents = {}
301
 
        for version, parents, expected_sha1, mpdiff in records:
302
 
            mpvf = multiparent.MultiMemoryVersionedFile()
303
 
            needed_parents = [p for p in parents if not mpvf.has_version(p)]
304
 
            parent_lines = self._get_lf_split_line_list(needed_parents)
305
 
            for parent_id, lines in zip(needed_parents, parent_lines):
306
 
                mpvf.add_version(lines, parent_id, [])
307
 
            mpvf.add_diff(mpdiff, version, parents)
308
 
            lines = mpvf.get_line_list([version])[0]
309
 
            version_text = self.add_lines(version, parents, lines, vf_parents)
310
 
            vf_parents[version] = version_text
311
 
            if expected_sha1 != self.get_sha1(version):
312
 
                raise errors.VersionedFileInvalidChecksum(version)
313
 
 
314
253
    def get_sha1(self, version_id):
315
254
        """Get the stored sha1 sum for the given revision.
316
255
        
318
257
        """
319
258
        raise NotImplementedError(self.get_sha1)
320
259
 
321
 
    def get_sha1s(self, version_ids):
322
 
        """Get the stored sha1 sums for the given revisions.
323
 
 
324
 
        :param version_ids: The names of the versions to lookup
325
 
        :return: a list of sha1s in order according to the version_ids
326
 
        """
327
 
        raise NotImplementedError(self.get_sha1)
328
 
 
329
260
    def get_suffixes(self):
330
261
        """Return the file suffixes associated with this versioned file."""
331
262
        raise NotImplementedError(self.get_suffixes)
355
286
        """
356
287
        raise NotImplementedError(self.get_lines)
357
288
 
358
 
    def _get_lf_split_line_list(self, version_ids):
359
 
        return [StringIO(t).readlines() for t in self.get_texts(version_ids)]
360
 
 
361
 
    def get_ancestry(self, version_ids, topo_sorted=True):
 
289
    def get_ancestry(self, version_ids):
362
290
        """Return a list of all ancestors of given version(s). This
363
291
        will not include the null revision.
364
292
 
365
 
        This list will not be topologically sorted if topo_sorted=False is
366
 
        passed.
367
 
 
368
293
        Must raise RevisionNotPresent if any of the given versions are
369
294
        not present in file history."""
370
295
        if isinstance(version_ids, basestring):
390
315
        :param version_ids: Versions to select.
391
316
                            None means retrieve all versions.
392
317
        """
 
318
        result = {}
393
319
        if version_ids is None:
394
 
            return dict(self.iter_parents(self.versions()))
395
 
        result = {}
396
 
        pending = set(osutils.safe_revision_id(v) for v in version_ids)
397
 
        while pending:
398
 
            this_iteration = pending
399
 
            pending = set()
400
 
            for version, parents in self.iter_parents(this_iteration):
401
 
                result[version] = parents
 
320
            for version in self.versions():
 
321
                result[version] = self.get_parents(version)
 
322
        else:
 
323
            pending = set(version_ids)
 
324
            while pending:
 
325
                version = pending.pop()
 
326
                if version in result:
 
327
                    continue
 
328
                parents = self.get_parents(version)
402
329
                for parent in parents:
403
330
                    if parent in result:
404
331
                        continue
405
332
                    pending.add(parent)
 
333
                result[version] = parents
406
334
        return result
407
335
 
408
336
    def get_graph_with_ghosts(self):
498
426
        """
499
427
        raise NotImplementedError(self.iter_lines_added_or_present_in_versions)
500
428
 
501
 
    def iter_parents(self, version_ids):
502
 
        """Iterate through the parents for many version ids.
503
 
 
504
 
        :param version_ids: An iterable yielding version_ids.
505
 
        :return: An iterator that yields (version_id, parents). Requested 
506
 
            version_ids not present in the versioned file are simply skipped.
507
 
            The order is undefined, allowing for different optimisations in
508
 
            the underlying implementation.
509
 
        """
510
 
        for version_id in version_ids:
511
 
            try:
512
 
                yield version_id, tuple(self.get_parents(version_id))
513
 
            except errors.RevisionNotPresent:
514
 
                pass
515
 
 
516
429
    def transaction_finished(self):
517
430
        """The transaction that this file was opened in has finished.
518
431
 
739
652
            # None cannot be in source.versions
740
653
            return set(self.source.versions())
741
654
        else:
742
 
            version_ids = [osutils.safe_revision_id(v) for v in version_ids]
743
655
            if ignore_missing:
744
656
                return set(self.source.versions()).intersection(set(version_ids))
745
657
            else:
752
664
                    else:
753
665
                        new_version_ids.add(version)
754
666
                return new_version_ids
 
667
 
 
668
 
 
669
class InterVersionedFileTestProviderAdapter(object):
 
670
    """A tool to generate a suite testing multiple inter versioned-file classes.
 
671
 
 
672
    This is done by copying the test once for each InterVersionedFile provider
 
673
    and injecting the transport_server, transport_readonly_server,
 
674
    versionedfile_factory and versionedfile_factory_to classes into each copy.
 
675
    Each copy is also given a new id() to make it easy to identify.
 
676
    """
 
677
 
 
678
    def __init__(self, transport_server, transport_readonly_server, formats):
 
679
        self._transport_server = transport_server
 
680
        self._transport_readonly_server = transport_readonly_server
 
681
        self._formats = formats
 
682
    
 
683
    def adapt(self, test):
 
684
        result = unittest.TestSuite()
 
685
        for (interversionedfile_class,
 
686
             versionedfile_factory,
 
687
             versionedfile_factory_to) in self._formats:
 
688
            new_test = deepcopy(test)
 
689
            new_test.transport_server = self._transport_server
 
690
            new_test.transport_readonly_server = self._transport_readonly_server
 
691
            new_test.interversionedfile_class = interversionedfile_class
 
692
            new_test.versionedfile_factory = versionedfile_factory
 
693
            new_test.versionedfile_factory_to = versionedfile_factory_to
 
694
            def make_new_test_id():
 
695
                new_id = "%s(%s)" % (new_test.id(), interversionedfile_class.__name__)
 
696
                return lambda: new_id
 
697
            new_test.id = make_new_test_id()
 
698
            result.addTest(new_test)
 
699
        return result
 
700
 
 
701
    @staticmethod
 
702
    def default_test_list():
 
703
        """Generate the default list of interversionedfile permutations to test."""
 
704
        from bzrlib.weave import WeaveFile
 
705
        from bzrlib.knit import KnitVersionedFile
 
706
        result = []
 
707
        # test the fallback InterVersionedFile from annotated knits to weave
 
708
        result.append((InterVersionedFile, 
 
709
                       KnitVersionedFile,
 
710
                       WeaveFile))
 
711
        for optimiser in InterVersionedFile._optimisers:
 
712
            result.append((optimiser,
 
713
                           optimiser._matching_file_from_factory,
 
714
                           optimiser._matching_file_to_factory
 
715
                           ))
 
716
        # if there are specific combinations we want to use, we can add them 
 
717
        # here.
 
718
        return result