/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

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
77
77
        """Returns whether version is present."""
78
78
        raise NotImplementedError(self.has_version)
79
79
 
80
 
    def add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
81
 
        """Add a text to the versioned file via a pregenerated delta.
82
 
 
83
 
        :param version_id: The version id being added.
84
 
        :param parents: The parents of the version_id.
85
 
        :param delta_parent: The parent this delta was created against.
86
 
        :param sha1: The sha1 of the full text.
87
 
        :param delta: The delta instructions. See get_delta for details.
88
 
        """
89
 
        version_id = osutils.safe_revision_id(version_id)
90
 
        parents = [osutils.safe_revision_id(v) for v in parents]
91
 
        self._check_write_ok()
92
 
        if self.has_version(version_id):
93
 
            raise errors.RevisionAlreadyPresent(version_id, self)
94
 
        return self._add_delta(version_id, parents, delta_parent, sha1, noeol, delta)
95
 
 
96
 
    def _add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
97
 
        """Class specific routine to add a delta.
98
 
 
99
 
        This generic version simply applies the delta to the delta_parent and
100
 
        then inserts it.
101
 
        """
102
 
        # strip annotation from delta
103
 
        new_delta = []
104
 
        for start, stop, delta_len, delta_lines in delta:
105
 
            new_delta.append((start, stop, delta_len, [text for origin, text in delta_lines]))
106
 
        if delta_parent is not None:
107
 
            parent_full = self.get_lines(delta_parent)
108
 
        else:
109
 
            parent_full = []
110
 
        new_full = self._apply_delta(parent_full, new_delta)
111
 
        # its impossible to have noeol on an empty file
112
 
        if noeol and new_full[-1][-1] == '\n':
113
 
            new_full[-1] = new_full[-1][:-1]
114
 
        self.add_lines(version_id, parents, new_full)
115
 
 
116
80
    def add_lines(self, version_id, parents, lines, parent_texts=None,
117
 
                  left_matching_blocks=None):
 
81
        left_matching_blocks=None, nostore_sha=None, random_id=False,
 
82
        check_content=True):
118
83
        """Add a single text on top of the versioned file.
119
84
 
120
85
        Must raise RevisionAlreadyPresent if the new version is
122
87
 
123
88
        Must raise RevisionNotPresent if any of the given parents are
124
89
        not present in file history.
 
90
 
 
91
        :param lines: A list of lines. Each line must be a bytestring. And all
 
92
            of them except the last must be terminated with \n and contain no
 
93
            other \n's. The last line may either contain no \n's or a single
 
94
            terminated \n. If the lines list does meet this constraint the add
 
95
            routine may error or may succeed - but you will be unable to read
 
96
            the data back accurately. (Checking the lines have been split
 
97
            correctly is expensive and extremely unlikely to catch bugs so it
 
98
            is not done at runtime unless check_content is True.)
125
99
        :param parent_texts: An optional dictionary containing the opaque 
126
 
             representations of some or all of the parents of 
127
 
             version_id to allow delta optimisations. 
128
 
             VERY IMPORTANT: the texts must be those returned
129
 
             by add_lines or data corruption can be caused.
 
100
            representations of some or all of the parents of version_id to
 
101
            allow delta optimisations.  VERY IMPORTANT: the texts must be those
 
102
            returned by add_lines or data corruption can be caused.
130
103
        :param left_matching_blocks: a hint about which areas are common
131
104
            between the text and its left-hand-parent.  The format is
132
105
            the SequenceMatcher.get_matching_blocks format.
133
 
        :return: An opaque representation of the inserted version which can be
134
 
                 provided back to future add_lines calls in the parent_texts
135
 
                 dictionary.
 
106
        :param nostore_sha: Raise ExistingContent and do not add the lines to
 
107
            the versioned file if the digest of the lines matches this.
 
108
        :param random_id: If True a random id has been selected rather than
 
109
            an id determined by some deterministic process such as a converter
 
110
            from a foreign VCS. When True the backend may choose not to check
 
111
            for uniqueness of the resulting key within the versioned file, so
 
112
            this should only be done when the result is expected to be unique
 
113
            anyway.
 
114
        :param check_content: If True, the lines supplied are verified to be
 
115
            bytestrings that are correctly formed lines.
 
116
        :return: The text sha1, the number of bytes in the text, and an opaque
 
117
                 representation of the inserted version which can be provided
 
118
                 back to future add_lines calls in the parent_texts dictionary.
136
119
        """
