/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,
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
28
    tsort,
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
29
    revision,
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
30
    ui,
31
    )
32
from bzrlib.transport.memory import MemoryTransport
33
""")
34
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.
35
from bzrlib.inter import InterObject
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
36
from bzrlib.textmerge import TextMerge
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
37
from bzrlib.symbol_versioning import (deprecated_function,
38
        deprecated_method,
39
        zero_eight,
40
        )
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.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.
69
    @deprecated_method(zero_eight)
70
    def names(self):
71
        """Return a list of all the versions in this versioned file.
72
73
        Please use versionedfile.versions() now.
74
        """
75
        return self.versions()
76
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
77
    def versions(self):
78
        """Return a unsorted list of versions."""
79
        raise NotImplementedError(self.versions)
80
1594.2.8 by Robert Collins
add ghost aware apis to knits.
81
    def has_ghost(self, version_id):
82
        """Returns whether version is present as a ghost."""
83
        raise NotImplementedError(self.has_ghost)
84
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
85
    def has_version(self, version_id):
86
        """Returns whether version is present."""
87
        raise NotImplementedError(self.has_version)
88
1596.2.37 by Robert Collins
Switch to delta based content copying in the generic versioned file copier.
89
    def add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
90
        """Add a text to the versioned file via a pregenerated delta.
91
92
        :param version_id: The version id being added.
93
        :param parents: The parents of the version_id.
94
        :param delta_parent: The parent this delta was created against.
95
        :param sha1: The sha1 of the full text.
96
        :param delta: The delta instructions. See get_delta for details.
97
        """
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
98
        version_id = osutils.safe_revision_id(version_id)
99
        parents = [osutils.safe_revision_id(v) for v in parents]
1596.2.37 by Robert Collins
Switch to delta based content copying in the generic versioned file copier.
100
        self._check_write_ok()
101
        if self.has_version(version_id):
102
            raise errors.RevisionAlreadyPresent(version_id, self)
103
        return self._add_delta(version_id, parents, delta_parent, sha1, noeol, delta)
104
105
    def _add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
106
        """Class specific routine to add a delta.
107
108
        This generic version simply applies the delta to the delta_parent and
109
        then inserts it.
110
        """
111
        # strip annotation from delta
112
        new_delta = []
113
        for start, stop, delta_len, delta_lines in delta:
114
            new_delta.append((start, stop, delta_len, [text for origin, text in delta_lines]))
115
        if delta_parent is not None:
116
            parent_full = self.get_lines(delta_parent)
117
        else:
118
            parent_full = []
119
        new_full = self._apply_delta(parent_full, new_delta)
120
        # its impossible to have noeol on an empty file
121
        if noeol and new_full[-1][-1] == '\n':
122
            new_full[-1] = new_full[-1][:-1]
123
        self.add_lines(version_id, parents, new_full)
124
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
125
    def add_lines(self, version_id, parents, lines, parent_texts=None):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
126
        """Add a single text on top of the versioned file.
127
128
        Must raise RevisionAlreadyPresent if the new version is
129
        already present in file history.
130
131
        Must raise RevisionNotPresent if any of the given parents are
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
132
        not present in file history.
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
133
        :param parent_texts: An optional dictionary containing the opaque 
1616.1.1 by Martin Pool
[merge] robertc
134
             representations of some or all of the parents of 
135
             version_id to allow delta optimisations. 
136
             VERY IMPORTANT: the texts must be those returned
137
             by add_lines or data corruption can be caused.
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
138
        :return: An opaque representation of the inserted version which can be
139
                 provided back to future add_lines calls in the parent_texts
140
                 dictionary.
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
141
        """
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
142
        version_id = osutils.safe_revision_id(version_id)
143
        parents = [osutils.safe_revision_id(v) for v in parents]
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
144
        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.
145
        return self._add_lines(version_id, parents, lines, parent_texts)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
146
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
147
    def _add_lines(self, version_id, parents, lines, parent_texts):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
148
        """Helper to do the class specific add_lines."""
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
149
        raise NotImplementedError(self.add_lines)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
150
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
151
    def add_lines_with_ghosts(self, version_id, parents, lines,
152
                              parent_texts=None):
153
        """Add lines to the versioned file, allowing ghosts to be present.
154
        
155
        This takes the same parameters as add_lines.
