/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.115.12 by John Arbash Meinel
Add a bunch of direct tests for the _TreeShim interface.
1
# Copyright (C) 2008, 2009 Canonical Ltd
0.64.5 by Ian Clatworthy
first cut at generic processing method
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
0.64.334 by Jelmer Vernooij
Remove old FSF address. Thanks Dan Callaghan.
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
0.64.5 by Ian Clatworthy
first cut at generic processing method
15
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
16
"""An abstraction of a repository providing just the bits importing needs."""
0.64.5 by Ian Clatworthy
first cut at generic processing method
17
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
18
from __future__ import absolute_import
19
6791.2.3 by Jelmer Vernooij
Fix more imports.
20
from ...sixish import StringIO
0.64.5 by Ian Clatworthy
first cut at generic processing method
21
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
22
from ... import (
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
23
    errors,
24
    graph as _mod_graph,
25
    lru_cache,
26
    osutils,
27
    revision as _mod_revision,
28
    trace,
29
    )
6670.4.1 by Jelmer Vernooij
Update imports.
30
from ...bzr import (
31
    knit,
32
    inventory,
33
    )
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
34
35
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
36
class _TreeShim(object):
37
    """Fake a Tree implementation.
38
39
    This implements just enough of the tree api to make commit builder happy.
40
    """
41
0.115.7 by John Arbash Meinel
Fall back to the repository for cases where the content is not present in the stream yet.
42
    def __init__(self, repo, basis_inv, inv_delta, content_provider):
43
        self._repo = repo
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
44
        self._content_provider = content_provider
45
        self._basis_inv = basis_inv
46
        self._inv_delta = inv_delta
47
        self._new_info_by_id = dict([(file_id, (new_path, ie))
48
                                    for _, new_path, file_id, ie in inv_delta])
49
50
    def id2path(self, file_id):
51
        if file_id in self._new_info_by_id:
52
            new_path = self._new_info_by_id[file_id][0]
53
            if new_path is None:
0.115.12 by John Arbash Meinel
Add a bunch of direct tests for the _TreeShim interface.
54
                raise errors.NoSuchId(self, file_id)
55
            return new_path
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
56
        return self._basis_inv.id2path(file_id)
57
58
    def path2id(self, path):
0.115.12 by John Arbash Meinel
Add a bunch of direct tests for the _TreeShim interface.
59
        # CommitBuilder currently only requires access to the root id. We don't
60
        # build a map of renamed files, etc. One possibility if we ever *do*
61
        # need more than just root, is to defer to basis_inv.path2id() and then
62
        # check if the file_id is in our _new_info_by_id dict. And in that
63
        # case, return _new_info_by_id[file_id][0]
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
64
        if path != '':
65
            raise NotImplementedError(_TreeShim.path2id)
66
        # TODO: Handle root renames?
67
        return self._basis_inv.root.file_id
68
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
69
    def get_file_with_stat(self, path, file_id=None):
70
        content = self.get_file_text(path, file_id)
6791.2.3 by Jelmer Vernooij
Fix more imports.
71
        sio = StringIO(content)
0.123.16 by Jelmer Vernooij
Support get_file_text in _TreeShim.
72
        return sio, None
73
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
74
    def get_file_text(self, path, file_id=None):
75
        if file_id is None:
76
            file_id = self.path2id(path)
0.115.7 by John Arbash Meinel
Fall back to the repository for cases where the content is not present in the stream yet.
77
        try:
0.123.16 by Jelmer Vernooij
Support get_file_text in _TreeShim.
78
            return self._content_provider(file_id)
0.115.7 by John Arbash Meinel
Fall back to the repository for cases where the content is not present in the stream yet.
79
        except KeyError:
80
            # The content wasn't shown as 'new'. Just validate this fact
81
            assert file_id not in self._new_info_by_id
82
            old_ie = self._basis_inv[file_id]
83
            old_text_key = (file_id, old_ie.revision)
84
            stream = self._repo.texts.get_record_stream([old_text_key],
85
                                                        'unordered', True)
0.123.16 by Jelmer Vernooij
Support get_file_text in _TreeShim.
86
            return stream.next().get_bytes_as('fulltext')
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
87
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
88
    def get_symlink_target(self, path, file_id=None):
89
        if file_id is None:
90
            file_id = self.path2id(path)
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
91
        if file_id in self._new_info_by_id:
92
            ie = self._new_info_by_id[file_id][1]
93
            return ie.symlink_target
94
        return self._basis_inv[file_id].symlink_target
95
6809.4.1 by Jelmer Vernooij
Swap file_id and path arguments for get_reference_revision and get_nested_tree.
96
    def get_reference_revision(self, path, file_id=None):
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
97
        raise NotImplementedError(_TreeShim.get_reference_revision)
98
99
    def _delta_to_iter_changes(self):
100
        """Convert the inv_delta into an iter_changes repr."""
101
        # iter_changes is:
102
        #   (file_id,
103
        #    (old_path, new_path),
104
        #    content_changed,
105
        #    (old_versioned, new_versioned),
106
        #    (old_parent_id, new_parent_id),
107
        #    (old_name, new_name),
108
        #    (old_kind, new_kind),
109
        #    (old_exec, new_exec),
110
        #   )
111
        basis_inv = self._basis_inv
112
        for old_path, new_path, file_id, ie in self._inv_delta:
0.115.12 by John Arbash Meinel
Add a bunch of direct tests for the _TreeShim interface.
113
            # Perf: Would this be faster if we did 'if file_id in basis_inv'?