137
 
        version_id = osutils.safe_revision_id(version_id)
138
 
        parents = [osutils.safe_revision_id(v) for v in parents]
139
120
        self._check_write_ok()
140
121
        return self._add_lines(version_id, parents, lines, parent_texts,
141
 
                               left_matching_blocks)
 
122
            left_matching_blocks, nostore_sha, random_id, check_content)
142
123
 
143
124
    def _add_lines(self, version_id, parents, lines, parent_texts,
144
 
                   left_matching_blocks):
 
125
        left_matching_blocks, nostore_sha, random_id, check_content):
145
126
        """Helper to do the class specific add_lines."""
146
127
        raise NotImplementedError(self.add_lines)
147
128
 
148
129
    def add_lines_with_ghosts(self, version_id, parents, lines,
149
 
                              parent_texts=None):
 
130
        parent_texts=None, nostore_sha=None, random_id=False,
 
131
        check_content=True):
150
132
        """Add lines to the versioned file, allowing ghosts to be present.
151
133
        
152
 
        This takes the same parameters as add_lines.
 
134
        This takes the same parameters as add_lines and returns the same.
153
135
        """
154
 
        version_id = osutils.safe_revision_id(version_id)
155
 
        parents = [osutils.safe_revision_id(v) for v in parents]
156
136
        self._check_write_ok()
157
137
        return self._add_lines_with_ghosts(version_id, parents, lines,
158
 
                                           parent_texts)
 
138
            parent_texts, nostore_sha, random_id, check_content)
159
139
 
160
 
    def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts):
 
140
    def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts,
 
141
        nostore_sha, random_id, check_content):
161
142
        """Helper to do class specific add_lines_with_ghosts."""
162
143
        raise NotImplementedError(self.add_lines_with_ghosts)
163
144
 
206
187
 
207
188
        Must raise RevisionAlreadyPresent if the new version is
208
189
        already present in file history."""
209
 
        new_version_id = osutils.safe_revision_id(new_version_id)
210
 
        old_version_id = osutils.safe_revision_id(old_version_id)
211
190
        self._check_write_ok()
212
191
        return self._clone_text(new_version_id, old_version_id, parents)
213
192
 
224
203
        """
225
204
        raise NotImplementedError(self.create_empty)
226
205
 
227
 
    def fix_parents(self, version_id, new_parents):
228
 
        """Fix the parents list for version.
229
 
        
230
 
        This is done by appending a new version to the index
231
 
        with identical data except for the parents list.
232
 
        the parents list must be a superset of the current
233
 
        list.
234
 
        """
235
 
        version_id = osutils.safe_revision_id(version_id)
236
 
        new_parents = [osutils.safe_revision_id(p) for p in new_parents]
237
 
        self._check_write_ok()
238
 
        return self._fix_parents(version_id, new_parents)
239
 
 
240
 
    def _fix_parents(self, version_id, new_parents):
241
 
        """Helper for fix_parents."""
242
 
        raise NotImplementedError(self.fix_parents)
243
 
 
244
 
    def get_delta(self, version):
245
 
        """Get a delta for constructing version from some other version.
246
 
        
247
 
        :return: (delta_parent, sha1, noeol, delta)
248
 
        Where delta_parent is a version id or None to indicate no parent.
249
 
        """
