~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/serializer/v4.py

  • Committer: Ian Clatworthy
  • Date: 2009-09-09 15:30:59 UTC
  • mto: (4634.37.2 prepare-2.0)
  • mto: This revision was merged to the branch mainline in revision 4689.
  • Revision ID: ian.clatworthy@canonical.com-20090909153059-sb038agvd38ci2q8
more link fixes in the User Guide

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
17
from cStringIO import StringIO
20
18
import bz2
21
19
import re
22
20
 
23
21
from bzrlib import (
 
22
    diff,
24
23
    errors,
25
24
    iterablefile,
26
25
    lru_cache,
31
30
    serializer,
32
31
    trace,
33
32
    ui,
34
 
    versionedfile as _mod_versionedfile,
35
33
    )
36
34
from bzrlib.bundle import bundle_data, serializer as bundle_serializer
37
 
from bzrlib.i18n import ngettext
38
35
from bzrlib import bencode
39
36
 
40
37
 
41
 
class _MPDiffInventoryGenerator(_mod_versionedfile._MPDiffGenerator):
42
 
    """Generate Inventory diffs serialized inventories."""
43
 
 
44
 
    def __init__(self, repo, inventory_keys):
45
 
        super(_MPDiffInventoryGenerator, self).__init__(repo.inventories,
46
 
            inventory_keys)
47
 
        self.repo = repo
48
 
        self.sha1s = {}
49
 
 
50
 
    def iter_diffs(self):
51
 
        """Compute the diffs one at a time."""
52
 
        # This is instead of compute_diffs() since we guarantee our ordering of
53
 
        # inventories, we don't have to do any buffering
54
 
        self._find_needed_keys()
55
 
        # We actually use a slightly different ordering. We grab all of the
56
 
        # parents first, and then grab the ordered requests.
57
 
        needed_ids = [k[-1] for k in self.present_parents]
58
 
        needed_ids.extend([k[-1] for k in self.ordered_keys])
59
 
        inv_to_str = self.repo._serializer.write_inventory_to_string
60
 
        for inv in self.repo.iter_inventories(needed_ids):
61
 
            revision_id = inv.revision_id
62
 
            key = (revision_id,)
63
 
            if key in self.present_parents:
64
 
                # Not a key we will transmit, which is a shame, since because
65
 
                # of that bundles don't work with stacked branches
66
 
                parent_ids = None
67
 
            else:
68
 
                parent_ids = [k[-1] for k in self.parent_map[key]]
69
 
            as_bytes = inv_to_str(inv)
70
 
            self._process_one_record(key, (as_bytes,))
71
 
            if parent_ids is None:
72
 
                continue
73
 
            diff = self.diffs.pop(key)
74
 
            sha1 = osutils.sha_string(as_bytes)
75
 
            yield revision_id, parent_ids, sha1, diff
76
 
 
77
 
 
78
38
class BundleWriter(object):
79
39
    """Writer for bundle-format files.
80
40
 
324
284
 
325
285
    def do_write(self):
326
286
        """Write all data to the bundle"""
327
 
        trace.note(ngettext('Bundling %d revision.', 'Bundling %d revisions.',
328
 
                            len(self.revision_ids)), len(self.revision_ids))
 
287
        trace.note('Bundling %d revision(s).', len(self.revision_ids))
329
288
        self.repository.lock_read()
330
289
        try:
331
290
            self.bundle.begin()
389
348
        the other side.
390
349
        """
391
350
        inventory_key_order = [(r,) for r in revision_order]
392
 
        generator = _MPDiffInventoryGenerator(self.repository,
393
 
                                              inventory_key_order)
394
 
        for revision_id, parent_ids, sha1, diff in generator.iter_diffs():
 
351
        parent_map = self.repository.inventories.get_parent_map(
 
352
                            inventory_key_order)
 
353
        missing_keys = set(inventory_key_order).difference(parent_map)
 
354
        if missing_keys:
 
355
            raise errors.RevisionNotPresent(list(missing_keys)[0],
 
356
                                            self.repository.inventories)
 
357
        inv_to_str = self.repository._serializer.write_inventory_to_string
 
358
        # Make sure that we grab the parent texts first
 
359
        just_parents = set()
 
360
        map(just_parents.update, parent_map.itervalues())
 
361
        just_parents.difference_update(parent_map)
 
362
        # Ignore ghost parents
 
363
        present_parents = self.repository.inventories.get_parent_map(
 
364
                            just_parents)
 
365
        ghost_keys = just_parents.difference(present_parents)
 
366
        needed_inventories = list(present_parents) + inventory_key_order
 
367
        needed_inventories = [k[-1] for k in needed_inventories]
 
368
        all_lines = {}
 
369
        for inv in self.repository.iter_inventories(needed_inventories):
 
370
            revision_id = inv.revision_id
 
371
            key = (revision_id,)
 
372
            as_bytes = inv_to_str(inv)
 
373
            # The sha1 is validated as the xml/textual form, not as the
 
374
            # form-in-the-repository
 
375
            sha1 = osutils.sha_string(as_bytes)
 
376
            as_lines = osutils.split_lines(as_bytes)
 
377
            del as_bytes
 
378
            all_lines[key] = as_lines
 
379
            if key in just_parents:
 
380
                # We don't transmit those entries
 
381
                continue
 
382
            # Create an mpdiff for this text, and add it to the output
 
383
            parent_keys = parent_map[key]
 
384
            # See the comment in VF.make_mpdiffs about how this effects
 
385
            # ordering when there are ghosts present. I think we have a latent
 
386
            # bug
 
387
            parent_lines = [all_lines[p_key] for p_key in parent_keys
 
388
                            if p_key not in ghost_keys]
 
389
            diff = multiparent.MultiParent.from_lines(
 
390
                as_lines, parent_lines)
395
391
            text = ''.join(diff.to_patch())
 
392
            parent_ids = [k[-1] for k in parent_keys]
396
393
            self.bundle.add_multiparent_record(text, sha1, parent_ids,
397
394
                                               'inventory', revision_id, None)
398
395