114
            # Since the *very* common case is that the file already exists, it
115
            # probably is better to optimize for that
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
116
            try:
117
                old_ie = basis_inv[file_id]
118
            except errors.NoSuchId:
119
                old_ie = None
0.115.6 by John Arbash Meinel
We need to handle when the object has been deleted.
120
                if ie is None:
121
                    raise AssertionError('How is both old and new None?')
122
                    change = (file_id,
123
                        (old_path, new_path),
124
                        False,
125
                        (False, False),
126
                        (None, None),
127
                        (None, None),
128
                        (None, None),
129
                        (None, None),
130
                        )
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
131
                change = (file_id,
132
                    (old_path, new_path),
133
                    True,
134
                    (False, True),
135
                    (None, ie.parent_id),
136
                    (None, ie.name),
137
                    (None, ie.kind),
138
                    (None, ie.executable),
139
                    )
140
            else:
0.115.6 by John Arbash Meinel
We need to handle when the object has been deleted.
141
                if ie is None:
142
                    change = (file_id,
143
                        (old_path, new_path),
144
                        True,
145
                        (True, False),
146
                        (old_ie.parent_id, None),
147
                        (old_ie.name, None),
148
                        (old_ie.kind, None),
149
                        (old_ie.executable, None),
150
                        )
151
                else:
152
                    content_modified = (ie.text_sha1 != old_ie.text_sha1
153
                                        or ie.text_size != old_ie.text_size)
0.115.7 by John Arbash Meinel
Fall back to the repository for cases where the content is not present in the stream yet.
154
                    # TODO: ie.kind != old_ie.kind
0.115.12 by John Arbash Meinel
Add a bunch of direct tests for the _TreeShim interface.
155
                    # TODO: symlinks changing targets, content_modified?
0.115.6 by John Arbash Meinel
We need to handle when the object has been deleted.
156
                    change = (file_id,
157
                        (old_path, new_path),
158
                        content_modified,
159
                        (True, True),
160
                        (old_ie.parent_id, ie.parent_id),
161
                        (old_ie.name, ie.name),
162
                        (old_ie.kind, ie.kind),
163
                        (old_ie.executable, ie.executable),
164
                        )
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
165
            yield change
166
167
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
168
class AbstractRevisionStore(object):
0.64.5 by Ian Clatworthy
first cut at generic processing method
169
0.64.48 by Ian Clatworthy
one revision loader instance
170
    def __init__(self, repo):
0.64.5 by Ian Clatworthy
first cut at generic processing method
171
        """An object responsible for loading revisions into a repository.
172
173
        NOTE: Repository locking is not managed by this class. Clients
174
        should take a write lock, call load() multiple times, then release
175
        the lock.
176
177
        :param repository: the target repository
0.64.48 by Ian Clatworthy
one revision loader instance
178
        """
179
        self.repo = repo
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
180
        self._graph = None
181
        self._use_known_graph = True
0.84.8 by Ian Clatworthy
ensure the chk stuff is only used on formats actually supporting it
182
        self._supports_chks = getattr(repo._format, 'supports_chks', False)
0.81.3 by Ian Clatworthy
enhance RevisionLoader to try inventory deltas & decide on rich-roots
183
184
    def expects_rich_root(self):
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
185
        """Does this store expect inventories with rich roots?"""
0.81.3 by Ian Clatworthy
enhance RevisionLoader to try inventory deltas & decide on rich-roots
186
        return self.repo.supports_rich_root()
0.64.48 by Ian Clatworthy
one revision loader instance
187
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
188
    def init_inventory(self, revision_id):
189
        """Generate an inventory for a parentless revision."""
0.84.8 by Ian Clatworthy
ensure the chk stuff is only used on formats actually supporting it
190
        if self._supports_chks:
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
191
            inv = self._init_chk_inventory(revision_id, inventory.ROOT_ID)
192
        else:
193
            inv = inventory.Inventory(revision_id=revision_id)
0.84.6 by Ian Clatworthy
set maximum_size & key_width for initial parent_id_basename_to_file_id map
194
            if self.expects_rich_root():
195
                # The very first root needs to have the right revision
196
                inv.root.revision = revision_id
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
197
        return inv
198
199
    def _init_chk_inventory(self, revision_id, root_id):
200
        """Generate a CHKInventory for a parentless revision."""
6670.4.3 by Jelmer Vernooij
Fix more imports.
201
        from ...bzr import chk_map
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
202
        # Get the creation parameters
0.84.8 by Ian Clatworthy
ensure the chk stuff is only used on formats actually supporting it
203
        chk_store = self.repo.chk_bytes
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
204
        serializer = self.repo._format._serializer
205
        search_key_name = serializer.search_key_name
206
        maximum_size = serializer.maximum_size
207
208
        # Maybe the rest of this ought to be part of the CHKInventory API?
209
        inv = inventory.CHKInventory(search_key_name)
210
        inv.revision_id = revision_id
211
        inv.root_id = root_id
212
        search_key_func = chk_map.search_key_registry.get(search_key_name)
213
        inv.id_to_entry = chk_map.CHKMap(chk_store, None, search_key_func)
214
        inv.id_to_entry._root_node.set_maximum_size(maximum_size)
0.64.151 by Ian Clatworthy
parent_id_to_basename_index is no longer a serializer attribute - always required now
215
        inv.parent_id_basename_to_file_id = chk_map.CHKMap(chk_store,
216
            None, search_key_func)
217
        inv.parent_id_basename_to_file_id._root_node.set_maximum_size(
218
            maximum_size)