156
        """
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
157
        version_id = osutils.safe_revision_id(version_id)
158
        parents = [osutils.safe_revision_id(v) for v in parents]
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
159
        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.
160
        return self._add_lines_with_ghosts(version_id, parents, lines,
161
                                           parent_texts)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
162
1596.2.32 by Robert Collins
Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.
163
    def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
164
        """Helper to do class specific add_lines_with_ghosts."""
1594.2.8 by Robert Collins
add ghost aware apis to knits.
165
        raise NotImplementedError(self.add_lines_with_ghosts)
166
1563.2.19 by Robert Collins
stub out a check for knits.
167
    def check(self, progress_bar=None):
168
        """Check the versioned file for integrity."""
169
        raise NotImplementedError(self.check)
170
1666.1.6 by Robert Collins
Make knit the default format.
171
    def _check_lines_not_unicode(self, lines):
172
        """Check that lines being added to a versioned file are not unicode."""
173
        for line in lines:
174
            if line.__class__ is not str:
175
                raise errors.BzrBadParameterUnicode("lines")
176
177
    def _check_lines_are_lines(self, lines):
178
        """Check that the lines really are full lines without inline EOL."""
179
        for line in lines:
180
            if '\n' in line[:-1]:
181
                raise errors.BzrBadParameterContainsNewline("lines")
182
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
183
    def _check_write_ok(self):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
184
        """Is the versioned file marked as 'finished' ? Raise if it is."""
185
        if self.finished:
186
            raise errors.OutSideTransaction()
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
187
        if self._access_mode != 'w':
188
            raise errors.ReadOnlyObjectDirtiedError(self)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
189
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
190
    def enable_cache(self):
191
        """Tell this versioned file that it should cache any data it reads.
192
        
193
        This is advisory, implementations do not have to support caching.
194
        """
195
        pass
196
    
1563.2.7 by Robert Collins
add versioned file clear_cache entry.
197
    def clear_cache(self):
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
198
        """Remove any data cached in the versioned file object.
199
200
        This only needs to be supported if caches are supported
201
        """
202
        pass
1563.2.7 by Robert Collins
add versioned file clear_cache entry.
203
1563.2.5 by Robert Collins
Remove unused transaction references from knit.py and the versionedfile interface.
204
    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.
205
        """Add an identical text to old_version_id as new_version_id.
206
207
        Must raise RevisionNotPresent if the old version or any of the
208
        parents are not present in file history.
209
210
        Must raise RevisionAlreadyPresent if the new version is
211
        already present in file history."""
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
212
        new_version_id = osutils.safe_revision_id(new_version_id)
213
        old_version_id = osutils.safe_revision_id(old_version_id)
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
214
        self._check_write_ok()
215
        return self._clone_text(new_version_id, old_version_id, parents)
216
217
    def _clone_text(self, new_version_id, old_version_id, parents):
218
        """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.
219
        raise NotImplementedError(self.clone_text)
220
1563.2.13 by Robert Collins
InterVersionedFile implemented.
221
    def create_empty(self, name, transport, mode=None):
222
        """Create a new versioned file of this exact type.
223
224
        :param name: the file name
225
        :param transport: the transport
226
        :param mode: optional file mode.
227
        """
228
        raise NotImplementedError(self.create_empty)
229
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
230
    def fix_parents(self, version_id, new_parents):
1594.2.7 by Robert Collins
Add versionedfile.fix_parents api for correcting data post hoc.
231
        """Fix the parents list for version.
232
        
233
        This is done by appending a new version to the index
234
        with identical data except for the parents list.
235
        the parents list must be a superset of the current
236
        list.
237
        """
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
238
        version_id = osutils.safe_revision_id(version_id)
239
        new_parents = [osutils.safe_revision_id(p) for p in new_parents]
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
240
        self._check_write_ok()
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
241
        return self._fix_parents(version_id, new_parents)
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
242
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
243
    def _fix_parents(self, version_id, new_parents):
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
244
        """Helper for fix_parents."""
1594.2.7 by Robert Collins
Add versionedfile.fix_parents api for correcting data post hoc.
245
        raise NotImplementedError(self.fix_parents)
246
1596.2.36 by Robert Collins
add a get_delta api to versioned_file.
247
    def get_delta(self, version):
