/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/versionedfile.py

  • Committer: Andrew Bennetts
  • Date: 2008-04-07 08:20:13 UTC
  • mfrom: (3340 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3344.
  • Revision ID: andrew.bennetts@canonical.com-20080407082013-ca1n1tqqon7ugxiy
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
    revision,
31
31
    ui,
32
32
    )
 
33
from bzrlib.graph import Graph
33
34
from bzrlib.transport.memory import MemoryTransport
34
35
""")
35
36
 
36
37
from cStringIO import StringIO
37
38
 
38
39
from bzrlib.inter import InterObject
 
40
from bzrlib.symbol_versioning import *
39
41
from bzrlib.textmerge import TextMerge
40
42
 
41
43
 
69
71
        """Return a unsorted list of versions."""
70
72
        raise NotImplementedError(self.versions)
71
73
 
 
74
    @deprecated_method(one_four)
72
75
    def has_ghost(self, version_id):
73
76
        """Returns whether version is present as a ghost."""
74
77
        raise NotImplementedError(self.has_ghost)
128
131
 
129
132
    def add_lines_with_ghosts(self, version_id, parents, lines,
130
133
        parent_texts=None, nostore_sha=None, random_id=False,
131
 
        check_content=True):
 
134
        check_content=True, left_matching_blocks=None):
132
135
        """Add lines to the versioned file, allowing ghosts to be present.
133
136
        
134
137
        This takes the same parameters as add_lines and returns the same.
135
138
        """
136
139
        self._check_write_ok()
137
140
        return self._add_lines_with_ghosts(version_id, parents, lines,
138
 
            parent_texts, nostore_sha, random_id, check_content)
 
141
            parent_texts, nostore_sha, random_id, check_content, left_matching_blocks)
139
142
 
140
143
    def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts,
141
 
        nostore_sha, random_id, check_content):
 
144
        nostore_sha, random_id, check_content, left_matching_blocks):
142
145
        """Helper to do class specific add_lines_with_ghosts."""
143
146
        raise NotImplementedError(self.add_lines_with_ghosts)
144
147
 
194
197
        """Helper function to do the _clone_text work."""
195
198
        raise NotImplementedError(self.clone_text)
196
199
 
197
 
    def create_empty(self, name, transport, mode=None):
198
 
        """Create a new versioned file of this exact type.
199
 
 
200
 
        :param name: the file name
201
 
        :param transport: the transport
202
 
        :param mode: optional file mode.
203
 
        """
204
 
        raise NotImplementedError(self.create_empty)
205
 
 
206
200
    def get_format_signature(self):
207
201
        """Get a text description of the data encoding in this file.
208
202
        
213
207
    def make_mpdiffs(self, version_ids):
214
208
        """Create multiparent diffs for specified versions."""
215
209
        knit_versions = set()
 
210
        knit_versions.update(version_ids)
 
211
        parent_map = self.get_parent_map(version_ids)
216
212
        for version_id in version_ids:
217
 
            knit_versions.add(version_id)
218
 
            knit_versions.update(self.get_parents(version_id))
 
213
            try:
 
214
                knit_versions.update(parent_map[version_id])
 
215
            except KeyError:
 
216
                raise RevisionNotPresent(version_id, self)
 
217
        # We need to filter out ghosts, because we can't diff against them.
 
218
        knit_versions = set(self.get_parent_map(knit_versions).keys())
219
219
        lines = dict(zip(knit_versions,
220
220
            self._get_lf_split_line_list(knit_versions)))
221
221
        diffs = []
222
222
        for version_id in version_ids:
223
223
            target = lines[version_id]
224
 
            parents = [lines[p] for p in self.get_parents(version_id)]
 
224
            try:
 
225
                parents = [lines[p] for p in parent_map[version_id] if p in
 
226
                    knit_versions]
 
227
            except KeyError:
 
228
                raise RevisionNotPresent(version_id, self)
225
229
            if len(parents) > 0:
226
230
                left_parent_blocks = self._extract_blocks(version_id,
227
231
                                                          parents[0], target)
