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