219
        inv.parent_id_basename_to_file_id._root_node._key_width = 2
0.84.4 by Ian Clatworthy
improved-but-not-yet-working CHKInventory support
220
        return inv
221
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
222
    def get_inventory(self, revision_id):
223
        """Get a stored inventory."""
224
        return self.repo.get_inventory(revision_id)
225
226
    def get_file_text(self, revision_id, file_id):
227
        """Get the text stored for a file in a given revision."""
228
        revtree = self.repo.revision_tree(revision_id)
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
229
        path = revtree.id2path(file_id)
230
        return revtree.get_file_text(path, file_id)
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
231
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
232
    def get_file_lines(self, revision_id, file_id):
233
        """Get the lines stored for a file in a given revision."""
0.64.156 by Ian Clatworthy
minor revision_store clean-ups
234
        revtree = self.repo.revision_tree(revision_id)
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
235
        path = revtree.id2path(file_id)
236
        return osutils.split_lines(revtree.get_file_text(path, file_id))
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
237
0.85.2 by Ian Clatworthy
improve per-file graph generation
238
    def start_new_revision(self, revision, parents, parent_invs):
239
        """Init the metadata needed for get_parents_and_revision_for_entry().
240
241
        :param revision: a Revision object
242
        """
243
        self._current_rev_id = revision.revision_id
244
        self._rev_parents = parents
245
        self._rev_parent_invs = parent_invs
246
        # We don't know what the branch will be so there's no real BranchConfig.
247
        # That means we won't be triggering any hooks and that's a good thing.
248
        # Without a config though, we must pass in the committer below so that
249
        # the commit builder doesn't try to look up the config.
250
        config = None
251
        # We can't use self.repo.get_commit_builder() here because it starts a
252
        # new write group. We want one write group around a batch of imports
253
        # where the default batch size is currently 10000. IGC 20090312
254
        self._commit_builder = self.repo._commit_builder_class(self.repo,
255
            parents, config, timestamp=revision.timestamp,
256
            timezone=revision.timezone, committer=revision.committer,
257
            revprops=revision.properties, revision_id=revision.revision_id)
258
259
    def get_parents_and_revision_for_entry(self, ie):
260
        """Get the parents and revision for an inventory entry.
0.64.161 by Ian Clatworthy
fix per-graph parent handling for adds and renames
261
 
0.85.2 by Ian Clatworthy
improve per-file graph generation
262
        :param ie: the inventory entry
263
        :return parents, revision_id where
0.64.160 by Ian Clatworthy
make per-file parents tuples and fix text loading in chk formats
264
            parents is the tuple of parent revision_ids for the per-file graph
0.85.2 by Ian Clatworthy
improve per-file graph generation
265
            revision_id is the revision_id to use for this entry
266
        """
267
        # Check for correct API usage
268
        if self._current_rev_id is None:
269
            raise AssertionError("start_new_revision() must be called"
270
                " before get_parents_and_revision_for_entry()")
271
        if ie.revision != self._current_rev_id:
272
            raise AssertionError("start_new_revision() registered a different"
273
                " revision (%s) to that in the inventory entry (%s)" %
274
                (self._current_rev_id, ie.revision))
275
276
        # Find the heads. This code is lifted from
277
        # repository.CommitBuilder.record_entry_contents().
278
        parent_candidate_entries = ie.parent_candidates(self._rev_parent_invs)
279
        head_set = self._commit_builder._heads(ie.file_id,
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
280
            list(parent_candidate_entries))
0.85.2 by Ian Clatworthy
improve per-file graph generation
281
        heads = []
282
        for inv in self._rev_parent_invs:
0.64.323 by Jelmer Vernooij
Avoid deprecated Inventory.__contains__.
283
            if inv.has_id(ie.file_id):
0.85.2 by Ian Clatworthy
improve per-file graph generation
284
                old_rev = inv[ie.file_id].revision
285
                if old_rev in head_set:
0.64.161 by Ian Clatworthy
fix per-graph parent handling for adds and renames
286
                    rev_id = inv[ie.file_id].revision
287
                    heads.append(rev_id)
288
                    head_set.remove(rev_id)
0.85.2 by Ian Clatworthy
improve per-file graph generation
289
290
        # Find the revision to use. If the content has not changed
291
        # since the parent, record the parent's revision.
0.64.161 by Ian Clatworthy
fix per-graph parent handling for adds and renames
292
        if len(heads) == 0:
293
            return (), ie.revision
0.85.2 by Ian Clatworthy
improve per-file graph generation
294
        parent_entry = parent_candidate_entries[heads[0]]
295
        changed = False
296
        if len(heads) > 1:
297
            changed = True
0.64.161 by Ian Clatworthy
fix per-graph parent handling for adds and renames
298
        elif (parent_entry.name != ie.name or parent_entry.kind != ie.kind or
0.85.2 by Ian Clatworthy
improve per-file graph generation
299
            parent_entry.parent_id != ie.parent_id): 
300
            changed = True
301
        elif ie.kind == 'file':
302
            if (parent_entry.text_sha1 != ie.text_sha1 or
303
                parent_entry.executable != ie.executable):
304
                changed = True
305
        elif ie.kind == 'symlink':
306
            if parent_entry.symlink_target != ie.symlink_target:
307
                changed = True
308
        if changed:
309
            rev_id = ie.revision
310
        else:
311
            rev_id = parent_entry.revision
0.64.160 by Ian Clatworthy
make per-file parents tuples and fix text loading in chk formats
312
        return tuple(heads), rev_id
0.85.2 by Ian Clatworthy
improve per-file graph generation
313
314
    def load(self, rev, inv, signature, text_provider, parents_provider,
0.64.48 by Ian Clatworthy
one revision loader instance
315
        inventories_provider=None):
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
316
        """Load a revision.
0.64.48 by Ian Clatworthy
one revision loader instance
317
318
        :param rev: the Revision
319
        :param inv: the inventory
320
        :param signature: signing information
321
        :param text_provider: a callable expecting a file_id parameter
322
            that returns the text for that file-id
0.85.2 by Ian Clatworthy
improve per-file graph generation
323
        :param parents_provider: a callable expecting a file_id parameter
324
            that return the list of parent-ids for that file-id
0.64.5 by Ian Clatworthy
first cut at generic processing method
325
        :param inventories_provider: a callable expecting a repository and
326
            a list of revision-ids, that returns:
327
              * the list of revision-ids present in the repository
328
              * the list of inventories for the revision-id's,
329
                including an empty inventory for the missing revisions
330
            If None, a default implementation is provided.
331
        """
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
332
        # NOTE: This is breezy.repository._install_revision refactored to
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
333
        # to provide more flexibility in how previous revisions are cached,
334
        # data is feed in, etc.
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
335
336
        # Get the non-ghost parents and their inventories
337
        if inventories_provider is None:
338
            inventories_provider = self._default_inventories_provider
339
        present_parents, parent_invs = inventories_provider(rev.parent_ids)
340
341
        # Load the inventory
342
        try:
343
            rev.inventory_sha1 = self._add_inventory(rev.revision_id,
344
                inv, present_parents, parent_invs)
345
        except errors.RevisionAlreadyPresent:
346
            pass
347
348
        # Load the texts, signature and revision
349
        entries = self._non_root_entries_iter(inv, rev.revision_id)
0.85.2 by Ian Clatworthy
improve per-file graph generation
350
        self._load_texts(rev.revision_id, entries, text_provider,
351
            parents_provider)
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
352
        if signature is not None:
353
            self.repo.add_signature_text(rev.revision_id, signature)
354
        self._add_revision(rev, inv)
355
0.64.171 by Ian Clatworthy
use inv deltas by default for all formats now: --classic to get old algorithm for packs
356
    def load_using_delta(self, rev, basis_inv, inv_delta, signature,
0.85.2 by Ian Clatworthy
improve per-file graph generation
357
        text_provider, parents_provider, inventories_provider=None):
0.64.171 by Ian Clatworthy
use inv deltas by default for all formats now: --classic to get old algorithm for packs
358
        """Load a revision by applying a delta to a (CHK)Inventory.
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
359
360
        :param rev: the Revision
0.64.171 by Ian Clatworthy
use inv deltas by default for all formats now: --classic to get old algorithm for packs
361
        :param basis_inv: the basis Inventory or CHKInventory
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
362
        :param inv_delta: the inventory delta
363
        :param signature: signing information
364
        :param text_provider: a callable expecting a file_id parameter
365
            that returns the text for that file-id
0.85.2 by Ian Clatworthy
improve per-file graph generation
366
        :param parents_provider: a callable expecting a file_id parameter
367
            that return the list of parent-ids for that file-id
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
368
        :param inventories_provider: a callable expecting a repository and
369
            a list of revision-ids, that returns:
370
              * the list of revision-ids present in the repository
371
              * the list of inventories for the revision-id's,
372
                including an empty inventory for the missing revisions
373
            If None, a default implementation is provided.
374
        """
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
375
        # TODO: set revision_id = rev.revision_id
376
        builder = self.repo._commit_builder_class(self.repo,
377
            parents=rev.parent_ids, config=None, timestamp=rev.timestamp,
378
            timezone=rev.timezone, committer=rev.committer,
379
            revprops=rev.properties, revision_id=rev.revision_id)
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
380
        if self._graph is None and self._use_known_graph:
0.64.290 by Jelmer Vernooij
Avoid use of Repository.revisions, which may not be set.
381
            if (getattr(_mod_graph, 'GraphThunkIdsToKeys', None) and
382
                getattr(_mod_graph.GraphThunkIdsToKeys, "add_node", None) and
383
                getattr(self.repo, "get_known_graph_ancestry", None)):
384
                self._graph = self.repo.get_known_graph_ancestry(
385
                    rev.parent_ids)
386
            else:
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
387
                self._use_known_graph = False
388
        if self._graph is not None:
0.116.2 by John Arbash Meinel
Some debugging code. It looks like the main bugs involve files that are deleted and restored.
389
            orig_heads = builder._heads
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
390
            def thunked_heads(file_id, revision_ids):
391
                # self._graph thinks in terms of keys, not ids, so translate
392
                # them
0.116.2 by John Arbash Meinel
Some debugging code. It looks like the main bugs involve files that are deleted and restored.
393
                # old_res = orig_heads(file_id, revision_ids)
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
394
                if len(revision_ids) < 2:
0.116.2 by John Arbash Meinel
Some debugging code. It looks like the main bugs involve files that are deleted and restored.
395
                    res = set(revision_ids)
396
                else:
0.64.290 by Jelmer Vernooij
Avoid use of Repository.revisions, which may not be set.
397
                    res = set(self._graph.heads(revision_ids))
0.116.2 by John Arbash Meinel
Some debugging code. It looks like the main bugs involve files that are deleted and restored.
398
                # if old_res != res:
399
                #     import pdb; pdb.set_trace()
400
                return res
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
401
            builder._heads = thunked_heads
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
402
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
403
        if rev.parent_ids:
404
            basis_rev_id = rev.parent_ids[0]
405
        else:
406
            basis_rev_id = _mod_revision.NULL_REVISION
0.115.7 by John Arbash Meinel
Fall back to the repository for cases where the content is not present in the stream yet.
407
        tree = _TreeShim(self.repo, basis_inv, inv_delta, text_provider)
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
408
        changes = tree._delta_to_iter_changes()
409
        for (file_id, path, fs_hash) in builder.record_iter_changes(
410
                tree, basis_rev_id, changes):
411
            # So far, we don't *do* anything with the result
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
412
            pass
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
413
        builder.finish_inventory()
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
414
        # TODO: This is working around a bug in the breezy code base.
0.115.5 by John Arbash Meinel
Found a bug in CommitBuilder.finish_inventory().
415
        # 'builder.finish_inventory()' ends up doing:
416
        # self.inv_sha1 = self.repository.add_inventory_by_delta(...)
417
        # However, add_inventory_by_delta returns (sha1, inv)
418
        # And we *want* to keep a handle on both of those objects
419
        if isinstance(builder.inv_sha1, tuple):
420
            builder.inv_sha1, builder.new_inventory = builder.inv_sha1
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
421
        # This is a duplicate of Builder.commit() since we already have the
422
        # Revision object, and we *don't* want to call commit_write_group()
423
        rev.inv_sha1 = builder.inv_sha1
6690.2.2 by Jelmer Vernooij
Drop support for bzr < 2.5.
424
        config = builder._config_stack
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
425
        builder.repository.add_revision(builder._new_revision_id, rev,
6700.2.4 by Jelmer Vernooij
Fix test.
426
            builder.revision_tree().root_inventory)
0.116.1 by John Arbash Meinel
Use the new KnownGraph.add_node() functionality.
427
        if self._graph is not None:
428
            # TODO: Use StaticTuple and .intern() for these things
0.64.290 by Jelmer Vernooij
Avoid use of Repository.revisions, which may not be set.
429
            self._graph.add_node(builder._new_revision_id, rev.parent_ids)
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
430
431
        if signature is not None:
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
432
            raise AssertionError('signatures not guaranteed yet')
0.64.290 by Jelmer Vernooij
Avoid use of Repository.revisions, which may not be set.
433
            self.repo.add_signature_text(rev.revision_id, signature)
0.115.4 by John Arbash Meinel
(broken) Start working towards using CommitBuilder rather than using a custom implementation.
434
        # self._add_revision(rev, inv)
6643.1.1 by Jelmer Vernooij
Fix fastimport tests now that RevisionTree.inventory has been removed.
435
        return builder.revision_tree().root_inventory
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
436
437
    def _non_root_entries_iter(self, inv, revision_id):
0.84.11 by Ian Clatworthy
use iter_non_root_entries if it exists
438
        if hasattr(inv, 'iter_non_root_entries'):
439
            entries = inv.iter_non_root_entries()
440
        else:
441
            path_entries = inv.iter_entries()
442
            # Backwards compatibility hack: skip the root id.
443
            if not self.repo.supports_rich_root():
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
444
                path, root = next(path_entries)
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
445
                if root.revision != revision_id:
0.84.11 by Ian Clatworthy
use iter_non_root_entries if it exists
446
                    raise errors.IncompatibleRevision(repr(self.repo))
447
            entries = iter([ie for path, ie in path_entries])
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
448
        return entries
0.81.10 by Ian Clatworthy
get DeltaCommitHandler passing all tests
449
0.85.2 by Ian Clatworthy
improve per-file graph generation
450
    def _load_texts(self, revision_id, entries, text_provider,
451
        parents_provider):
0.64.5 by Ian Clatworthy
first cut at generic processing method
452
        """Load texts to a repository for inventory entries.
453
        
454
        This method is provided for subclasses to use or override.
455
456
        :param revision_id: the revision identifier
457
        :param entries: iterator over the inventory entries
458
        :param text_provider: a callable expecting a file_id parameter
459
            that returns the text for that file-id
0.85.2 by Ian Clatworthy
improve per-file graph generation
460
        :param parents_provider: a callable expecting a file_id parameter
461
            that return the list of parent-ids for that file-id
0.64.5 by Ian Clatworthy
first cut at generic processing method
462
        """
0.64.79 by Ian Clatworthy
support new Repository API
463
        raise NotImplementedError(self._load_texts)
0.64.5 by Ian Clatworthy
first cut at generic processing method
464
0.81.3 by Ian Clatworthy
enhance RevisionLoader to try inventory deltas & decide on rich-roots
465
    def _add_inventory(self, revision_id, inv, parents, parent_invs):
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
466
        """Add the inventory inv to the repository as revision_id.
467
        
468
        :param parents: The revision ids of the parents that revision_id
469
                        is known to have and are in the repository already.
0.81.3 by Ian Clatworthy
enhance RevisionLoader to try inventory deltas & decide on rich-roots
470
        :param parent_invs: the parent inventories
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
471
472
        :returns: The validator(which is a sha1 digest, though what is sha'd is
473
            repository format specific) of the serialized inventory.
474
        """
0.64.156 by Ian Clatworthy
minor revision_store clean-ups
475
        return self.repo.add_inventory(revision_id, inv, parents)
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
476
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
477
    def _add_inventory_by_delta(self, revision_id, basis_inv, inv_delta,
478
        parents, parent_invs):
479
        """Add the inventory to the repository as revision_id.
480
        
0.64.171 by Ian Clatworthy
use inv deltas by default for all formats now: --classic to get old algorithm for packs
481
        :param basis_inv: the basis Inventory or CHKInventory
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
482
        :param inv_delta: the inventory delta
483
        :param parents: The revision ids of the parents that revision_id
484
                        is known to have and are in the repository already.
485
        :param parent_invs: the parent inventories
486
0.64.156 by Ian Clatworthy
minor revision_store clean-ups
487
        :returns: (validator, inv) where validator is the validator
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
488
          (which is a sha1 digest, though what is sha'd is repository format
489
          specific) of the serialized inventory;
490
          inv is the generated inventory
491
        """
492
        if len(parents):
0.64.171 by Ian Clatworthy
use inv deltas by default for all formats now: --classic to get old algorithm for packs
493
            if self._supports_chks:
0.99.3 by Ian Clatworthy
Improve diagnostics collection when inconsistent delta found
494
                try:
495
                    validator, new_inv = self.repo.add_inventory_by_delta(parents[0],
496
                        inv_delta, revision_id, parents, basis_inv=basis_inv,
497
                        propagate_caches=False)
498
                except errors.InconsistentDelta:
499
                    #print "BASIS INV IS\n%s\n" % "\n".join([str(i) for i in basis_inv.iter_entries_by_dir()])
500
                    trace.mutter("INCONSISTENT DELTA IS:\n%s\n" % "\n".join([str(i) for i in inv_delta]))
501
                    raise
0.64.171 by Ian Clatworthy
use inv deltas by default for all formats now: --classic to get old algorithm for packs
502
            else:
503
                validator, new_inv = self.repo.add_inventory_by_delta(parents[0],
504
                    inv_delta, revision_id, parents)
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
505
        else:
0.64.257 by Ian Clatworthy
Get fastimport working on non-chk repositories again for bzr versions after 2.0.0
506
            if isinstance(basis_inv, inventory.CHKInventory):
0.64.171 by Ian Clatworthy
use inv deltas by default for all formats now: --classic to get old algorithm for packs
507
                new_inv = basis_inv.create_by_apply_delta(inv_delta, revision_id)
508
            else:
509
                new_inv = inventory.Inventory(revision_id=revision_id)
510
                # This is set in the delta so remove it to prevent a duplicate
511
                del new_inv[inventory.ROOT_ID]
512
                new_inv.apply_delta(inv_delta)
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
513
            validator = self.repo.add_inventory(revision_id, new_inv, parents)
514
        return validator, new_inv
515
0.64.79 by Ian Clatworthy
support new Repository API
516
    def _add_revision(self, rev, inv):
517
        """Add a revision and its inventory to a repository.
518
519
        :param rev: the Revision
520
        :param inv: the inventory
521
        """
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
522
        self.repo.add_revision(rev.revision_id, rev, inv)
0.64.79 by Ian Clatworthy
support new Repository API
523
0.64.5 by Ian Clatworthy
first cut at generic processing method
524
    def _default_inventories_provider(self, revision_ids):
525
        """An inventories provider that queries the repository."""
526
        present = []
527
        inventories = []
528
        for revision_id in revision_ids:
529
            if self.repo.has_revision(revision_id):
530
                present.append(revision_id)
531
                rev_tree = self.repo.revision_tree(revision_id)
532
            else:
533
                rev_tree = self.repo.revision_tree(None)
6643.1.1 by Jelmer Vernooij
Fix fastimport tests now that RevisionTree.inventory has been removed.
534
            inventories.append(rev_tree.root_inventory)
0.64.5 by Ian Clatworthy
first cut at generic processing method
535
        return present, inventories
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
536
537
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
538
class RevisionStore1(AbstractRevisionStore):
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
539
    """A RevisionStore that uses the old breezy Repository API.
0.64.79 by Ian Clatworthy
support new Repository API
540
    
541
    The old API was present until bzr.dev rev 3510.
542
    """
543
0.85.2 by Ian Clatworthy
improve per-file graph generation
544
    def _load_texts(self, revision_id, entries, text_provider, parents_provider):
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
545
        """See RevisionStore._load_texts()."""
0.64.79 by Ian Clatworthy
support new Repository API
546
        # Add the texts that are not already present
547
        tx = self.repo.get_transaction()
0.84.11 by Ian Clatworthy
use iter_non_root_entries if it exists
548
        for ie in entries:
0.64.79 by Ian Clatworthy
support new Repository API
549
            # This test is *really* slow: over 50% of import time
550
            #w = self.repo.weave_store.get_weave_or_empty(ie.file_id, tx)
551
            #if ie.revision in w:
552
            #    continue
553
            # Try another way, realising that this assumes that the
554
            # version is not already there. In the general case,
555
            # a shared repository might already have the revision but
556
            # we arguably don't need that check when importing from
557
            # a foreign system.
558
            if ie.revision != revision_id:
559
                continue
0.85.2 by Ian Clatworthy
improve per-file graph generation
560
            file_id = ie.file_id
561
            text_parents = [(file_id, p) for p in parents_provider(file_id)]
562
            lines = text_provider(file_id)
563
            vfile = self.repo.weave_store.get_weave_or_empty(file_id,  tx)
0.64.79 by Ian Clatworthy
support new Repository API
564
            vfile.add_lines(revision_id, text_parents, lines)
565
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
566
    def get_file_lines(self, revision_id, file_id):
0.74.1 by John Arbash Meinel
Change the rename code to create a new text entry.
567
        tx = self.repo.get_transaction()
0.64.139 by Ian Clatworthy
fix ie reference in _get_file_lines()
568
        w = self.repo.weave_store.get_weave(file_id, tx)
0.74.1 by John Arbash Meinel
Change the rename code to create a new text entry.
569
        return w.get_lines(revision_id)
570
0.64.79 by Ian Clatworthy
support new Repository API
571
    def _add_revision(self, rev, inv):
572
        # There's no need to do everything repo.add_revision does and
573
        # doing so (since bzr.dev 3392) can be pretty slow for long
574
        # delta chains on inventories. Just do the essentials here ...
575
        _mod_revision.check_not_reserved_id(rev.revision_id)
576
        self.repo._revision_store.add_revision(rev, self.repo.get_transaction())
577
578
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
579
class RevisionStore2(AbstractRevisionStore):
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
580
    """A RevisionStore that uses the new breezy Repository API."""
0.64.79 by Ian Clatworthy
support new Repository API
581
0.85.2 by Ian Clatworthy
improve per-file graph generation
582
    def _load_texts(self, revision_id, entries, text_provider, parents_provider):
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
583
        """See RevisionStore._load_texts()."""
0.64.79 by Ian Clatworthy
support new Repository API
584
        text_keys = {}
0.84.11 by Ian Clatworthy
use iter_non_root_entries if it exists
585
        for ie in entries:
0.64.79 by Ian Clatworthy
support new Repository API
586
            text_keys[(ie.file_id, ie.revision)] = ie
587
        text_parent_map = self.repo.texts.get_parent_map(text_keys)
588
        missing_texts = set(text_keys) - set(text_parent_map)
0.85.2 by Ian Clatworthy
improve per-file graph generation
589
        self._load_texts_for_file_rev_ids(missing_texts, text_provider,
590
            parents_provider)
0.64.79 by Ian Clatworthy
support new Repository API
591
0.85.2 by Ian Clatworthy
improve per-file graph generation
592
    def _load_texts_for_file_rev_ids(self, file_rev_ids, text_provider,
593
        parents_provider):
0.64.155 by Ian Clatworthy
store empty texts for non-files for chk formats, not just other formats
594
        """Load texts to a repository for file-ids, revision-id tuples.
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
595
        
0.64.155 by Ian Clatworthy
store empty texts for non-files for chk formats, not just other formats
596
        :param file_rev_ids: iterator over the (file_id, revision_id) tuples
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
597
        :param text_provider: a callable expecting a file_id parameter
598
            that returns the text for that file-id
0.85.2 by Ian Clatworthy
improve per-file graph generation
599
        :param parents_provider: a callable expecting a file_id parameter
600
            that return the list of parent-ids for that file-id
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
601
        """
0.64.155 by Ian Clatworthy
store empty texts for non-files for chk formats, not just other formats
602
        for file_id, revision_id in file_rev_ids:
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
603
            text_key = (file_id, revision_id)
0.85.2 by Ian Clatworthy
improve per-file graph generation
604
            text_parents = [(file_id, p) for p in parents_provider(file_id)]
605
            lines = text_provider(file_id)
606
            #print "adding text for %s\n\tparents:%s" % (text_key,text_parents)
0.84.13 by Ian Clatworthy
smarter RevisionStore.chk_load()
607
            self.repo.texts.add_lines(text_key, text_parents, lines)
608
0.81.7 by Ian Clatworthy
merge import tests and tweaks to make them pass
609
    def get_file_lines(self, revision_id, file_id):
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
610
        record = next(self.repo.texts.get_record_stream([(file_id, revision_id)],
611
            'unordered', True))
0.74.1 by John Arbash Meinel
Change the rename code to create a new text entry.
612
        if record.storage_kind == 'absent':
613
            raise errors.RevisionNotPresent(record.key, self.repo)
614
        return osutils.split_lines(record.get_bytes_as('fulltext'))
615
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
616
    # This is breaking imports into brisbane-core currently
617
    #def _add_revision(self, rev, inv):
618
    #    # There's no need to do everything repo.add_revision does and
619
    #    # doing so (since bzr.dev 3392) can be pretty slow for long
620
    #    # delta chains on inventories. Just do the essentials here ...
621
    #    _mod_revision.check_not_reserved_id(rev.revision_id)
622
    #    self.repo._add_revision(rev)
0.64.79 by Ian Clatworthy
support new Repository API
623
 
624
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
625
class ImportRevisionStore1(RevisionStore1):
626
    """A RevisionStore (old Repository API) optimised for importing.
0.64.79 by Ian Clatworthy
support new Repository API
627
628
    This implementation caches serialised inventory texts and provides
629
    fine-grained control over when inventories are stored as fulltexts.
630
    """
631
632
    def __init__(self, repo, parent_texts_to_cache=1, fulltext_when=None,
633
        random_ids=True):
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
634
        """See AbstractRevisionStore.__init__.
0.64.48 by Ian Clatworthy
one revision loader instance
635
636
        :param repository: the target repository
637
        :param parent_text_to_cache: the number of parent texts to cache
0.64.79 by Ian Clatworthy
support new Repository API
638
        :para fulltext_when: if non None, a function to call to decide
639
          whether to fulltext the inventory or not. The revision count
640
          is passed as a parameter and the result is treated as a boolean.
0.64.48 by Ian Clatworthy
one revision loader instance
641
        """
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
642
        RevisionStore1.__init__(self, repo)
0.64.48 by Ian Clatworthy
one revision loader instance
643
        self.inv_parent_texts = lru_cache.LRUCache(parent_texts_to_cache)
0.64.79 by Ian Clatworthy
support new Repository API
644
        self.fulltext_when = fulltext_when
0.64.49 by Ian Clatworthy
skip check re fulltext storage better than delta for inventories when in experimental mode
645
        self.random_ids = random_ids
0.64.79 by Ian Clatworthy
support new Repository API
646
        self.revision_count = 0
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
647
0.81.3 by Ian Clatworthy
enhance RevisionLoader to try inventory deltas & decide on rich-roots
648
    def _add_inventory(self, revision_id, inv, parents, parent_invs):
0.81.4 by Ian Clatworthy
generalise RevisionLoader to RevisionStore as a repo abstraction
649
        """See RevisionStore._add_inventory."""
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
650
        # Code taken from breezy.repository.add_inventory
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
651
        assert self.repo.is_in_write_group()
652
        _mod_revision.check_not_reserved_id(revision_id)
653
        assert inv.revision_id is None or inv.revision_id == revision_id, \
654
            "Mismatch between inventory revision" \
655
            " id and insertion revid (%r, %r)" % (inv.revision_id, revision_id)
656
        assert inv.root is not None
657
        inv_lines = self.repo._serialise_inventory_to_lines(inv)
658
        inv_vf = self.repo.get_inventory_weave()
0.64.49 by Ian Clatworthy
skip check re fulltext storage better than delta for inventories when in experimental mode
659
        sha1, num_bytes, parent_text = self._inventory_add_lines(inv_vf,
660
            revision_id, parents, inv_lines, self.inv_parent_texts)
661
        self.inv_parent_texts[revision_id] = parent_text
662
        return sha1
663
664
    def _inventory_add_lines(self, inv_vf, version_id, parents, lines,
665
            parent_texts):
666
        """See Repository._inventory_add_lines()."""
667
        # setup parameters used in original code but not this API
668
        self.revision_count += 1
0.64.77 by Ian Clatworthy
add inv-fulltext option and improve speed
669
        if self.fulltext_when is not None:
670
            delta = not self.fulltext_when(self.revision_count)
0.64.49 by Ian Clatworthy
skip check re fulltext storage better than delta for inventories when in experimental mode
671
        else:
672
            delta = inv_vf.delta
673
        left_matching_blocks = None
674
        random_id = self.random_ids
675
        check_content = False
676
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
677
        # breezy.knit.add_lines() but error checking optimised
0.64.49 by Ian Clatworthy
skip check re fulltext storage better than delta for inventories when in experimental mode
678
        inv_vf._check_add(version_id, lines, random_id, check_content)
679
680
        ####################################################################
6628.1.2 by Jelmer Vernooij
Fix imports, move exporter.py, drop explorer metadata.
681
        # breezy.knit._add() but skip checking if fulltext better than delta
0.64.49 by Ian Clatworthy
skip check re fulltext storage better than delta for inventories when in experimental mode
682
        ####################################################################
683
684
        line_bytes = ''.join(lines)
685
        digest = osutils.sha_string(line_bytes)
686
        present_parents = []
687
        for parent in parents:
688
            if inv_vf.has_version(parent):
689
                present_parents.append(parent)
690
        if parent_texts is None:
691
            parent_texts = {}
692
693
        # can only compress against the left most present parent.
694
        if (delta and
695
            (len(present_parents) == 0 or
696
             present_parents[0] != parents[0])):
697
            delta = False
698
699
        text_length = len(line_bytes)
700
        options = []
701
        if lines:
702
            if lines[-1][-1] != '\n':
703
                # copy the contents of lines.
704
                lines = lines[:]
705
                options.append('no-eol')
706
                lines[-1] = lines[-1] + '\n'
707
                line_bytes += '\n'
708
709
        #if delta:
710
        #    # To speed the extract of texts the delta chain is limited
711
        #    # to a fixed number of deltas.  This should minimize both
712
        #    # I/O and the time spend applying deltas.
713
        #    delta = inv_vf._check_should_delta(present_parents)
714
715
        assert isinstance(version_id, str)
716
        content = inv_vf.factory.make(lines, version_id)
717
        if delta or (inv_vf.factory.annotated and len(present_parents) > 0):
718
            # Merge annotations from parent texts if needed.
719
            delta_hunks = inv_vf._merge_annotations(content, present_parents,
720
                parent_texts, delta, inv_vf.factory.annotated,
721
                left_matching_blocks)
722
723
        if delta:
724
            options.append('line-delta')
725
            store_lines = inv_vf.factory.lower_line_delta(delta_hunks)
726
            size, bytes = inv_vf._data._record_to_data(version_id, digest,
727
                store_lines)
728
        else:
729
            options.append('fulltext')
730
            # isinstance is slower and we have no hierarchy.
731
            if inv_vf.factory.__class__ == knit.KnitPlainFactory:
732
                # Use the already joined bytes saving iteration time in
733
                # _record_to_data.
734
                size, bytes = inv_vf._data._record_to_data(version_id, digest,
735
                    lines, [line_bytes])
736
            else:
737
                # get mixed annotation + content and feed it into the
738
                # serialiser.
739
                store_lines = inv_vf.factory.lower_fulltext(content)
740
                size, bytes = inv_vf._data._record_to_data(version_id, digest,
741
                    store_lines)
742
743
        access_memo = inv_vf._data.add_raw_records([size], bytes)[0]
744
        inv_vf._index.add_versions(
745
            ((version_id, options, access_memo, parents),),
746
            random_id=random_id)
747
        return digest, text_length, content