248
        """Get a delta for constructing version from some other version.
249
        
1596.2.38 by Robert Collins
rollback from using deltas to using fulltexts - deltas need more work to be ready.
250
        :return: (delta_parent, sha1, noeol, delta)
1596.2.36 by Robert Collins
add a get_delta api to versioned_file.
251
        Where delta_parent is a version id or None to indicate no parent.
252
        """
253
        raise NotImplementedError(self.get_delta)
254
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
255
    def get_deltas(self, version_ids):
1596.2.38 by Robert Collins
rollback from using deltas to using fulltexts - deltas need more work to be ready.
256
        """Get multiple deltas at once for constructing versions.
257
        
258
        :return: dict(version_id:(delta_parent, sha1, noeol, delta))
259
        Where delta_parent is a version id or None to indicate no parent, and
260
        version_id is the version_id created by that delta.
261
        """
262
        result = {}
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
263
        for version_id in version_ids:
264
            result[version_id] = self.get_delta(version_id)
1596.2.38 by Robert Collins
rollback from using deltas to using fulltexts - deltas need more work to be ready.
265
        return result
266
1666.1.6 by Robert Collins
Make knit the default format.
267
    def get_sha1(self, version_id):
268
        """Get the stored sha1 sum for the given revision.
269
        
270
        :param name: The name of the version to lookup
271
        """
272
        raise NotImplementedError(self.get_sha1)
273
1563.2.15 by Robert Collins
remove the weavestore assumptions about the number and nature of files it manages.
274
    def get_suffixes(self):
275
        """Return the file suffixes associated with this versioned file."""
276
        raise NotImplementedError(self.get_suffixes)
277
    
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
278
    def get_text(self, version_id):
279
        """Return version contents as a text string.
280
281
        Raises RevisionNotPresent if version is not present in
282
        file history.
283
        """
284
        return ''.join(self.get_lines(version_id))
285
    get_string = get_text
286
1756.2.1 by Aaron Bentley
Implement get_texts
287
    def get_texts(self, version_ids):
288
        """Return the texts of listed versions as a list of strings.
289
290
        Raises RevisionNotPresent if version is not present in
291
        file history.
292
        """
293
        return [''.join(self.get_lines(v)) for v in version_ids]
294
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
295
    def get_lines(self, version_id):
296
        """Return version contents as a sequence of lines.
297
298
        Raises RevisionNotPresent if version is not present in
299
        file history.
300
        """
301
        raise NotImplementedError(self.get_lines)
302
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
303
    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.
304
        """Return a list of all ancestors of given version(s). This
305
        will not include the null revision.
306
2490.2.32 by Aaron Bentley
Merge of not-sorting-ancestry branch
307
        This list will not be topologically sorted if topo_sorted=False is
308
        passed.
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
309
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
310
        Must raise RevisionNotPresent if any of the given versions are
311
        not present in file history."""
312
        if isinstance(version_ids, basestring):
313
            version_ids = [version_ids]
314
        raise NotImplementedError(self.get_ancestry)
315
        
1594.2.8 by Robert Collins
add ghost aware apis to knits.
316
    def get_ancestry_with_ghosts(self, version_ids):
317
        """Return a list of all ancestors of given version(s). This
318
        will not include the null revision.
319
320
        Must raise RevisionNotPresent if any of the given versions are
321
        not present in file history.
322
        
323
        Ghosts that are known about will be included in ancestry list,
324
        but are not explicitly marked.
325
        """
326
        raise NotImplementedError(self.get_ancestry_with_ghosts)
327
        
1684.3.1 by Robert Collins
Fix versioned file joins with empty targets.
328
    def get_graph(self, version_ids=None):
329
        """Return a graph from the versioned file. 
1594.2.8 by Robert Collins
add ghost aware apis to knits.
330
        
331
        Ghosts are not listed or referenced in the graph.
1684.3.1 by Robert Collins
Fix versioned file joins with empty targets.
332
        :param version_ids: Versions to select.
1759.2.1 by Jelmer Vernooij
Fix some types (found using aspell).
333
                            None means retrieve all versions.
1594.2.8 by Robert Collins
add ghost aware apis to knits.
334
        """
2592.3.43 by Robert Collins
A knit iter_parents API.
335
        if version_ids is None:
336
            return dict(self.iter_parents(self.versions()))
1563.2.13 by Robert Collins
InterVersionedFile implemented.
337
        result = {}
2592.3.43 by Robert Collins
A knit iter_parents API.
338
        pending = set(osutils.safe_revision_id(v) for v in version_ids)
