/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005, 2006 Canonical Ltd
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
10
#
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
15
#
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
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
"""Versioned text file storage api."""
21
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
22
from bzrlib.lazy_import import lazy_import
23
lazy_import(globals(), """
24
25
from bzrlib import (
26
    errors,
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
27
    osutils,
2520.4.3 by Aaron Bentley
Implement plain strategy for extracting and installing multiparent diffs
28
    multiparent,
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
29
    tsort,
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
30
    revision,
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
31
    ui,
32
    )
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
33
from bzrlib.graph import Graph
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
34
from bzrlib.transport.memory import MemoryTransport
35
""")
36
2520.4.90 by Aaron Bentley
Handle \r terminated lines in Weaves properly
37
from cStringIO import StringIO
38
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.
39
from bzrlib.inter import InterObject
3350.3.7 by Robert Collins
Create a registry of versioned file record adapters.
40
from bzrlib.registry import Registry
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
41
from bzrlib.symbol_versioning import *
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
42
from bzrlib.textmerge import TextMerge
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.
43
44
3350.3.7 by Robert Collins
Create a registry of versioned file record adapters.
45
adapter_registry = Registry()
46
adapter_registry.register_lazy(('knit-delta-gz', 'fulltext'), 'bzrlib.knit',
47
    'DeltaPlainToFullText')
48
adapter_registry.register_lazy(('knit-ft-gz', 'fulltext'), 'bzrlib.knit',
49
    'FTPlainToFullText')
50
adapter_registry.register_lazy(('knit-annotated-delta-gz', 'knit-delta-gz'),
51
    'bzrlib.knit', 'DeltaAnnotatedToUnannotated')
52
adapter_registry.register_lazy(('knit-annotated-delta-gz', 'fulltext'),
53
    'bzrlib.knit', 'DeltaAnnotatedToFullText')
54
adapter_registry.register_lazy(('knit-annotated-ft-gz', 'knit-ft-gz'),
55
    'bzrlib.knit', 'FTAnnotatedToUnannotated')
56
adapter_registry.register_lazy(('knit-annotated-ft-gz', 'fulltext'),
57
    'bzrlib.knit', 'FTAnnotatedToFullText')
58
59
3350.3.3 by Robert Collins
Functional get_record_stream interface tests covering full interface.
60
class ContentFactory(object):
61
    """Abstract interface for insertion and retrieval from a VersionedFile.
62
    
63
    :ivar sha1: None, or the sha1 of the content fulltext.
64
    :ivar storage_kind: The native storage kind of this factory. One of
65
        'mpdiff', 'knit-annotated-ft', 'knit-annotated-delta', 'knit-ft',
66
        'knit-delta', 'fulltext', 'knit-annotated-ft-gz',
67
        'knit-annotated-delta-gz', 'knit-ft-gz', 'knit-delta-gz'.
68
    :ivar key: The key of this content. Each key is a tuple with a single
69
        string in it.
70
    :ivar parents: A tuple of parent keys for self.key. If the object has
71
        no parent information, None (as opposed to () for an empty list of
72
        parents).
73
        """
74
75
    def __init__(self):
76
        """Create a ContentFactory."""
77
        self.sha1 = None
78
        self.storage_kind = None
79
        self.key = None
80
        self.parents = None
81
82
3350.3.12 by Robert Collins
Generate streams with absent records.
83
class AbsentContentFactory(object):
84
    """A placeholder content factory for unavailable texts.
85
    
86
    :ivar sha1: None.
87
    :ivar storage_kind: 'absent'.
88
    :ivar key: The key of this content. Each key is a tuple with a single
89
        string in it.
90
    :ivar parents: None.
91
    """
92
93
    def __init__(self, key):
94
        """Create a ContentFactory."""
95
        self.sha1 = None
96
        self.storage_kind = 'absent'
97
        self.key = key
98
        self.parents = None
99
100
3350.3.14 by Robert Collins
Deprecate VersionedFile.join.
101
def filter_absent(record_stream):
102
    """Adapt a record stream to remove absent records."""
103
    for record in record_stream:
104
        if record.storage_kind != 'absent':
105
            yield record
106
107
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
108
class VersionedFile(object):
109
    """Versioned text file storage.
110
    
111
    A versioned file manages versions of line-based text files,
112
    keeping track of the originating version for each line.
113
114
    To clients the "lines" of the file are represented as a list of
115
    strings. These strings will typically have terminal newline
116
    characters, but this is not required.  In particular files commonly
117
    do not have a newline at the end of the file.
118
119
    Texts are identified by a version-id string.
120
    """
121
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
122
    @staticmethod
2229.2.3 by Aaron Bentley
change reserved_id to is_reserved_id, add check_not_reserved for DRY
123
    def check_not_reserved_id(version_id):
124
        revision.check_not_reserved_id(version_id)
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
125
1563.2.15 by Robert Collins
remove the weavestore assumptions about the number and nature of files it manages.
126
    def copy_to(self, name, transport):
127
        """Copy this versioned file to name on transport."""
128
        raise NotImplementedError(self.copy_to)
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
129
3350.3.3 by Robert Collins
Functional get_record_stream interface tests covering full interface.
130
    def get_record_stream(self, versions, ordering, include_delta_closure):
131
        """Get a stream of records for versions.
132
133
        :param versions: The versions to include. Each version is a tuple
134
            (version,).
135
        :param ordering: Either 'unordered' or 'topological'. A topologically
136
            sorted stream has compression parents strictly before their
137
            children.
138
        :param include_delta_closure: If True then the closure across any
139
            compression parents will be included (in the opaque data).
140
        :return: An iterator of ContentFactory objects, each of which is only
141
            valid until the iterator is advanced.
142
        """
143
        raise NotImplementedError(self.get_record_stream)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
144
3287.6.5 by Robert Collins
Deprecate VersionedFile.has_ghost.
145
    @deprecated_method(one_four)
1594.2.8 by Robert Collins
add ghost aware apis to knits.
146
    def has_ghost(self, version_id):
147
        """Returns whether version is present as a ghost."""
