~bzr-pqm/bzr/bzr.dev

2520.4.20 by Aaron Bentley
Compress and base64-encode bundle contents
1
from cStringIO import StringIO
2520.4.26 by Aaron Bentley
Make decompression reasonably memory-efficient
2
import bz2
2520.4.20 by Aaron Bentley
Compress and base64-encode bundle contents
3
2520.4.27 by Aaron Bentley
Use less memory when writing bzip-encoded files
4
# The number of bytes per base64-encoded line.  We could use less, but it would
5
# be ugly
6
BASE64_LINE_BYTES = 57
7
2520.4.13 by Aaron Bentley
Use real container implementation
8
from bzrlib import (
2520.4.40 by Aaron Bentley
Add human-readable diff to bundles
9
    diff,
2520.4.34 by Aaron Bentley
Add signature support
10
    errors,
2520.4.26 by Aaron Bentley
Make decompression reasonably memory-efficient
11
    iterablefile,
2520.4.13 by Aaron Bentley
Use real container implementation
12
    multiparent,
13
    pack,
2520.4.40 by Aaron Bentley
Add human-readable diff to bundles
14
    revision as _mod_revision,
2520.4.34 by Aaron Bentley
Add signature support
15
    testament as _mod_testament,
2520.4.45 by Aaron Bentley
Handle inconsistencies in last-modified-revision between vf and inventory
16
    trace,
2520.4.13 by Aaron Bentley
Use real container implementation
17
    )
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
18
from bzrlib.bundle import bundle_data, serializer
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
19
from bzrlib.util import bencode
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
20
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
21
2520.4.25 by Aaron Bentley
Rename ContainerWriter/ContainerReader to BundleWriter/BundleReader
22
class BundleWriter(object):
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
23
2520.4.23 by Aaron Bentley
Move responsability for encoding into container objects
24
    def __init__(self, fileobj):
2520.4.27 by Aaron Bentley
Use less memory when writing bzip-encoded files
25
        self._container = pack.ContainerWriter(self._write_encoded)
2520.4.23 by Aaron Bentley
Move responsability for encoding into container objects
26
        self._fileobj = fileobj
2520.4.27 by Aaron Bentley
Use less memory when writing bzip-encoded files
27
        self._compressor = bz2.BZ2Compressor()
28
        self._base64_buffer = ''
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
29
30
    def begin(self):
2520.4.72 by Aaron Bentley
Rename format to 4alpha
31
        self._fileobj.write(serializer._get_bundle_header('4alpha'))
2520.4.24 by Aaron Bentley
Move heading writing above container beginning
32
        self._fileobj.write('#\n')
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
33
        self._container.begin()
34
2520.4.27 by Aaron Bentley
Use less memory when writing bzip-encoded files
35
    def _write_encoded(self, bytes):
36
        self._base64_buffer += self._compressor.compress(bytes)
37
        if len(self._base64_buffer) >=  BASE64_LINE_BYTES:
38
            to_leave = len(self._base64_buffer) % BASE64_LINE_BYTES
39
            self._fileobj.write(self._base64_buffer[:-to_leave].encode(
40
                'base-64'))
41
            self._base64_buffer = self._base64_buffer[-to_leave:]
42
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
43
    def end(self):
44
        self._container.end()
2520.4.27 by Aaron Bentley
Use less memory when writing bzip-encoded files
45
        tail = self._base64_buffer+self._compressor.flush()
46
        self._fileobj.write(tail.encode('base-64'))
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
47
2520.4.60 by Aaron Bentley
Add sha1 verification for mpdiffs
48
    def add_multiparent_record(self, mp_bytes, sha1, parents, repo_kind,
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
49
                               revision_id, file_id):
2520.4.60 by Aaron Bentley
Add sha1 verification for mpdiffs
50
        metadata = {'parents': parents,
51
                    'storage_kind': 'mpdiff',
52
                    'sha1': sha1}
53
        self._add_record(mp_bytes, metadata, repo_kind, revision_id, file_id)
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
54
55
    def add_fulltext_record(self, bytes, parents, repo_kind, revision_id,
56
                            file_id):
2520.4.60 by Aaron Bentley
Add sha1 verification for mpdiffs
57
        self._add_record(bytes, {'parents': parents,
2520.4.58 by Aaron Bentley
Propogate support for metadata to iter_revisions, add storage kind
58
            'storage_kind': 'fulltext'}, repo_kind, revision_id, file_id)
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
59
60
    @staticmethod
2520.4.68 by Aaron Bentley
Change name separators to all-slash
61
    def encode_name(content_kind, revision_id, file_id=None):
62
        assert content_kind in ('revision', 'file', 'inventory', 'testament',
2520.4.34 by Aaron Bentley
Add signature support
63
                             'signature')
2520.4.68 by Aaron Bentley
Change name separators to all-slash
64
        if content_kind in ('revision', 'inventory', 'testament', 'signature'):
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
65
            assert file_id is None
66
        else:
67
            assert file_id is not None
2520.4.68 by Aaron Bentley
Change name separators to all-slash
68
        names = [content_kind, revision_id]
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
69
        if file_id is not None:
2520.4.68 by Aaron Bentley
Change name separators to all-slash
70
            names.append(file_id)
71
        return '/'.join(names)
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
72
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
73
    def _add_record(self, bytes, metadata, repo_kind, revision_id, file_id):
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
74
        name = self.encode_name(repo_kind, revision_id, file_id)
2520.4.69 by Aaron Bentley
Simplify encoding by storing bodies in anonymous records
75
        metadata = bencode.bencode(metadata)
76
        self._container.add_bytes_record(metadata, [name])
77
        self._container.add_bytes_record(bytes, [])
2520.4.13 by Aaron Bentley
Use real container implementation
78
2520.4.7 by Aaron Bentley
Fix patch deserialization
79
2520.4.25 by Aaron Bentley
Rename ContainerWriter/ContainerReader to BundleWriter/BundleReader
80
class BundleReader(object):
2520.4.22 by Aaron Bentley
Create ContainerReader
81
2520.4.23 by Aaron Bentley
Move responsability for encoding into container objects
82
    def __init__(self, fileobj):
83
        line = fileobj.readline()
84
        if line != '\n':
85
            fileobj.readline()
2520.4.40 by Aaron Bentley
Add human-readable diff to bundles
86
        self.patch_lines = []
2520.4.26 by Aaron Bentley
Make decompression reasonably memory-efficient
87
        self._container = pack.ContainerReader(
2520.4.36 by Aaron Bentley
Speed up bundle reading, tweak help for bundle-info
88
            StringIO(fileobj.read().decode('base-64').decode('bz2')).read)
89
#            Have to use StringIO for perf, until ContainerReader fixed.
90
#            iterablefile.IterableFile(self.iter_decode(fileobj)).read)
2520.4.26 by Aaron Bentley
Make decompression reasonably memory-efficient
91
92
    @staticmethod
93
    def iter_decode(fileobj):
94
        decompressor = bz2.BZ2Decompressor()
95
        for line in fileobj:
96
            yield decompressor.decompress(line.decode('base-64'))
2520.4.22 by Aaron Bentley
Create ContainerReader
97
98
    @staticmethod
99
    def decode_name(name):
2520.4.68 by Aaron Bentley
Change name separators to all-slash
100
        names = name.split('/')
101
        content_kind, revision_id = names[:2]
102
        if len(names) > 2:
103
            file_id = names[2]
104
        else:
2520.4.22 by Aaron Bentley
Create ContainerReader
105
            file_id = None
2520.4.68 by Aaron Bentley
Change name separators to all-slash
106
        return content_kind, revision_id, file_id
2520.4.22 by Aaron Bentley
Create ContainerReader
107
108
    def iter_records(self):
2520.4.69 by Aaron Bentley
Simplify encoding by storing bodies in anonymous records
109
        iterator = self._container.iter_records()
110
        for (name,), meta_bytes in iterator:
111
            metadata = bencode.bdecode(meta_bytes(None))
112
            _unused, bytes = iterator.next()
113
            yield (bytes(None), metadata) + self.decode_name(name)
2520.4.22 by Aaron Bentley
Create ContainerReader
114
115
2520.4.72 by Aaron Bentley
Rename format to 4alpha
116
class BundleSerializerV4(serializer.BundleSerializer):
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
117
118
    def write(self, repository, revision_ids, forced_bases, fileobj):
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
119
        write_op = BundleWriteOperation.from_old_args(repository, revision_ids,
120
                                                      forced_bases, fileobj)
2520.4.53 by Aaron Bentley
refactor bundle serialization to make write_bundle primary
121
        return write_op.do_write()
122
123
    def write_bundle(self, repository, target, base, fileobj):
124
        write_op =  BundleWriteOperation(base, target, repository, fileobj)
125
        return write_op.do_write()
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
126
127
    def read(self, file):
2520.4.72 by Aaron Bentley
Rename format to 4alpha
128
        bundle = BundleInfoV4(file, self)
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
129
        return bundle
130
131
132
class BundleWriteOperation(object):
133
134
    @classmethod
135
    def from_old_args(cls, repository, revision_ids, forced_bases, fileobj):
136
        base, target = cls.get_base_target(revision_ids, forced_bases,
137
                                           repository)
138
        return BundleWriteOperation(base, target, repository, fileobj,
139
                                    revision_ids)
140
2520.4.53 by Aaron Bentley
refactor bundle serialization to make write_bundle primary
141
    def __init__(self, base, target, repository, fileobj, revision_ids=None):
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
142
        self.base = base
143
        self.target = target
144
        self.repository = repository
2520.4.39 by Aaron Bentley
Rename container => bundle(reader) where appropriate
145
        bundle = BundleWriter(fileobj)
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
146
        self.bundle = bundle
2520.4.64 by Aaron Bentley
Avoid topo sort for v10 bundles
147
        self.base_ancestry = set(repository.get_ancestry(base,
148
                                                         topo_sorted=False))
2520.4.53 by Aaron Bentley
refactor bundle serialization to make write_bundle primary
149
        if revision_ids is not None:
150
            self.revision_ids = revision_ids
151
        else:
2520.4.64 by Aaron Bentley
Avoid topo sort for v10 bundles
152
            revision_ids = set(repository.get_ancestry(target,
153
                                                       topo_sorted=False))
2520.4.55 by Aaron Bentley
Fix file revision selection to grab all dependencies properly
154
            self.revision_ids = revision_ids.difference(self.base_ancestry)
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
155
156
    def do_write(self):
157
        self.bundle.begin()
158
        self.write_files()
159
        self.write_revisions()
160
        self.write_testament()
161
        self.bundle.end()
2520.4.53 by Aaron Bentley
refactor bundle serialization to make write_bundle primary
162
        return self.revision_ids
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
163
2520.4.51 by Aaron Bentley
Split iteration through file revisions into a method, so we can vary it
164
    def iter_file_revisions(self):
165
        """This is the correct approach, but not compatible.
166
167
        It does not work with bzr.dev, because certain old revisions were not
2520.4.55 by Aaron Bentley
Fix file revision selection to grab all dependencies properly
168
        converted correctly, and have the wrong "revision" marker in
169
        inventories.
2520.4.51 by Aaron Bentley
Split iteration through file revisions into a method, so we can vary it
170
        """
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
171
        transaction = self.repository.get_transaction()
172
        altered = self.repository.fileids_altered_by_revision_ids(
173
            self.revision_ids)
2520.4.6 by Aaron Bentley
Get installation started
174
        for file_id, file_revision_ids in altered.iteritems():
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
175
            vf = self.repository.weave_store.get_weave(file_id, transaction)
2520.4.51 by Aaron Bentley
Split iteration through file revisions into a method, so we can vary it
176
            yield vf, file_id, file_revision_ids
177
2520.4.55 by Aaron Bentley
Fix file revision selection to grab all dependencies properly
178
    def iter_file_revisions_aggressive(self):
179
        """Ensure that all required revisions are fetched.
180
181
        This uses the standard iter_file_revisions to determine what revisions
182
        are referred to by inventories, but then uses the versionedfile to
183
        determine what the build-dependencies of each required revision.
184
185
        All build dependencies which are not ancestors of the base revision
186
        are emitted.
187
        """
188
        for vf, file_id, file_revision_ids in self.iter_file_revisions():
189
            new_revision_ids = set()
190
            pending = list(file_revision_ids)
191
            while len(pending) > 0:
192
                revision_id = pending.pop()
193
                if revision_id in new_revision_ids:
194
                    continue
195
                if revision_id in self.base_ancestry:
196
                    continue
197
                new_revision_ids.add(revision_id)
198
                pending.extend(vf.get_parents(revision_id))
199
            yield vf, file_id, new_revision_ids
200
2520.4.51 by Aaron Bentley
Split iteration through file revisions into a method, so we can vary it
201
    def write_files(self):
2520.4.55 by Aaron Bentley
Fix file revision selection to grab all dependencies properly
202
        for vf, file_id, revision_ids in self.iter_file_revisions_aggressive():
2520.4.51 by Aaron Bentley
Split iteration through file revisions into a method, so we can vary it
203
            self.add_mp_records('file', file_id, vf, revision_ids)
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
204
205
    def write_revisions(self):
206
        inv_vf = self.repository.get_inventory_weave()
207
        revision_order = list(multiparent.topo_iter(inv_vf, self.revision_ids))
208
        if self.target is not None:
209
            revision_order.remove(self.target)
210
            revision_order.append(self.target)
211
        self.add_mp_records('inventory', None, inv_vf, revision_order)
212
        for revision_id in revision_order:
213
            parents = self.repository.revision_parents(revision_id)
214
            revision_text = self.repository.get_revision_xml(revision_id)
215
            self.bundle.add_fulltext_record(revision_text, parents,
2520.4.39 by Aaron Bentley
Rename container => bundle(reader) where appropriate
216
                                       'revision', revision_id, None)
2520.4.34 by Aaron Bentley
Add signature support
217
            try:
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
218
                self.bundle.add_fulltext_record(
219
                    self.repository.get_signature_text(
2520.4.34 by Aaron Bentley
Add signature support
220
                    revision_id), parents, 'signature', revision_id, None)
221
            except errors.NoSuchRevision:
222
                pass
223
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
224
    def write_testament(self):
225
        if self.target is not None:
226
            t = _mod_testament.StrictTestament3.from_revision(self.repository,
227
                                                              self.target)
228
            self.bundle.add_fulltext_record(t.as_short_text(), [],
229
                                            'testament', '', None)
230
231
    @staticmethod
232
    def get_base_target(revision_ids, forced_bases, repository):
233
        if len(revision_ids) == 0:
234
            return None, None
235
        target = revision_ids[0]
236
        base = forced_bases.get(target)
237
        if base is None:
238
            parents = repository.get_revision(target).parent_ids
239
            if len(parents) == 0:
240
                base = _mod_revision.NULL_REVISION
241
            else:
242
                base = parents[0]
243
        return base, target
244
245
    def add_mp_records(self, repo_kind, file_id, vf, revision_ids):
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
246
        revision_ids = list(multiparent.topo_iter(vf, revision_ids))
247
        mpdiffs = vf.make_mpdiffs(revision_ids)
248
        for mpdiff, revision_id in zip(mpdiffs, revision_ids):
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
249
            parents = vf.get_parents(revision_id)
2520.4.60 by Aaron Bentley
Add sha1 verification for mpdiffs
250
            sha1 = vf.get_sha1(revision_id)
2520.4.41 by Aaron Bentley
Accelerate mpdiff generation
251
            text = ''.join(mpdiff.to_patch())
2520.4.60 by Aaron Bentley
Add sha1 verification for mpdiffs
252
            self.bundle.add_multiparent_record(text, sha1, parents, repo_kind,
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
253
                                               revision_id, file_id)
2520.4.6 by Aaron Bentley
Get installation started
254
255
2520.4.72 by Aaron Bentley
Rename format to 4alpha
256
class BundleInfoV4(object):
2520.4.6 by Aaron Bentley
Get installation started
257
258
    def __init__(self, fileobj, serializer):
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
259
        self._fileobj = fileobj
260
        self._serializer = serializer
261
        self.__real_revisions = None
262
        self.__revisions = None
263
264
    def install(self, repository):
265
        return self.install_revisions(repository)
266
267
    def install_revisions(self, repository):
2520.4.18 by Aaron Bentley
Generate mpdiffs for inventory
268
        repository.lock_write()
269
        try:
2520.4.35 by Aaron Bentley
zap obsolete changeset commands, add bundle-info command
270
            ri = RevisionInstaller(self.get_bundle_reader(),
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
271
                                   self._serializer, repository)
2520.4.18 by Aaron Bentley
Generate mpdiffs for inventory
272
            return ri.install()
273
        finally:
274
            repository.unlock()
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
275
2520.4.35 by Aaron Bentley
zap obsolete changeset commands, add bundle-info command
276
    def get_bundle_reader(self):
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
277
        self._fileobj.seek(0)
2520.4.25 by Aaron Bentley
Rename ContainerWriter/ContainerReader to BundleWriter/BundleReader
278
        return BundleReader(self._fileobj)
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
279
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
280
    def _get_real_revisions(self):
281
        from bzrlib import xml7
282
        if self.__real_revisions is None:
283
            self.__real_revisions = []
2520.4.39 by Aaron Bentley
Rename container => bundle(reader) where appropriate
284
            bundle_reader = self.get_bundle_reader()
2520.4.22 by Aaron Bentley
Create ContainerReader
285
            for bytes, parents, repo_kind, revision_id, file_id in \
2520.4.39 by Aaron Bentley
Rename container => bundle(reader) where appropriate
286
                bundle_reader.iter_records():
2520.4.22 by Aaron Bentley
Create ContainerReader
287
                if repo_kind == 'revision':
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
288
                    rev = xml7.serializer_v7.read_revision_from_string(bytes)
289
                    self.__real_revisions.append(rev)
290
        return self.__real_revisions
291
    real_revisions = property(_get_real_revisions)
292
293
    def _get_revisions(self):
294
        if self.__revisions is None:
295
            self.__revisions = []
296
            for revision in self.real_revisions:
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
297
                self.__revisions.append(
298
                    bundle_data.RevisionInfo.from_revision(revision))
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
299
        return self.__revisions
300
301
    revisions = property(_get_revisions)
302
2520.4.29 by Aaron Bentley
Reactivate some testing, fix topo_iter
303
    def _get_target(self):
304
        return self.revisions[-1].revision_id
305
306
    target = property(_get_target)
307
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
308
309
class RevisionInstaller(object):
310
2520.4.21 by Aaron Bentley
Finish turning ContainerWriter into a new layer
311
    def __init__(self, container, serializer, repository):
312
        self._container = container
2520.4.6 by Aaron Bentley
Get installation started
313
        self._serializer = serializer
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
314
        self._repository = repository
2520.4.6 by Aaron Bentley
Get installation started
315
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
316
    def install(self):
2520.4.6 by Aaron Bentley
Get installation started
317
        current_file = None
318
        current_versionedfile = None
319
        pending_file_records = []
2520.4.8 by Aaron Bentley
Serialize inventory
320
        added_inv = set()
2520.4.29 by Aaron Bentley
Reactivate some testing, fix topo_iter
321
        target_revision = None
2520.4.58 by Aaron Bentley
Propogate support for metadata to iter_revisions, add storage kind
322
        for bytes, metadata, repo_kind, revision_id, file_id in\
2520.4.22 by Aaron Bentley
Create ContainerReader
323
            self._container.iter_records():
2520.4.34 by Aaron Bentley
Add signature support
324
            if repo_kind == 'testament':
325
                testament = bytes
2520.4.22 by Aaron Bentley
Create ContainerReader
326
            if  repo_kind != 'file':
2520.4.18 by Aaron Bentley
Generate mpdiffs for inventory
327
                self._install_mp_records(current_versionedfile,
2520.4.6 by Aaron Bentley
Get installation started
328
                    pending_file_records)
2520.4.8 by Aaron Bentley
Serialize inventory
329
                current_file = None
330
                current_versionedfile = None
331
                pending_file_records = []
2520.4.22 by Aaron Bentley
Create ContainerReader
332
                if repo_kind == 'inventory':
2520.4.59 by Aaron Bentley
Push metadata down the stack
333
                    self._install_inventory(revision_id, metadata, bytes)
2520.4.22 by Aaron Bentley
Create ContainerReader
334
                if repo_kind == 'revision':
2520.4.28 by Aaron Bentley
Force revisions to be topologically sorted
335
                    target_revision = revision_id
2520.4.59 by Aaron Bentley
Push metadata down the stack
336
                    self._install_revision(revision_id, metadata, bytes)
2520.4.34 by Aaron Bentley
Add signature support
337
                if repo_kind == 'signature':
2520.4.59 by Aaron Bentley
Push metadata down the stack
338
                    self._install_signature(revision_id, metadata, bytes)
2520.4.22 by Aaron Bentley
Create ContainerReader
339
            if repo_kind == 'file':
2520.4.6 by Aaron Bentley
Get installation started
340
                if file_id != current_file:
2520.4.18 by Aaron Bentley
Generate mpdiffs for inventory
341
                    self._install_mp_records(current_versionedfile,
2520.4.6 by Aaron Bentley
Get installation started
342
                        pending_file_records)
343
                    current_file = file_id
344
                    current_versionedfile = \
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
345
                        self._repository.weave_store.get_weave_or_empty(
346
                        file_id, self._repository.get_transaction())
2520.4.6 by Aaron Bentley
Get installation started
347
                    pending_file_records = []
348
                if revision_id in current_versionedfile:
349
                    continue
2520.4.59 by Aaron Bentley
Push metadata down the stack
350
                pending_file_records.append((revision_id, metadata, bytes))
2520.4.18 by Aaron Bentley
Generate mpdiffs for inventory
351
        self._install_mp_records(current_versionedfile, pending_file_records)
2520.4.34 by Aaron Bentley
Add signature support
352
        if target_revision is not None:
353
            self._check_testament(target_revision, testament)
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
354
        return target_revision
2520.4.6 by Aaron Bentley
Get installation started
355
2520.4.34 by Aaron Bentley
Add signature support
356
    def _check_testament(self, target_revision, testament):
357
        t = _mod_testament.StrictTestament3.from_revision(self._repository,
358
                                                          target_revision)
359
        if testament != t.as_short_text():
2520.4.50 by Aaron Bentley
Split write functionality out into a separate object
360
            raise errors.TestamentMismatch(target_revision, testament,
361
                                           t.as_short_text())
2520.4.34 by Aaron Bentley
Add signature support
362
2520.4.60 by Aaron Bentley
Add sha1 verification for mpdiffs
363
    def _install_mp_records(self, versionedfile, records):
2520.4.61 by Aaron Bentley
Do bulk insertion of records
364
        if len(records) == 0:
365
            return
366
        d_func = multiparent.MultiParent.from_patch
367
        vf_records = [(r, m['parents'], m['sha1'], d_func(t)) for r, m, t in
368
                      records if r not in versionedfile]
369
        versionedfile.add_mpdiffs(vf_records)
2520.4.8 by Aaron Bentley
Serialize inventory
370
2520.4.59 by Aaron Bentley
Push metadata down the stack
371
    def _install_inventory(self, revision_id, metadata, text):
2520.4.18 by Aaron Bentley
Generate mpdiffs for inventory
372
        vf = self._repository.get_inventory_weave()
2520.4.59 by Aaron Bentley
Push metadata down the stack
373
        return self._install_mp_records(vf, [(revision_id, metadata, text)])
2520.4.10 by Aaron Bentley
Enable installation of revisions
374
2520.4.59 by Aaron Bentley
Push metadata down the stack
375
    def _install_revision(self, revision_id, metadata, text):
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
376
        if self._repository.has_revision(revision_id):
377
            return
378
        self._repository._add_revision_text(revision_id, text)
2520.4.34 by Aaron Bentley
Add signature support
379
2520.4.59 by Aaron Bentley
Push metadata down the stack
380
    def _install_signature(self, revision_id, metadata, text):
2520.4.34 by Aaron Bentley
Add signature support
381
        self._repository._revision_store.add_revision_signature_text(
382
            revision_id, text, self._repository.get_transaction())