250
 
        raise NotImplementedError(self.get_delta)
251
 
 
252
 
    def get_deltas(self, version_ids):
253
 
        """Get multiple deltas at once for constructing versions.
254
 
        
255
 
        :return: dict(version_id:(delta_parent, sha1, noeol, delta))
256
 
        Where delta_parent is a version id or None to indicate no parent, and
257
 
        version_id is the version_id created by that delta.
258
 
        """
259
 
        result = {}
260
 
        for version_id in version_ids:
261
 
            result[version_id] = self.get_delta(version_id)
262
 
        return result
263
 
 
264
206
    def get_format_signature(self):
265
207
        """Get a text description of the data encoding in this file.
266
208
        
267
 
        :since: 0.19
 
209
        :since: 0.90
268
210
        """
269
211
        raise NotImplementedError(self.get_format_signature)
270
212
 
271
213
    def make_mpdiffs(self, version_ids):
272
 
        """Create multiparent diffs for specified versions"""
 
214
        """Create multiparent diffs for specified versions."""
273
215
        knit_versions = set()
274
216
        for version_id in version_ids:
275
217
            knit_versions.add(version_id)
293
235
        return None
294
236
 
295
237
    def add_mpdiffs(self, records):
296
 
        """Add mpdiffs to this versionedfile
 
238
        """Add mpdiffs to this VersionedFile.
297
239
 
298
240
        Records should be iterables of version, parents, expected_sha1,
299
 
        mpdiff.  mpdiff should be a MultiParent instance.
 
241
        mpdiff. mpdiff should be a MultiParent instance.
300
242
        """
 
243
        # Does this need to call self._check_write_ok()? (IanC 20070919)
301
244
        vf_parents = {}
302
245
        mpvf = multiparent.MultiMemoryVersionedFile()
303
246
        versions = []
318
261
                    mpvf.get_diff(parent_ids[0]).num_lines()))
319
262
            else:
320
263
                left_matching_blocks = None
321
 
            version_text = self.add_lines(version, parent_ids, lines,
 
264
            _, _, version_text = self.add_lines(version, parent_ids, lines,
322
265
                vf_parents, left_matching_blocks=left_matching_blocks)
323
266
            vf_parents[version] = version_text
324
267
        for (version, parent_ids, expected_sha1, mpdiff), sha1 in\
329
272
    def get_sha1(self, version_id):
330
273
        """Get the stored sha1 sum for the given revision.
331
274
        
332
 
        :param name: The name of the version to lookup
 
275
        :param version_id: The name of the version to lookup
333
276
        """
334
277
        raise NotImplementedError(self.get_sha1)
335
278
 
339
282
        :param version_ids: The names of the versions to lookup
340
283
        :return: a list of sha1s in order according to the version_ids
341
284
        """
342
 
        raise NotImplementedError(self.get_sha1)
 
285
        raise NotImplementedError(self.get_sha1s)
343
286
 
344
287
    def get_suffixes(self):
345
288
        """Return the file suffixes associated with this versioned file."""
408
351
        if version_ids is None:
409
352
            return dict(self.iter_parents(self.versions()))
410
353
        result = {}
411
 
        pending = set(osutils.safe_revision_id(v) for v in version_ids)
 
354
        pending = set(version_ids)
412
355
        while pending:
413
356
            this_iteration = pending
414
357
            pending = set()
451
394
        """Yield list of (version-id, line) pairs for the specified
452
395
        version.
453
396
 
454
 
        Must raise RevisionNotPresent if any of the given versions are
 
397
        Must raise RevisionNotPresent if the given version is
455
398
        not present in file history.
456
399
        """
457
400
        raise NotImplementedError(self.annotate_iter)
459
402
    def annotate(self, version_id):
460
403
        return list(self.annotate_iter(version_id))
461
404
 
462
 
    def _apply_delta(self, lines, delta):
463
 
        """Apply delta to lines."""