339
        while pending:
340
            this_iteration = pending
341
            pending = set()
342
            for version, parents in self.iter_parents(this_iteration):
1684.3.1 by Robert Collins
Fix versioned file joins with empty targets.
343
                result[version] = parents
2592.3.43 by Robert Collins
A knit iter_parents API.
344
                pending.update(parents)
345
            pending.difference_update(result)
1563.2.13 by Robert Collins
InterVersionedFile implemented.
346
        return result
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
347
1594.2.8 by Robert Collins
add ghost aware apis to knits.
348
    def get_graph_with_ghosts(self):
349
        """Return a graph for the entire versioned file.
350
        
351
        Ghosts are referenced in parents list but are not
352
        explicitly listed.
353
        """
354
        raise NotImplementedError(self.get_graph_with_ghosts)
355
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.
356
    @deprecated_method(zero_eight)
357
    def parent_names(self, version):
358
        """Return version names for parents of a version.
359
        
360
        See get_parents for the current api.
361
        """
362
        return self.get_parents(version)
363
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
364
    def get_parents(self, version_id):
365
        """Return version names for parents of a version.
366
367
        Must raise RevisionNotPresent if version is not present in
368
        file history.
369
        """
370
        raise NotImplementedError(self.get_parents)
371
1594.2.8 by Robert Collins
add ghost aware apis to knits.
372
    def get_parents_with_ghosts(self, version_id):
373
        """Return version names for parents of version_id.
374
375
        Will raise RevisionNotPresent if version_id is not present
376
        in the history.
377
378
        Ghosts that are known about will be included in the parent list,
379
        but are not explicitly marked.
380
        """
381
        raise NotImplementedError(self.get_parents_with_ghosts)
382
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
383
    def annotate_iter(self, version_id):
384
        """Yield list of (version-id, line) pairs for the specified
385
        version.
386
387
        Must raise RevisionNotPresent if any of the given versions are
388
        not present in file history.
389
        """
390
        raise NotImplementedError(self.annotate_iter)
391
392
    def annotate(self, version_id):
393
        return list(self.annotate_iter(version_id))
394
1596.2.37 by Robert Collins
Switch to delta based content copying in the generic versioned file copier.
395
    def _apply_delta(self, lines, delta):
396
        """Apply delta to lines."""
397
        lines = list(lines)
398
        offset = 0
399
        for start, end, count, delta_lines in delta:
400
            lines[offset+start:offset+end] = delta_lines
401
            offset = offset + (start - end) + count
402
        return lines
403
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
404
    def join(self, other, pb=None, msg=None, version_ids=None,
405
             ignore_missing=False):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
406
        """Integrate versions from other into this versioned file.
407
408
        If version_ids is None all versions from other should be
409
        incorporated into this versioned file.
410
411
        Must raise RevisionNotPresent if any of the specified versions
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
412
        are not present in the other files history unless ignore_missing
413
        is supplied when they are silently skipped.
414
        """
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
415
        self._check_write_ok()
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
416
        return InterVersionedFile.get(other, self).join(
417
            pb,
418
            msg,
419
            version_ids,
420
            ignore_missing)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
421
2039.1.1 by Aaron Bentley
Clean up progress properly when interrupted during fetch (#54000)
422
    def iter_lines_added_or_present_in_versions(self, version_ids=None, 
423
                                                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.
424
        """Iterate over the lines in the versioned file from version_ids.
425
426
        This may return lines from other versions, and does not return the
427
        specific version marker at this point. The api may be changed
428
        during development to include the version that the versioned file
429
        thinks is relevant, but given that such hints are just guesses,
1759.2.2 by Jelmer Vernooij
Revert some of my spelling fixes and fix some typos after review by Aaron.
430
        its better not to have it if we don't need it.
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
431
2039.1.1 by Aaron Bentley
Clean up progress properly when interrupted during fetch (#54000)
432
        If a progress bar is supplied, it may be used to indicate progress.
433
        The caller is responsible for cleaning up progress bars (because this
434
        is an iterator).
435
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
436
        NOTES: Lines are normalised: they will all have \n terminators.
437
               Lines are returned in arbitrary order.
438
        """
439
        raise NotImplementedError(self.iter_lines_added_or_present_in_versions)
440
2592.3.43 by Robert Collins
A knit iter_parents API.
441
    def iter_parents(self, version_ids):
442
        """Iterate through the parents for many version ids.
443
444
        :param version_ids: An iterable yielding version_ids.
445
        :return: An iterator that yields (version_id, parents). Requested 
446
            version_ids not present in the versioned file are simply skipped.
447
            The order is undefined, allowing for different optimisations in
448
            the underlying implementation.
449
        """
450
        for version_id in version_ids:
451
            try:
452
                yield version_id, tuple(self.get_parents(version_id))
453
            except errors.RevisionNotPresent:
454
                pass
455
1594.2.21 by Robert Collins
Teach versioned files to prevent mutation after finishing.
456
    def transaction_finished(self):
457
        """The transaction that this file was opened in has finished.
458
459
        This records self.finished = True and should cause all mutating
460
        operations to error.
461
        """
462
        self.finished = True
463
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
464
    @deprecated_method(zero_eight)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
465
    def walk(self, version_ids=None):
466
        """Walk the versioned file as a weave-like structure, for
467
        versions relative to version_ids.  Yields sequence of (lineno,
468
        insert, deletes, text) for each relevant line.
469
470
        Must raise RevisionNotPresent if any of the specified versions
471
        are not present in the file history.
472
473
        :param version_ids: the version_ids to walk with respect to. If not
474
                            supplied the entire weave-like structure is walked.
1594.2.6 by Robert Collins
Introduce a api specifically for looking at lines in some versions of the inventory, for fileid_involved.
475
476
        walk is deprecated in favour of iter_lines_added_or_present_in_versions
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
477
        """
478
        raise NotImplementedError(self.walk)
479
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.
480
    @deprecated_method(zero_eight)
481
    def iter_names(self):
482
        """Walk the names list."""
483
        return iter(self.versions())
484
1551.6.15 by Aaron Bentley
Moved plan_merge into Weave
485
    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.
486
        """Return pseudo-annotation indicating how the two versions merge.
487
488
        This is computed between versions a and b and their common
489
        base.
490
491
        Weave lines present in none of them are skipped entirely.
1664.2.2 by Aaron Bentley
Added legend for plan-merge output
492
493
        Legend:
494
        killed-base Dead in base revision
495
        killed-both Killed in each revision
496
        killed-a    Killed in a
497
        killed-b    Killed in b
498
        unchanged   Alive in both a and b (possibly created in both)
499
        new-a       Created in a
500
        new-b       Created in b
1664.2.5 by Aaron Bentley
Update plan-merge legend
501
        ghost-a     Killed in a, unborn in b    
502
        ghost-b     Killed in b, unborn in a
1664.2.2 by Aaron Bentley
Added legend for plan-merge output
503
        irrelevant  Not in either revision
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
504
        """
1551.6.15 by Aaron Bentley
Moved plan_merge into Weave
505
        raise NotImplementedError(VersionedFile.plan_merge)
506
        
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
507
    def weave_merge(self, plan, a_marker=TextMerge.A_MARKER,
1551.6.14 by Aaron Bentley
Tweaks from merge review
508
                    b_marker=TextMerge.B_MARKER):
1551.6.12 by Aaron Bentley
Indicate conflicts from merge_lines, insead of guessing
509
        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
510
1664.2.7 by Aaron Bentley
Merge bzr.dev
511
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
512
class PlanWeaveMerge(TextMerge):
1551.6.13 by Aaron Bentley
Cleanup
513
    """Weave merge that takes a plan as its input.
514
    
1551.6.14 by Aaron Bentley
Tweaks from merge review
515
    This exists so that VersionedFile.plan_merge is implementable.
516
    Most callers will want to use WeaveMerge instead.
1551.6.13 by Aaron Bentley
Cleanup
517
    """
518
1551.6.14 by Aaron Bentley
Tweaks from merge review
519
    def __init__(self, plan, a_marker=TextMerge.A_MARKER,
520
                 b_marker=TextMerge.B_MARKER):
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
521
        TextMerge.__init__(self, a_marker, b_marker)
522
        self.plan = plan
523
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
524
    def _merge_struct(self):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
525
        lines_a = []
526
        lines_b = []
527
        ch_a = ch_b = False
1664.2.8 by Aaron Bentley
Fix WeaveMerge when plan doesn't end with unchanged lines
528
529
        def outstanding_struct():
530
            if not lines_a and not lines_b:
531
                return
532
            elif ch_a and not ch_b:
533
                # one-sided change:
534
                yield(lines_a,)
535
            elif ch_b and not ch_a:
536
                yield (lines_b,)
537
            elif lines_a == lines_b:
538
                yield(lines_a,)
539
            else:
540
                yield (lines_a, lines_b)
1551.6.13 by Aaron Bentley
Cleanup
541
       
1616.1.18 by Martin Pool
(weave-merge) don't treat killed-both lines as points of agreement;
542
        # We previously considered either 'unchanged' or 'killed-both' lines
543
        # to be possible places to resynchronize.  However, assuming agreement
1759.2.1 by Jelmer Vernooij
Fix some types (found using aspell).
544
        # on killed-both lines may be too aggressive. -- mbp 20060324
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
545
        for state, line in self.plan:
1616.1.18 by Martin Pool
(weave-merge) don't treat killed-both lines as points of agreement;
546
            if state == 'unchanged':
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
547
                # resync and flush queued conflicts changes if any
1664.2.8 by Aaron Bentley
Fix WeaveMerge when plan doesn't end with unchanged lines
548
                for struct in outstanding_struct():
549
                    yield struct
1551.6.11 by Aaron Bentley
Switched TextMerge_lines to work on a list
550
                lines_a = []
551
                lines_b = []
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
552
                ch_a = ch_b = False
553
                
554
            if state == 'unchanged':
555
                if line:
1551.6.5 by Aaron Bentley
Got weave merge producing structural output
556
                    yield ([line],)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
557
            elif state == 'killed-a':
558
                ch_a = True
559
                lines_b.append(line)
560
            elif state == 'killed-b':
561
                ch_b = True
562
                lines_a.append(line)
563
            elif state == 'new-a':
564
                ch_a = True
565
                lines_a.append(line)
566
            elif state == 'new-b':
567
                ch_b = True
568
                lines_b.append(line)
569
            else:
1551.6.6 by Aaron Bentley
Cleanup
570
                assert state in ('irrelevant', 'ghost-a', 'ghost-b', 
571
                                 'killed-base', 'killed-both'), state
1664.2.8 by Aaron Bentley
Fix WeaveMerge when plan doesn't end with unchanged lines
572
        for struct in outstanding_struct():
573
            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.
574
1664.2.14 by Aaron Bentley
spacing fix
575
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
576
class WeaveMerge(PlanWeaveMerge):
1551.6.13 by Aaron Bentley
Cleanup
577
    """Weave merge that takes a VersionedFile and two versions as its input"""
578
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
579
    def __init__(self, versionedfile, ver_a, ver_b, 
1551.6.14 by Aaron Bentley
Tweaks from merge review
580
        a_marker=PlanWeaveMerge.A_MARKER, b_marker=PlanWeaveMerge.B_MARKER):
1551.6.15 by Aaron Bentley
Moved plan_merge into Weave
581
        plan = versionedfile.plan_merge(ver_a, ver_b)
1551.6.10 by Aaron Bentley
Renamed WeaveMerge to PlanMerge, added plan method, created planless WeaveMerge
582
        PlanWeaveMerge.__init__(self, plan, a_marker, b_marker)
583
584
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.
585
class InterVersionedFile(InterObject):
586
    """This class represents operations taking place between two versionedfiles..
587
588
    Its instances have methods like join, and contain
589
    references to the source and target versionedfiles these operations can be 
590
    carried out on.
591
592
    Often we will provide convenience methods on 'versionedfile' which carry out
593
    operations with another versionedfile - they will always forward to
594
    InterVersionedFile.get(other).method_name(parameters).
595
    """
596
1910.2.15 by Aaron Bentley
Back out inter.get changes, make optimizers an ordered list
597
    _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.
598
    """The available optimised InterVersionedFile types."""
599
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
600
    def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
1563.2.13 by Robert Collins
InterVersionedFile implemented.
601
        """Integrate versions from self.source into self.target.
602
603
        If version_ids is None all versions from source should be
604
        incorporated into this versioned file.
605
606
        Must raise RevisionNotPresent if any of the specified versions
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
607
        are not present in the other files history unless ignore_missing is 
608
        supplied when they are silently skipped.
1563.2.13 by Robert Collins
InterVersionedFile implemented.
609
        """
610
        # the default join: 
1594.2.11 by Robert Collins
Setup fast-code paths for copying into empty weaves and weave->empty knit.
611
        # - if the target is empty, just add all the versions from 
612
        #   source to target, otherwise:
1563.2.13 by Robert Collins
InterVersionedFile implemented.
613
        # - make a temporary versioned file of type target
614
        # - insert the source content into it one at a time
615
        # - join them
1594.2.11 by Robert Collins
Setup fast-code paths for copying into empty weaves and weave->empty knit.
616
        if not self.target.versions():
617
            target = self.target
618
        else:
619
            # Make a new target-format versioned file. 
620
            temp_source = self.target.create_empty("temp", MemoryTransport())
621
            target = temp_source
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
622
        version_ids = self._get_source_version_ids(version_ids, ignore_missing)
1684.3.1 by Robert Collins
Fix versioned file joins with empty targets.
623
        graph = self.source.get_graph(version_ids)
1996.3.7 by John Arbash Meinel
lazy import versionedfile, late-load bzrlib.merge
624
        order = tsort.topo_sort(graph.items())
1563.2.37 by Robert Collins
Merge in nested progress bars
625
        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.
626
        parent_texts = {}
1563.2.37 by Robert Collins
Merge in nested progress bars
627
        try:
1596.2.28 by Robert Collins
more knit profile based tuning.
628
            # TODO for incremental cross-format work:
1596.2.27 by Robert Collins
Note potential improvements in knit adds.
629
            # make a versioned file with the following content:
630
            # all revisions we have been asked to join
631
            # all their ancestors that are *not* in target already.
632
            # the immediate parents of the above two sets, with 
633
            # empty parent lists - these versions are in target already
634
            # and the incorrect version data will be ignored.
635
            # TODO: for all ancestors that are present in target already,
636
            # 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.
637
            # 
638
            # TODO: remove parent texts when they are not relevant any more for 
639
            # memory pressure reduction. RBC 20060313
640
            # pb.update('Converting versioned data', 0, len(order))
641
            # deltas = self.source.get_deltas(order)
1563.2.37 by Robert Collins
Merge in nested progress bars
642
            for index, version in enumerate(order):
643
                pb.update('Converting versioned data', index, len(order))
1596.2.38 by Robert Collins
rollback from using deltas to using fulltexts - deltas need more work to be ready.
644
                parent_text = target.add_lines(version,
645
                                               self.source.get_parents(version),
646
                                               self.source.get_lines(version),
647
                                               parent_texts=parent_texts)
648
                parent_texts[version] = parent_text
649
                #delta_parent, sha1, noeol, delta = deltas[version]
650
                #target.add_delta(version,
651
                #                 self.source.get_parents(version),
652
                #                 delta_parent,
653
                #                 sha1,
654
                #                 noeol,
655
                #                 delta)
656
                #target.get_lines(version)
1563.2.37 by Robert Collins
Merge in nested progress bars
657
            
658
            # 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.
659
            if target is not self.target:
660
                return self.target.join(temp_source,
661
                                        pb,
662
                                        msg,
663
                                        version_ids,
664
                                        ignore_missing)
1563.2.37 by Robert Collins
Merge in nested progress bars
665
        finally:
666
            pb.finished()
1563.2.13 by Robert Collins
InterVersionedFile implemented.
667
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
668
    def _get_source_version_ids(self, version_ids, ignore_missing):
669
        """Determine the version ids to be used from self.source.
670
671
        :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.
672
                            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.
673
        :param ignore_missing: if True, remove missing ids from the version 
674
                               list. If False, raise RevisionNotPresent on
675
                               a missing version id.
676
        :return: A set of version ids.
677
        """
678
        if version_ids is None:
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
679
            # None cannot be in source.versions
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
680
            return set(self.source.versions())
681
        else:
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
682
            version_ids = [osutils.safe_revision_id(v) for v in version_ids]
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
683
            if ignore_missing:
684
                return set(self.source.versions()).intersection(set(version_ids))
685
            else:
686
                new_version_ids = set()
687
                for version in version_ids:
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
688
                    if version is None:
689
                        continue
1684.3.2 by Robert Collins
Factor out version_ids-to-join selection in InterVersionedfile.
690
                    if not self.source.has_version(version):
691
                        raise errors.RevisionNotPresent(version, str(self.source))
692
                    else:
693
                        new_version_ids.add(version)
694
                return new_version_ids