251
255
        for version, parent_ids, expected_sha1, mpdiff in records:
252
256
            needed_parents.update(p for p in parent_ids
253
257
                                  if not mpvf.has_version(p))
254
 
        for parent_id, lines in zip(needed_parents,
255
 
                                 self._get_lf_split_line_list(needed_parents)):
 
258
        present_parents = set(self.get_parent_map(needed_parents).keys())
 
259
        for parent_id, lines in zip(present_parents,
 
260
                                 self._get_lf_split_line_list(present_parents)):
256
261
            mpvf.add_version(lines, parent_id, [])
257
262
        for (version, parent_ids, expected_sha1, mpdiff), lines in\
258
263
            zip(records, mpvf.get_line_list(versions)):
261
266
                    mpvf.get_diff(parent_ids[0]).num_lines()))
262
267
            else:
263
268
                left_matching_blocks = None
264
 
            _, _, version_text = self.add_lines(version, parent_ids, lines,
265
 
                vf_parents, left_matching_blocks=left_matching_blocks)
 
269
            try:
 
270
                _, _, version_text = self.add_lines_with_ghosts(version,
 
271
                    parent_ids, lines, vf_parents,
 
272
                    left_matching_blocks=left_matching_blocks)
 
273
            except NotImplementedError:
 
274
                # The vf can't handle ghosts, so add lines normally, which will
 
275
                # (reasonably) fail if there are ghosts in the data.
 
276
                _, _, version_text = self.add_lines(version,
 
277
                    parent_ids, lines, vf_parents,
 
278
                    left_matching_blocks=left_matching_blocks)
266
279
            vf_parents[version] = version_text
267
280
        for (version, parent_ids, expected_sha1, mpdiff), sha1 in\
268
281
             zip(records, self.get_sha1s(versions)):
363
376
                    pending.add(parent)
364
377
        return result
365
378
 
 
379
    @deprecated_method(one_four)
366
380
    def get_graph_with_ghosts(self):
367
381
        """Return a graph for the entire versioned file.
368
382
        
371
385
        """
372
386
        raise NotImplementedError(self.get_graph_with_ghosts)
373
387
 
 
388
    def get_parent_map(self, version_ids):
 
389
        """Get a map of the parents of version_ids.
 
390
 
 
391
        :param version_ids: The version ids to look up parents for.
 
392
        :return: A mapping from version id to parents.
 
393
        """
 
394
        raise NotImplementedError(self.get_parent_map)
 
395
 
 
396
    @deprecated_method(one_four)
374
397
    def get_parents(self, version_id):
375
398
        """Return version names for parents of a version.
376
399
 
377
400
        Must raise RevisionNotPresent if version is not present in
378
401
        file history.
379
402
        """
380
 
        raise NotImplementedError(self.get_parents)
 
403
        try:
 
404
            all = self.get_parent_map([version_id])[version_id]
 
405
        except KeyError:
 
406
            raise errors.RevisionNotPresent(version_id, self)
 
407
        result = []
 
408
        parent_parents = self.get_parent_map(all)
 
409
        for version_id in all:
 
410
            if version_id in parent_parents:
 
411
                result.append(version_id)
 
412
        return result
381
413
 
382
414
    def get_parents_with_ghosts(self, version_id):
383
415
        """Return version names for parents of version_id.
388
420
        Ghosts that are known about will be included in the parent list,
389
421
        but are not explicitly marked.
390
422
        """
391
 
        raise NotImplementedError(self.get_parents_with_ghosts)
 
423
        try:
 
424
            return list(self.get_parent_map([version_id])[version_id])
 
425
        except KeyError:
 
426
            raise errors.RevisionNotPresent(version_id, self)
392
427
 
393
428
    def annotate_iter(self, version_id):
394
429
        """Yield list of (version-id, line) pairs for the specified
451
486
            The order is undefined, allowing for different optimisations in
452
487
            the underlying implementation.
453
488
        """
454
 
        for version_id in version_ids:
455
 
            try:
456
 
                yield version_id, tuple(self.get_parents(version_id))
457
 
            except errors.RevisionNotPresent:
458
 
                pass
 
489
        return self.get_parent_map(version_ids).iteritems()
459
490
 
460
491
    def transaction_finished(self):
461
492
        """The transaction that this file was opened in has finished.
547
578
            raise ValueError('Parents may not be None')
548
579
        if lines is None:
549
580
            raise ValueError('Lines may not be None')
550
 
        self._parents[version_id] = parents
 
581
        self._parents[version_id] = tuple(parents)
551
582
        self._lines[version_id] = lines
552
583
 
553
584
    def get_lines(self, version_id):
590
621
            ancestry.update(self.get_ancestry(parent, topo_sorted=False))
591
622
        return ancestry
592
623
 
593
 
    def get_parents(self, version_id):
594
 
        """See VersionedFile.get_parents"""
595
 
        parents = self._parents.get(version_id)
596
 
        if parents is not None:
597
 
            return parents
 
624
    def get_parent_map(self, version_ids):
 
625
        """See VersionedFile.get_parent_map"""
 
626
        result = {}
 
627
        pending = set(version_ids)
 
628
        for key in version_ids:
 
629
            try:
 
630
                result[key] = self._parents[key]
 
631
            except KeyError:
 
632
                pass
 
633
        pending = pending - set(result.keys())
598
634
        for versionedfile in self.fallback_versionedfiles:
599
 
            try:
600
 
                return versionedfile.get_parents(version_id)
601
 
            except errors.RevisionNotPresent:
602
 
                continue
603
 
        else:
604
 
            raise errors.RevisionNotPresent(version_id, self._file_id)
 
635
            parents = versionedfile.get_parent_map(pending)
 
636
            result.update(parents)
 
637
            pending = pending - set(parents.keys())
 
638
            if not pending:
 
639
                return result
 
640
        return result
605
641
 
606
642
    def _get_graph(self):
607
643
        from bzrlib.graph import (
720
756
        are not present in the other file's history unless ignore_missing is 
721
757
        supplied in which case they are silently skipped.
722
758
        """
723
 
        # the default join: 
724
 
        # - if the target is empty, just add all the versions from 
725
 
        #   source to target, otherwise:
726
 
        # - make a temporary versioned file of type target
727
 
        # - insert the source content into it one at a time
728
 
        # - join them
729
 
        if not self.target.versions():
730
 
            target = self.target
731
 
        else:
732
 
            # Make a new target-format versioned file. 
733
 
            temp_source = self.target.create_empty("temp", MemoryTransport())
734
 
            target = temp_source
 
759
        target = self.target
735
760
        version_ids = self._get_source_version_ids(version_ids, ignore_missing)
736
 
        graph = self.source.get_graph(version_ids)
737
 
        order = tsort.topo_sort(graph.items())
 
761
        graph = Graph(self.source)
 
762
        search = graph._make_breadth_first_searcher(version_ids)
 
763
        transitive_ids = set()
 
764
        map(transitive_ids.update, list(search))
 
765
        parent_map = self.source.get_parent_map(transitive_ids)
 
766
        order = tsort.topo_sort(parent_map.items())
738
767
        pb = ui.ui_factory.nested_progress_bar()
739
768
        parent_texts = {}
740
769
        try:
754
783
            total = len(order)
755
784
            for index, version in enumerate(order):
756
785
                pb.update('Converting versioned data', index, total)
 
786
                if version in target:
 
787
                    continue
757
788
                _, _, parent_text = target.add_lines(version,
758
 
                                               self.source.get_parents(version),
 
789
                                               parent_map[version],
759
790
                                               self.source.get_lines(version),
760
791
                                               parent_texts=parent_texts)
761
792
                parent_texts[version] = parent_text
762
 
            
763
 
            # this should hit the native code path for target
764
 
            if target is not self.target:
765
 
                return self.target.join(temp_source,
766
 
                                        pb,
767
 
                                        msg,
768
 
                                        version_ids,
769
 
                                        ignore_missing)
770
 
            else:
771
 
                return total
 
793
            return total
772
794
        finally:
773
795
            pb.finished()
774
796