148
        raise NotImplementedError(self.has_ghost)
149
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
150
    def has_version(self, version_id):
151
        """Returns whether version is present."""
152
        raise NotImplementedError(self.has_version)
153
3350.3.8 by Robert Collins
Basic stream insertion, no fast path yet for knit to knit.
154
    def insert_record_stream(self, stream):
155
        """Insert a record stream into this versioned file.
156
157
        :param stream: A stream of records to insert. 
158
        :return: None
159
        :seealso VersionedFile.get_record_stream:
160
        """
161
        raise NotImplementedError
162
2520.4.140 by Aaron Bentley
Use matching blocks from mpdiff for knit delta creation
163
    def add_lines(self, version_id, parents, lines, parent_texts=None,
2805.6.7 by Robert Collins
Review feedback.
164
        left_matching_blocks=None, nostore_sha=None, random_id=False,
165
        check_content=True):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
166
        """Add a single text on top of the versioned file.
167
168
        Must raise RevisionAlreadyPresent if the new version is
169
        already present in file history.
170
171
        Must raise RevisionNotPresent if any of the given parents are
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
172
        not present in file history.
2805.6.3 by Robert Collins
* The ``VersionedFile`` interface no longer protects against misuse when
173
174
        :param lines: A list of lines. Each line must be a bytestring. And all
175
            of them except the last must be terminated with \n and contain no
176
            other \n's. The last line may either contain no \n's or a single
177
            terminated \n. If the lines list does meet this constraint the add
178
            routine may error or may succeed - but you will be unable to read
179
            the data back accurately. (Checking the lines have been split
2805.6.7 by Robert Collins
Review feedback.
180
            correctly is expensive and extremely unlikely to catch bugs so it
181
            is not done at runtime unless check_content is True.)
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
182
        :param parent_texts: An optional dictionary containing the opaque 
2805.6.3 by Robert Collins
* The ``VersionedFile`` interface no longer protects against misuse when
183
            representations of some or all of the parents of version_id to
184
            allow delta optimisations.  VERY IMPORTANT: the texts must be those
185
            returned by add_lines or data corruption can be caused.
2520.4.148 by Aaron Bentley
Updates from review
186
        :param left_matching_blocks: a hint about which areas are common
187
            between the text and its left-hand-parent.  The format is
188
            the SequenceMatcher.get_matching_blocks format.
2794.1.1 by Robert Collins
Allow knits to be instructed not to add a text based on a sha, for commit.
189
        :param nostore_sha: Raise ExistingContent and do not add the lines to
190
            the versioned file if the digest of the lines matches this.
2805.6.4 by Robert Collins
Don't check for existing versions when adding texts with random revision ids.
191
        :param random_id: If True a random id has been selected rather than
192
            an id determined by some deterministic process such as a converter
193
            from a foreign VCS. When True the backend may choose not to check
194
            for uniqueness of the resulting key within the versioned file, so
195
            this should only be done when the result is expected to be unique
196
            anyway.
2805.6.7 by Robert Collins
Review feedback.
197
        :param check_content: If True, the lines supplied are verified to be
198
            bytestrings that are correctly formed lines.
2776.1.1 by Robert Collins
* The ``add_lines`` methods on ``VersionedFile`` implementations has changed
199
        :return: The text sha1, the number of bytes in the text, and an opaque
200
                 representation of the inserted version which can be provided
201
                 back to future add_lines calls in the parent_texts dictionary.
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
202
        """
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
203
        self._check_write_ok()
2520.4.140 by Aaron Bentley
Use matching blocks from mpdiff for knit delta creation
204
        return self._add_lines(version_id, parents, lines, parent_texts,
2805.6.7 by Robert Collins
Review feedback.
205
            left_matching_blocks, nostore_sha, random_id, check_content)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
206
2520.4.140 by Aaron Bentley
Use matching blocks from mpdiff for knit delta creation
207
    def _add_lines(self, version_id, parents, lines, parent_texts,
2805.6.7 by Robert Collins
Review feedback.
208
        left_matching_blocks, nostore_sha, random_id, check_content):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
209
        """Helper to do the class specific add_lines."""
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
210
        raise NotImplementedError(self.add_lines)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
211
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
212
    def add_lines_with_ghosts(self, version_id, parents, lines,
2805.6.7 by Robert Collins
Review feedback.
213
        parent_texts=None, nostore_sha=None, random_id=False,
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
214
        check_content=True, left_matching_blocks=None):
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
215
        """Add lines to the versioned file, allowing ghosts to be present.
216
        
2794.1.1 by Robert Collins
Allow knits to be instructed not to add a text based on a sha, for commit.
217
        This takes the same parameters as add_lines and returns the same.
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
218
        """
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
219
        self._check_write_ok()
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
220
        return self._add_lines_with_ghosts(version_id, parents, lines,
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
221
            parent_texts, nostore_sha, random_id, check_content, left_matching_blocks)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
222
2794.1.1 by Robert Collins
Allow knits to be instructed not to add a text based on a sha, for commit.
223
    def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts,
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
224
        nostore_sha, random_id, check_content, left_matching_blocks):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
225
        """Helper to do class specific add_lines_with_ghosts."""
1594.2.8 by Robert Collins
add ghost aware apis to knits.
226
        raise NotImplementedError(self.add_lines_with_ghosts)
227
1563.2.19 by Robert Collins
stub out a check for knits.
228
    def check(self, progress_bar=None):
229
        """Check the versioned file for integrity."""
230
        raise NotImplementedError(self.check)
231
1666.1.6 by Robert Collins
Make knit the default format.
232
    def _check_lines_not_unicode(self, lines):
233
        """Check that lines being added to a versioned file are not unicode."""
234
        for line in lines:
235
            if line.__class__ is not str:
236
                raise errors.BzrBadParameterUnicode("lines")
237
238
    def _check_lines_are_lines(self, lines):
239
        """Check that the lines really are full lines without inline EOL."""
240
        for line in lines:
241
            if '\n' in line[:-1]:
242
                raise errors.BzrBadParameterContainsNewline("lines")
243
3316.2.11 by Robert Collins
* ``VersionedFile.clear_cache`` and ``enable_cache`` are deprecated.
244
    @deprecated_method(one_four)
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
245
    def enable_cache(self):
246
        """Tell this versioned file that it should cache any data it reads.
247
        
248
        This is advisory, implementations do not have to support caching.
249
        """
250
        pass
251
    
3316.2.11 by Robert Collins
* ``VersionedFile.clear_cache`` and ``enable_cache`` are deprecated.
252
    @deprecated_method(one_four)
1563.2.7 by Robert Collins
add versioned file clear_cache entry.
253
    def clear_cache(self):
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
254
        """Remove any data cached in the versioned file object.
255
256
        This only needs to be supported if caches are supported
257
        """
258
        pass
1563.2.7 by Robert Collins
add versioned file clear_cache entry.
259
3316.2.10 by Robert Collins
* ``VersionedFile.clone_text`` is deprecated. This performance optimisation
260
    @deprecated_method(one_four)
1563.2.5 by Robert Collins
Remove unused transaction references from knit.py and the versionedfile interface.
261
    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.
262
        """Add an identical text to old_version_id as new_version_id.
263
264
        Must raise RevisionNotPresent if the old version or any of the
265
        parents are not present in file history.
266
267
        Must raise RevisionAlreadyPresent if the new version is
268
        already present in file history."""
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
269
        self._check_write_ok()
3316.2.10 by Robert Collins
* ``VersionedFile.clone_text`` is deprecated. This performance optimisation
270
        return self.add_lines(new_version_id, parents,
271
            self.get_lines(old_version_id))
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
272
2535.3.1 by Andrew Bennetts
Add get_format_signature to VersionedFile
273
    def get_format_signature(self):
274
        """Get a text description of the data encoding in this file.
275
        
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
276
        :since: 0.90
2535.3.1 by Andrew Bennetts
Add get_format_signature to VersionedFile
277
        """
278
        raise NotImplementedError(self.get_format_signature)
279
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
280
    def make_mpdiffs(self, version_ids):
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
281
        """Create multiparent diffs for specified versions."""
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
282
        knit_versions = set()
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
283
        knit_versions.update(version_ids)
284
        parent_map = self.get_parent_map(version_ids)
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
285
        for version_id in version_ids:
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
286
            try:
287
                knit_versions.update(parent_map[version_id])
288
            except KeyError:
289
                raise RevisionNotPresent(version_id, self)
290
        # We need to filter out ghosts, because we can't diff against them.
291
        knit_versions = set(self.get_parent_map(knit_versions).keys())
2520.4.90 by Aaron Bentley
Handle \r terminated lines in Weaves properly
292
        lines = dict(zip(knit_versions,
293
            self._get_lf_split_line_list(knit_versions)))
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
294
        diffs = []
295
        for version_id in version_ids:
296
            target = lines[version_id]
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
297
            try:
298
                parents = [lines[p] for p in parent_map[version_id] if p in
299
                    knit_versions]
300
            except KeyError:
301
                raise RevisionNotPresent(version_id, self)
2520.4.48 by Aaron Bentley
Support getting blocks from knit deltas with no final EOL
302
            if len(parents) > 0:
303
                left_parent_blocks = self._extract_blocks(version_id,
304
                                                          parents[0], target)
305
            else:
306
                left_parent_blocks = None
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
307
            diffs.append(multiparent.MultiParent.from_lines(target, parents,
308
                         left_parent_blocks))
309
        return diffs
310
2520.4.48 by Aaron Bentley
Support getting blocks from knit deltas with no final EOL
311
    def _extract_blocks(self, version_id, source, target):
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
312
        return None
2520.4.3 by Aaron Bentley
Implement plain strategy for extracting and installing multiparent diffs
313
2520.4.61 by Aaron Bentley
Do bulk insertion of records
314
    def add_mpdiffs(self, records):
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
315
        """Add mpdiffs to this VersionedFile.
2520.4.126 by Aaron Bentley
Add more docs
316
317
        Records should be iterables of version, parents, expected_sha1,
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
318
        mpdiff. mpdiff should be a MultiParent instance.
2520.4.126 by Aaron Bentley
Add more docs
319
        """
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
320
        # Does this need to call self._check_write_ok()? (IanC 20070919)
2520.4.61 by Aaron Bentley
Do bulk insertion of records
321
        vf_parents = {}
2520.4.141 by Aaron Bentley
More batch operations adding mpdiffs
322
        mpvf = multiparent.MultiMemoryVersionedFile()
323
        versions = []
324
        for version, parent_ids, expected_sha1, mpdiff in records:
325
            versions.append(version)
326
            mpvf.add_diff(mpdiff, version, parent_ids)
327
        needed_parents = set()
2520.4.142 by Aaron Bentley
Clean up installation of inventory records
328
        for version, parent_ids, expected_sha1, mpdiff in records:
2520.4.141 by Aaron Bentley
More batch operations adding mpdiffs
329
            needed_parents.update(p for p in parent_ids
330
                                  if not mpvf.has_version(p))
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
331
        present_parents = set(self.get_parent_map(needed_parents).keys())
332
        for parent_id, lines in zip(present_parents,
333
                                 self._get_lf_split_line_list(present_parents)):
2520.4.141 by Aaron Bentley
More batch operations adding mpdiffs
334
            mpvf.add_version(lines, parent_id, [])
335
        for (version, parent_ids, expected_sha1, mpdiff), lines in\
336
            zip(records, mpvf.get_line_list(versions)):
337
            if len(parent_ids) == 1:
2520.4.140 by Aaron Bentley
Use matching blocks from mpdiff for knit delta creation
338
                left_matching_blocks = list(mpdiff.get_matching_blocks(0,
2520.4.141 by Aaron Bentley
More batch operations adding mpdiffs
339
                    mpvf.get_diff(parent_ids[0]).num_lines()))
2520.4.140 by Aaron Bentley
Use matching blocks from mpdiff for knit delta creation
340
            else:
341
                left_matching_blocks = None
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
342
            try:
343
                _, _, version_text = self.add_lines_with_ghosts(version,
344
                    parent_ids, lines, vf_parents,
345
                    left_matching_blocks=left_matching_blocks)
346
            except NotImplementedError:
347
                # The vf can't handle ghosts, so add lines normally, which will
348
                # (reasonably) fail if there are ghosts in the data.
349
                _, _, version_text = self.add_lines(version,
350
                    parent_ids, lines, vf_parents,
351
                    left_matching_blocks=left_matching_blocks)
2520.4.61 by Aaron Bentley
Do bulk insertion of records
352
            vf_parents[version] = version_text
2520.4.142 by Aaron Bentley
Clean up installation of inventory records
353
        for (version, parent_ids, expected_sha1, mpdiff), sha1 in\
354
             zip(records, self.get_sha1s(versions)):
355
            if expected_sha1 != sha1:
2520.4.71 by Aaron Bentley
Update test to accept VersionedFileInvalidChecksum instead of TestamentMismatch
356
                raise errors.VersionedFileInvalidChecksum(version)
2520.4.3 by Aaron Bentley
Implement plain strategy for extracting and installing multiparent diffs
357
3316.2.9 by Robert Collins
* ``VersionedFile.get_sha1`` is deprecated, please use
358
    @deprecated_method(one_four)
1666.1.6 by Robert Collins
Make knit the default format.
359
    def get_sha1(self, version_id):
360
        """Get the stored sha1 sum for the given revision.
361
        
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
362
        :param version_id: The name of the version to lookup
1666.1.6 by Robert Collins
Make knit the default format.
363
        """
3316.2.9 by Robert Collins
* ``VersionedFile.get_sha1`` is deprecated, please use
364
        return self.get_sha1s([version_id])[0]
1666.1.6 by Robert Collins
Make knit the default format.
365
2520.4.89 by Aaron Bentley
Add get_sha1s to weaves
366
    def get_sha1s(self, version_ids):
367
        """Get the stored sha1 sums for the given revisions.
368
369
        :param version_ids: The names of the versions to lookup
370
        :return: a list of sha1s in order according to the version_ids
371
        """
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
372
        raise NotImplementedError(self.get_sha1s)
2520.4.89 by Aaron Bentley
Add get_sha1s to weaves
373
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
374
    def get_text(self, version_id):
375
        """Return version contents as a text string.
376
377
        Raises RevisionNotPresent if version is not present in
378
        file history.
379
        """
380
        return ''.join(self.get_lines(version_id))
381
    get_string = get_text
382
1756.2.1 by Aaron Bentley
Implement get_texts
383
    def get_texts(self, version_ids):
384
        """Return the texts of listed versions as a list of strings.
385
386
        Raises RevisionNotPresent if version is not present in
387
        file history.
388
        """
389
        return [''.join(self.get_lines(v)) for v in version_ids]
390
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
391
    def get_lines(self, version_id):
392
        """Return version contents as a sequence of lines.
393
394
        Raises RevisionNotPresent if version is not present in
395
        file history.
396
        """
397
        raise NotImplementedError(self.get_lines)
398
2520.4.90 by Aaron Bentley
Handle \r terminated lines in Weaves properly
399
    def _get_lf_split_line_list(self, version_ids):
400
        return [StringIO(t).readlines() for t in self.get_texts(version_ids)]
2520.4.3 by Aaron Bentley
Implement plain strategy for extracting and installing multiparent diffs
401
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
402
    def get_ancestry(self, version_ids, topo_sorted=True):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
403
        """Return a list of all ancestors of given version(s). This
404
        will not include the null revision.
405
2490.2.32 by Aaron Bentley
Merge of not-sorting-ancestry branch
406
        This list will not be topologically sorted if topo_sorted=False is
407
        passed.
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
408
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
409
        Must raise RevisionNotPresent if any of the given versions are
410
        not present in file history."""
411
        if isinstance(version_ids, basestring):
412
            version_ids = [version_ids]
413
        raise NotImplementedError(self.get_ancestry)
414
        
1594.2.8 by Robert Collins
add ghost aware apis to knits.
415
    def get_ancestry_with_ghosts(self, version_ids):
416
        """Return a list of all ancestors of given version(s). This
417
        will not include the null revision.
418
419
        Must raise RevisionNotPresent if any of the given versions are
420
        not present in file history.
421
        
422
        Ghosts that are known about will be included in ancestry list,
423
        but are not explicitly marked.
424
        """
425
        raise NotImplementedError(self.get_ancestry_with_ghosts)
3316.2.7 by Robert Collins
Actually deprecated VersionedFile.get_graph.
426
    
427
    @deprecated_method(one_four)
1684.3.1 by Robert Collins
Fix versioned file joins with empty targets.
428
    def get_graph(self, version_ids=None):
429
        """Return a graph from the versioned file. 
1594.2.8 by Robert Collins
add ghost aware apis to knits.
430
        
431
        Ghosts are not listed or referenced in the graph.
1684.3.1 by Robert Collins
Fix versioned file joins with empty targets.
432
        :param version_ids: Versions to select.
1759.2.1 by Jelmer Vernooij
Fix some types (found using aspell).
433
                            None means retrieve all versions.
1594.2.8 by Robert Collins
add ghost aware apis to knits.
434
        """
2592.3.43 by Robert Collins
A knit iter_parents API.
435
        if version_ids is None:
3316.2.8 by Robert Collins
* ``VersionedFile.iter_parents`` is now deprecated in favour of
436
            result = self.get_parent_map(self.versions())
437
        else:
438
            result = {}
439
            pending = set(version_ids)
440
            while pending:
441
                this_iteration = pending
442
                pending = set()
443
                parents = self.get_parent_map(this_iteration)
444
                for version, parents in parents.iteritems():
445
                    result[version] = parents
446
                    for parent in parents:
447
                        if parent in result:
448
                            continue
449
                        pending.add(parent)
450
        references = set()
451
        for parents in result.itervalues():
452
            references.update(parents)
453
        existing_parents = self.get_parent_map(references)
454
        for key, parents in result.iteritems():
455
            present_parents = [parent for parent in parents if parent in
456
                existing_parents]
457
            result[key] = tuple(present_parents)
1563.2.13 by Robert Collins
InterVersionedFile implemented.
458
        return result
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
459
3287.6.7 by Robert Collins
* ``VersionedFile.get_graph_with_ghosts`` is deprecated, with no
460
    @deprecated_method(one_four)
1594.2.8 by Robert Collins
add ghost aware apis to knits.
461
    def get_graph_with_ghosts(self):
462
        """Return a graph for the entire versioned file.
463
        
464
        Ghosts are referenced in parents list but are not
465
        explicitly listed.
466
        """
467
        raise NotImplementedError(self.get_graph_with_ghosts)
468
3287.5.1 by Robert Collins
Add VersionedFile.get_parent_map.
469
    def get_parent_map(self, version_ids):
470
        """Get a map of the parents of version_ids.
471
472
        :param version_ids: The version ids to look up parents for.
473
        :return: A mapping from version id to parents.
474
        """
475
        raise NotImplementedError(self.get_parent_map)
476
3287.5.4 by Robert Collins
Bump the deprecation to 1.4.
477
    @deprecated_method(one_four)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
478
    def get_parents(self, version_id):
479
        """Return version names for parents of a version.
480
481
        Must raise RevisionNotPresent if version is not present in
482
        file history.
483
        """
3287.5.1 by Robert Collins
Add VersionedFile.get_parent_map.
484
        try:
485
            all = self.get_parent_map([version_id])[version_id]
486
        except KeyError:
487
            raise errors.RevisionNotPresent(version_id, self)
488
        result = []
489
        parent_parents = self.get_parent_map(all)
490
        for version_id in all:
491
            if version_id in parent_parents:
492
                result.append(version_id)
493
        return result
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
494
1594.2.8 by Robert Collins
add ghost aware apis to knits.
495
    def get_parents_with_ghosts(self, version_id):
496
        """Return version names for parents of version_id.
497
498
        Will raise RevisionNotPresent if version_id is not present
499
        in the history.
500
501
        Ghosts that are known about will be included in the parent list,
502
        but are not explicitly marked.
503
        """
3287.5.1 by Robert Collins
Add VersionedFile.get_parent_map.
504
        try:
505
            return list(self.get_parent_map([version_id])[version_id])
506
        except KeyError:
507
            raise errors.RevisionNotPresent(version_id, self)
1594.2.8 by Robert Collins
add ghost aware apis to knits.
508
3316.2.13 by Robert Collins
* ``VersionedFile.annotate_iter`` is deprecated. While in principal this
509
    @deprecated_method(one_four)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
510
    def annotate_iter(self, version_id):
511
        """Yield list of (version-id, line) pairs for the specified
512
        version.
513
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
514
        Must raise RevisionNotPresent if the given version is
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
515
        not present in file history.
516
        """
3316.2.13 by Robert Collins
* ``VersionedFile.annotate_iter`` is deprecated. While in principal this
517
        return iter(self.annotate(version_id))
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
518
519
    def annotate(self, version_id):
3316.2.13 by Robert Collins
* ``VersionedFile.annotate_iter`` is deprecated. While in principal this
520
        """Return a list of (version-id, line) tuples for version_id.
521
522
        :raise RevisionNotPresent: If the given version is
523
        not present in file history.
524
        """
525
        raise NotImplementedError(self.annotate)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
526
3350.3.14 by Robert Collins
Deprecate VersionedFile.join.
527
    @deprecated_method(one_five)
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
528
    def join(self, other, pb=None, msg=None, version_ids=None,
529
             ignore_missing=False):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
530
        """Integrate versions from other into this versioned file.
531
532
        If version_ids is None all versions from other should be
533
        incorporated into this versioned file.
534
535
        Must raise RevisionNotPresent if any of the specified versions
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
536
        are not present in the other file's history unless ignore_missing
537
        is supplied in which case they are silently skipped.
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
538
        """
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
539
        self._check_write_ok()
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
540
        return InterVersionedFile.get(other, self).join(
541
            pb,
542
            msg,
543
            version_ids,
544
            ignore_missing)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
545
2975.3.2 by Robert Collins
Review feedback - document the API change and improve readability in pack's _do_copy_nodes.
546
    def iter_lines_added_or_present_in_versions(self, version_ids=None,
2039.1.1 by Aaron Bentley
Clean up progress properly when interrupted during fetch (#54000)
547
                                                pb=None):
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
548
        """Iterate over the lines in the versioned file from version_ids.
549
2975.3.2 by Robert Collins
Review feedback - document the API change and improve readability in pack's _do_copy_nodes.
550
        This may return lines from other versions. Each item the returned
551
        iterator yields is a tuple of a line and a text version that that line
552
        is present in (not introduced in).
553
554
        Ordering of results is in whatever order is most suitable for the
555
        underlying storage format.
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
556
2039.1.1 by Aaron Bentley
Clean up progress properly when interrupted during fetch (#54000)
557
        If a progress bar is supplied, it may be used to indicate progress.
558
        The caller is responsible for cleaning up progress bars (because this
559
        is an iterator).
560
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
561
        NOTES: Lines are normalised: they will all have \n terminators.
562
               Lines are returned in arbitrary order.
2975.3.2 by Robert Collins
Review feedback - document the API change and improve readability in pack's _do_copy_nodes.
563
564
        :return: An iterator over (line, version_id).
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
565
        """
566
        raise NotImplementedError(self.iter_lines_added_or_present_in_versions)
567
3316.2.8 by Robert Collins
* ``VersionedFile.iter_parents`` is now deprecated in favour of
568
    @deprecated_method(one_four)
2592.3.43 by Robert Collins
A knit iter_parents API.
569
    def iter_parents(self, version_ids):
570
        """Iterate through the parents for many version ids.
571
572
        :param version_ids: An iterable yielding version_ids.
573
        :return: An iterator that yields (version_id, parents). Requested 
574
            version_ids not present in the versioned file are simply skipped.
575
            The order is undefined, allowing for different optimisations in
576
            the underlying implementation.
577
        """
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
578
        return self.get_parent_map(version_ids).iteritems()
2592.3.43 by Robert Collins
A knit iter_parents API.
579
1551.6.15 by Aaron Bentley
Moved plan_merge into Weave
580
    def plan_merge(self, ver_a, ver_b):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
581
        """Return pseudo-annotation indicating how the two versions merge.
582
583
        This is computed between versions a and b and their common
584
        base.
585
586
        Weave lines present in none of them are skipped entirely.
1664.2.2 by Aaron Bentley
Added legend for plan-merge output
587
588
        Legend:
589
        killed-base Dead in base revision
590
        killed-both Killed in each revision
591
        killed-a    Killed in a
592
        killed-b    Killed in b
593
        unchanged   Alive in both a and b (possibly created in both)
594
        new-a       Created in a
595
        new-b       Created in b
1664.2.5 by Aaron Bentley
Update plan-merge legend
596
        ghost-a     Killed in a, unborn in b    
597
        ghost-b     Killed in b, unborn in a
1664.2.2 by Aaron Bentley
Added legend for plan-merge output
598
        irrelevant  Not in either revision
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
599
        """
1551.6.15 by Aaron Bentley
Moved plan_merge into Weave
600
        raise NotImplementedError(VersionedFile.plan_merge)
601
        
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
602
    def weave_merge(self, plan, a_marker=TextMerge.A_MARKER,
1551.6.14 by Aaron Bentley
Tweaks from merge review
603
                    b_marker=TextMerge.B_MARKER):
1551.6.12 by Aaron Bentley
Indicate conflicts from merge_lines, insead of guessing
604
        return PlanWeaveMerge(plan, a_marker, b_marker).merge_lines()[0]
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
605
1664.2.7 by Aaron Bentley
Merge bzr.dev
606
3350.3.4 by Robert Collins
Finish adapters for annotated knits to unannotated knits and full texts.
607
class RecordingVersionedFileDecorator(object):
608
    """A minimal versioned file that records calls made on it.
609
    
610
    Only enough methods have been added to support tests using it to date.
611
612
    :ivar calls: A list of the calls made; can be reset at any time by
613
        assigning [] to it.
614
    """
615
616
    def __init__(self, backing_vf):
617
        """Create a RecordingVersionedFileDecorator decorating backing_vf.
618
        
619
        :param backing_vf: The versioned file to answer all methods.
620
        """
621
        self._backing_vf = backing_vf
622
        self.calls = []
623
624
    def get_lines(self, version_ids):
625
        self.calls.append(("get_lines", version_ids))
626
        return self._backing_vf.get_lines(version_ids)
627
628
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
629
class _PlanMergeVersionedFile(object):
630
    """A VersionedFile for uncommitted and committed texts.
631
632
    It is intended to allow merges to be planned with working tree texts.
633
    It implements only the small part of the VersionedFile interface used by
634
    PlanMerge.  It falls back to multiple versionedfiles for data not stored in
635
    _PlanMergeVersionedFile itself.
636
    """
637
638
    def __init__(self, file_id, fallback_versionedfiles=None):
639
        """Constuctor
640
641
        :param file_id: Used when raising exceptions.
642
        :param fallback_versionedfiles: If supplied, the set of fallbacks to
643
            use.  Otherwise, _PlanMergeVersionedFile.fallback_versionedfiles
644
            can be appended to later.
645
        """
646
        self._file_id = file_id
647
        if fallback_versionedfiles is None:
648
            self.fallback_versionedfiles = []
649
        else:
650
            self.fallback_versionedfiles = fallback_versionedfiles
651
        self._parents = {}
652
        self._lines = {}
653
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
654
    def plan_merge(self, ver_a, ver_b, base=None):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
655
        """See VersionedFile.plan_merge"""
3144.3.7 by Aaron Bentley
Update from review
656
        from bzrlib.merge import _PlanMerge
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
657
        if base is None:
658
            return _PlanMerge(ver_a, ver_b, self).plan_merge()
659
        old_plan = list(_PlanMerge(ver_a, base, self).plan_merge())
660
        new_plan = list(_PlanMerge(ver_a, ver_b, self).plan_merge())
661
        return _PlanMerge._subtract_plans(old_plan, new_plan)
662
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
663
    def plan_lca_merge(self, ver_a, ver_b, base=None):
3144.3.7 by Aaron Bentley
Update from review
664
        from bzrlib.merge import _PlanLCAMerge
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
665
        graph = self._get_graph()
666
        new_plan = _PlanLCAMerge(ver_a, ver_b, self, graph).plan_merge()
667
        if base is None:
668
            return new_plan
669
        old_plan = _PlanLCAMerge(ver_a, base, self, graph).plan_merge()
670
        return _PlanLCAMerge._subtract_plans(list(old_plan), list(new_plan))
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
671
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
672
    def add_lines(self, version_id, parents, lines):
673
        """See VersionedFile.add_lines
674
675
        Lines are added locally, not fallback versionedfiles.  Also, ghosts are
676
        permitted.  Only reserved ids are permitted.
677
        """
678
        if not revision.is_reserved_id(version_id):
679
            raise ValueError('Only reserved ids may be used')
680
        if parents is None:
681
            raise ValueError('Parents may not be None')
682
        if lines is None:
683
            raise ValueError('Lines may not be None')
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
684
        self._parents[version_id] = tuple(parents)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
685
        self._lines[version_id] = lines
686
687
    def get_lines(self, version_id):
688
        """See VersionedFile.get_ancestry"""
689
        lines = self._lines.get(version_id)
690
        if lines is not None:
691
            return lines
692
        for versionedfile in self.fallback_versionedfiles:
693
            try:
694
                return versionedfile.get_lines(version_id)
695
            except errors.RevisionNotPresent:
696
                continue
697
        else:
698
            raise errors.RevisionNotPresent(version_id, self._file_id)
699
3062.1.14 by Aaron Bentley
Use topo_sorted=False with get_ancestry
700
    def get_ancestry(self, version_id, topo_sorted=False):
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
701
        """See VersionedFile.get_ancestry.
702
703
        Note that this implementation assumes that if a VersionedFile can
704
        answer get_ancestry at all, it can give an authoritative answer.  In
705
        fact, ghosts can invalidate this assumption.  But it's good enough
706
        99% of the time, and far cheaper/simpler.
707
708
        Also note that the results of this version are never topologically
709
        sorted, and are a set.
710
        """
3062.1.14 by Aaron Bentley
Use topo_sorted=False with get_ancestry
711
        if topo_sorted:
712
            raise ValueError('This implementation does not provide sorting')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
713
        parents = self._parents.get(version_id)
714
        if parents is None:
715
            for vf in self.fallback_versionedfiles:
716
                try:
3062.1.14 by Aaron Bentley
Use topo_sorted=False with get_ancestry
717
                    return vf.get_ancestry(version_id, topo_sorted=False)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
718
                except errors.RevisionNotPresent:
719
                    continue
720
            else:
721
                raise errors.RevisionNotPresent(version_id, self._file_id)
722
        ancestry = set([version_id])
723
        for parent in parents:
3062.1.14 by Aaron Bentley
Use topo_sorted=False with get_ancestry
724
            ancestry.update(self.get_ancestry(parent, topo_sorted=False))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
725
        return ancestry
726
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
727
    def get_parent_map(self, version_ids):
728
        """See VersionedFile.get_parent_map"""
729
        result = {}
730
        pending = set(version_ids)
731
        for key in version_ids:
732
            try:
733
                result[key] = self._parents[key]
734
            except KeyError:
735
                pass
736
        pending = pending - set(result.keys())
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
737
        for versionedfile in self.fallback_versionedfiles:
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
738
            parents = versionedfile.get_parent_map(pending)
739
            result.update(parents)
740
            pending = pending - set(parents.keys())
741
            if not pending:
742
                return result
743
        return result
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
744
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
745
    def _get_graph(self):
3144.3.7 by Aaron Bentley
Update from review
746
        from bzrlib.graph import (
747
            DictParentsProvider,
748
            Graph,
749
            _StackedParentsProvider,
750
            )
751
        from bzrlib.repofmt.knitrepo import _KnitParentsProvider
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
752
        parent_providers = [DictParentsProvider(self._parents)]
753
        for vf in self.fallback_versionedfiles:
754
            parent_providers.append(_KnitParentsProvider(vf))
755
        return Graph(_StackedParentsProvider(parent_providers))
756
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
757
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
758
class PlanWeaveMerge(TextMerge):
1551.6.13 by Aaron Bentley
Cleanup
759
    """Weave merge that takes a plan as its input.
760
    
1551.6.14 by Aaron Bentley
Tweaks from merge review
761
    This exists so that VersionedFile.plan_merge is implementable.
762
    Most callers will want to use WeaveMerge instead.
1551.6.13 by Aaron Bentley
Cleanup
763
    """
764
1551.6.14 by Aaron Bentley
Tweaks from merge review
765
    def __init__(self, plan, a_marker=TextMerge.A_MARKER,
766
                 b_marker=TextMerge.B_MARKER):
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
767
        TextMerge.__init__(self, a_marker, b_marker)
768
        self.plan = plan
769
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
770
    def _merge_struct(self):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
771
        lines_a = []
772
        lines_b = []
773
        ch_a = ch_b = False
1664.2.8 by Aaron Bentley
Fix WeaveMerge when plan doesn't end with unchanged lines
774
775
        def outstanding_struct():
776
            if not lines_a and not lines_b:
777
                return
778
            elif ch_a and not ch_b:
779
                # one-sided change:
780
                yield(lines_a,)
781
            elif ch_b and not ch_a:
782
                yield (lines_b,)
783
            elif lines_a == lines_b:
784
                yield(lines_a,)
785
            else:
786
                yield (lines_a, lines_b)
1551.6.13 by Aaron Bentley
Cleanup
787
       
1616.1.18 by Martin Pool
(weave-merge) don't treat killed-both lines as points of agreement;
788
        # We previously considered either 'unchanged' or 'killed-both' lines
789
        # to be possible places to resynchronize.  However, assuming agreement
1759.2.1 by Jelmer Vernooij
Fix some types (found using aspell).
790
        # on killed-both lines may be too aggressive. -- mbp 20060324
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
791
        for state, line in self.plan:
1616.1.18 by Martin Pool
(weave-merge) don't treat killed-both lines as points of agreement;
792
            if state == 'unchanged':
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
793
                # resync and flush queued conflicts changes if any
1664.2.8 by Aaron Bentley
Fix WeaveMerge when plan doesn't end with unchanged lines
794
                for struct in outstanding_struct():
795
                    yield struct
1551.6.11 by Aaron Bentley
Switched TextMerge_lines to work on a list
796
                lines_a = []
797
                lines_b = []
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
798
                ch_a = ch_b = False
799
                
800
            if state == 'unchanged':
801
                if line:
1551.6.5 by Aaron Bentley
Got weave merge producing structural output
802
                    yield ([line],)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
803
            elif state == 'killed-a':
804
                ch_a = True
805
                lines_b.append(line)
806
            elif state == 'killed-b':
807
                ch_b = True
808
                lines_a.append(line)
809
            elif state == 'new-a':
810
                ch_a = True
811
                lines_a.append(line)
812
            elif state == 'new-b':
813
                ch_b = True
814
                lines_b.append(line)
3144.3.2 by Aaron Bentley
Get conflict handling working
815
            elif state == 'conflicted-a':
816
                ch_b = ch_a = True
817
                lines_a.append(line)
818
            elif state == 'conflicted-b':
819
                ch_b = ch_a = True
820
                lines_b.append(line)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
821
            else:
1551.6.6 by Aaron Bentley
Cleanup
822
                assert state in ('irrelevant', 'ghost-a', 'ghost-b', 
823
                                 'killed-base', 'killed-both'), state
1664.2.8 by Aaron Bentley
Fix WeaveMerge when plan doesn't end with unchanged lines
824
        for struct in outstanding_struct():
825
            yield struct
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.
826
1664.2.14 by Aaron Bentley
spacing fix
827
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
828
class WeaveMerge(PlanWeaveMerge):
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
829
    """Weave merge that takes a VersionedFile and two versions as its input."""
1551.6.13 by Aaron Bentley
Cleanup
830
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
831
    def __init__(self, versionedfile, ver_a, ver_b, 
1551.6.14 by Aaron Bentley
Tweaks from merge review
832
        a_marker=PlanWeaveMerge.A_MARKER, b_marker=PlanWeaveMerge.B_MARKER):
1551.6.15 by Aaron Bentley
Moved plan_merge into Weave
833
        plan = versionedfile.plan_merge(ver_a, ver_b)
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
834
        PlanWeaveMerge.__init__(self, plan, a_marker, b_marker)
835
836
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.
837
class InterVersionedFile(InterObject):
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
838
    """This class represents operations taking place between two VersionedFiles.
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.
839
840
    Its instances have methods like join, and contain
841
    references to the source and target versionedfiles these operations can be 
842
    carried out on.
843
844
    Often we will provide convenience methods on 'versionedfile' which carry out
845
    operations with another versionedfile - they will always forward to
846
    InterVersionedFile.get(other).method_name(parameters).
847
    """
848
1910.2.15 by Aaron Bentley
Back out inter.get changes, make optimizers an ordered list
849
    _optimisers = []
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.
850
    """The available optimised InterVersionedFile types."""
851
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
852
    def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
1563.2.13 by Robert Collins
InterVersionedFile implemented.
853
        """Integrate versions from self.source into self.target.
854
855
        If version_ids is None all versions from source should be
856
        incorporated into this versioned file.
857
858
        Must raise RevisionNotPresent if any of the specified versions
2831.7.1 by Ian Clatworthy
versionedfile.py code cleanups
859
        are not present in the other file's history unless ignore_missing is 
860
        supplied in which case they are silently skipped.
1563.2.13 by Robert Collins
InterVersionedFile implemented.
861
        """
3316.2.1 by Robert Collins
* ``VersionedFile.create_empty`` is removed. This method presupposed a
862
        target = self.target
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
863
        version_ids = self._get_source_version_ids(version_ids, ignore_missing)
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
864
        graph = Graph(self.source)
865
        search = graph._make_breadth_first_searcher(version_ids)
866
        transitive_ids = set()
867
        map(transitive_ids.update, list(search))
868
        parent_map = self.source.get_parent_map(transitive_ids)
869
        order = tsort.topo_sort(parent_map.items())
1563.2.37 by Robert Collins
Merge in nested progress bars
870
        pb = ui.ui_factory.nested_progress_bar()
1596.2.38 by Robert Collins
rollback from using deltas to using fulltexts - deltas need more work to be ready.
871
        parent_texts = {}
1563.2.37 by Robert Collins
Merge in nested progress bars
872
        try:
1596.2.28 by Robert Collins
more knit profile based tuning.
873
            # TODO for incremental cross-format work:
1596.2.27 by Robert Collins
Note potential improvements in knit adds.
874
            # make a versioned file with the following content:
875
            # all revisions we have been asked to join
876
            # all their ancestors that are *not* in target already.
877
            # the immediate parents of the above two sets, with 
878
            # empty parent lists - these versions are in target already
879
            # and the incorrect version data will be ignored.
880
            # TODO: for all ancestors that are present in target already,
881
            # check them for consistent data, this requires moving sha1 from
1596.2.38 by Robert Collins
rollback from using deltas to using fulltexts - deltas need more work to be ready.
882
            # 
883
            # TODO: remove parent texts when they are not relevant any more for 
884
            # memory pressure reduction. RBC 20060313
885
            # pb.update('Converting versioned data', 0, len(order))
2851.4.3 by Ian Clatworthy
fix up plain-to-annotated knit conversion
886
            total = len(order)
1563.2.37 by Robert Collins
Merge in nested progress bars
887
            for index, version in enumerate(order):
2851.4.3 by Ian Clatworthy
fix up plain-to-annotated knit conversion
888
                pb.update('Converting versioned data', index, total)
3316.2.1 by Robert Collins
* ``VersionedFile.create_empty`` is removed. This method presupposed a
889
                if version in target:
890
                    continue
2776.1.3 by Robert Collins
Missed bundles in the return value conversion of vf.add_lines.
891
                _, _, parent_text = target.add_lines(version,
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
892
                                               parent_map[version],
1596.2.38 by Robert Collins
rollback from using deltas to using fulltexts - deltas need more work to be ready.
893
                                               self.source.get_lines(version),
894
                                               parent_texts=parent_texts)
895
                parent_texts[version] = parent_text
3316.2.1 by Robert Collins
* ``VersionedFile.create_empty`` is removed. This method presupposed a
896
            return total
1563.2.37 by Robert Collins
Merge in nested progress bars
897
        finally:
898
            pb.finished()
1563.2.13 by Robert Collins
InterVersionedFile implemented.
899
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
900
    def _get_source_version_ids(self, version_ids, ignore_missing):
901
        """Determine the version ids to be used from self.source.
902
903
        :param version_ids: The caller-supplied version ids to check. (None 
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
904
                            for all). If None is in version_ids, it is stripped.
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
905
        :param ignore_missing: if True, remove missing ids from the version 
906
                               list. If False, raise RevisionNotPresent on
907
                               a missing version id.
908
        :return: A set of version ids.
909
        """
910
        if version_ids is None:
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
911
            # None cannot be in source.versions
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
912
            return set(self.source.versions())
913
        else:
914
            if ignore_missing:
915
                return set(self.source.versions()).intersection(set(version_ids))
916
            else:
917
                new_version_ids = set()
918
                for version in version_ids:
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
919
                    if version is None:
920
                        continue
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
921
                    if not self.source.has_version(version):
922
                        raise errors.RevisionNotPresent(version, str(self.source))
923
                    else:
924
                        new_version_ids.add(version)
925
                return new_version_ids