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