464
 
        lines = list(lines)
465
 
        offset = 0
466
 
        for start, end, count, delta_lines in delta:
467
 
            lines[offset+start:offset+end] = delta_lines
468
 
            offset = offset + (start - end) + count
469
 
        return lines
470
 
 
471
405
    def join(self, other, pb=None, msg=None, version_ids=None,
472
406
             ignore_missing=False):
473
407
        """Integrate versions from other into this versioned file.
476
410
        incorporated into this versioned file.
477
411
 
478
412
        Must raise RevisionNotPresent if any of the specified versions
479
 
        are not present in the other files history unless ignore_missing
480
 
        is supplied when they are silently skipped.
 
413
        are not present in the other file's history unless ignore_missing
 
414
        is supplied in which case they are silently skipped.
481
415
        """
482
416
        self._check_write_ok()
483
417
        return InterVersionedFile.get(other, self).join(
620
554
 
621
555
 
622
556
class WeaveMerge(PlanWeaveMerge):
623
 
    """Weave merge that takes a VersionedFile and two versions as its input"""
 
557
    """Weave merge that takes a VersionedFile and two versions as its input."""
624
558
 
625
559
    def __init__(self, versionedfile, ver_a, ver_b, 
626
560
        a_marker=PlanWeaveMerge.A_MARKER, b_marker=PlanWeaveMerge.B_MARKER):
629
563
 
630
564
 
631
565
class InterVersionedFile(InterObject):
632
 
    """This class represents operations taking place between two versionedfiles..
 
566
    """This class represents operations taking place between two VersionedFiles.
633
567
 
634
568
    Its instances have methods like join, and contain
635
569
    references to the source and target versionedfiles these operations can be 
650
584
        incorporated into this versioned file.
651
585
 
652
586
        Must raise RevisionNotPresent if any of the specified versions
653
 
        are not present in the other files history unless ignore_missing is 
654
 
        supplied when they are silently skipped.
 
587
        are not present in the other file's history unless ignore_missing is 
 
588
        supplied in which case they are silently skipped.
655
589
        """
656
590
        # the default join: 
657
591
        # - if the target is empty, just add all the versions from 
684
618
            # TODO: remove parent texts when they are not relevant any more for 
685
619
            # memory pressure reduction. RBC 20060313
686
620
            # pb.update('Converting versioned data', 0, len(order))
687
 
            # deltas = self.source.get_deltas(order)
 
621
            total = len(order)
688
622
            for index, version in enumerate(order):
689
 
                pb.update('Converting versioned data', index, len(order))
690
 
                parent_text = target.add_lines(version,
 
623
                pb.update('Converting versioned data', index, total)
 
624
                _, _, parent_text = target.add_lines(version,
691
625
                                               self.source.get_parents(version),
692
626
                                               self.source.get_lines(version),
693
627
                                               parent_texts=parent_texts)
694
628
                parent_texts[version] = parent_text
695
 
                #delta_parent, sha1, noeol, delta = deltas[version]
696
 
                #target.add_delta(version,
697
 
                #                 self.source.get_parents(version),
698
 
                #                 delta_parent,
699
 
                #                 sha1,
700
 
                #                 noeol,
701
 
                #                 delta)
702
 
                #target.get_lines(version)
703
629
            
704
630
            # this should hit the native code path for target
705
631
            if target is not self.target:
708
634
                                        msg,
709
635
                                        version_ids,
710
636
                                        ignore_missing)
 
637
            else:
 
638
                return total
711
639
        finally:
712
640
            pb.finished()
713
641
 
725
653
            # None cannot be in source.versions
726
654
            return set(self.source.versions())
727
655
        else:
728
 
            version_ids = [osutils.safe_revision_id(v) for v in version_ids]
729
656
            if ignore_missing:
730
657
                return set(self.source.versions()).intersection(set(version_ids))
731
658
            else: