/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.64.5 by Ian Clatworthy
first cut at generic processing method
1
# Copyright (C) 2008 Canonical Ltd
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
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Parameterised loading of revisions into a repository."""
18
19
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
20
from bzrlib import errors, lru_cache
21
from bzrlib import revision as _mod_revision
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
22
23
0.64.5 by Ian Clatworthy
first cut at generic processing method
24
class RevisionLoader(object):
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
25
    # NOTE: This is effectively bzrlib.repository._install_revision
26
    # refactored to be a class. When importing, we want more flexibility
27
    # in how previous revisions are cached, data is feed in, etc.
0.64.5 by Ian Clatworthy
first cut at generic processing method
28
29
    def __init__(self, repo, inventories_provider=None):
30
        """An object responsible for loading revisions into a repository.
31
32
        NOTE: Repository locking is not managed by this class. Clients
33
        should take a write lock, call load() multiple times, then release
34
        the lock.
35
36
        :param repository: the target repository
37
        :param inventories_provider: a callable expecting a repository and
38
            a list of revision-ids, that returns:
39
              * the list of revision-ids present in the repository
40
              * the list of inventories for the revision-id's,
41
                including an empty inventory for the missing revisions
42
            If None, a default implementation is provided.
43
        """
44
        self.repo = repo
45
        if inventories_provider is not None:
46
            self.inventories_provider = inventories_provider
47
        else:
48
            self.inventories_provider = self._default_inventories_provider
49
50
    def load(self, rev, inv, signature, text_provider):
51
        """Load a revision into a repository.
52
53
        :param rev: the Revision
54
        :param inv: the inventory
55
        :param signature: signing information
56
        :param text_provider: a callable expecting a file_id parameter
57
            that returns the text for that file-id
58
        """
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
59
        present_parents, parent_invs = self.inventories_provider(
0.64.5 by Ian Clatworthy
first cut at generic processing method
60
            rev.parent_ids)
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
61
        self._load_texts(rev.revision_id, inv.iter_entries(), parent_invs,
0.64.5 by Ian Clatworthy
first cut at generic processing method
62
            text_provider)
63
        try:
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
64
            rev.inventory_sha1 = self._add_inventory(rev.revision_id,
0.64.6 by Ian Clatworthy
generic processing method working for one revision in one branch
65
                inv, present_parents)
0.64.5 by Ian Clatworthy
first cut at generic processing method
66
        except errors.RevisionAlreadyPresent:
67
            pass
68
        if signature is not None:
69
            self.repo.add_signature_text(rev.revision_id, signature)
70
        self.repo.add_revision(rev.revision_id, rev, inv)
71
72
    def _load_texts(self, revision_id, entries, parent_invs, text_provider):
73
        """Load texts to a repository for inventory entries.
74
        
75
        This method is provided for subclasses to use or override.
76
77
        :param revision_id: the revision identifier
78
        :param entries: iterator over the inventory entries
79
        :param parent_inv: the parent inventories
80
        :param text_provider: a callable expecting a file_id parameter
81
            that returns the text for that file-id
82
        """
83
84
        # Backwards compatibility hack: skip the root id.
85
        if not self.repo.supports_rich_root():
86
            path, root = entries.next()
87
            if root.revision != revision_id:
88
                raise errors.IncompatibleRevision(repr(self.repo))
89
        # Add the texts that are not already present
0.64.27 by Ian Clatworthy
1st cut at performance tuning
90
        tx = self.repo.get_transaction()
0.64.5 by Ian Clatworthy
first cut at generic processing method
91
        for path, ie in entries:
0.64.27 by Ian Clatworthy
1st cut at performance tuning
92
            # This test is *really* slow: over 50% of import time
93
            #w = self.repo.weave_store.get_weave_or_empty(ie.file_id, tx)
94
            #if ie.revision in w:
95
            #    continue
0.64.29 by Ian Clatworthy
improve explanation of faster check in revisionloader
96
            # Try another way, realising that this assumes that the
97
            # version is not already there. In the general case,
98
            # a shared repository might already have the revision but
99
            # we arguably don't need that check when importing from
100
            # a foreign system.
0.64.27 by Ian Clatworthy
1st cut at performance tuning
101
            if ie.revision != revision_id:
102
                continue
103
            text_parents = []
104
            for parent_inv in parent_invs:
105
                if ie.file_id not in parent_inv:
106
                    continue
107
                parent_id = parent_inv[ie.file_id].revision
108
                if parent_id in text_parents:
109
                    continue
110
                text_parents.append(parent_id)
111
            vfile = self.repo.weave_store.get_weave_or_empty(ie.file_id,  tx)
112
            lines = text_provider(ie.file_id)
113
            vfile.add_lines(revision_id, text_parents, lines)
0.64.5 by Ian Clatworthy
first cut at generic processing method
114
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
115
    def _add_inventory(self, revision_id, inv, parents):
116
        """Add the inventory inv to the repository as revision_id.
117
        
118
        :param parents: The revision ids of the parents that revision_id
119
                        is known to have and are in the repository already.
120
121
        :returns: The validator(which is a sha1 digest, though what is sha'd is
122
            repository format specific) of the serialized inventory.
123
        """
124
        return self.repo.add_inventory(revision_id, inv, parents)
125
0.64.5 by Ian Clatworthy
first cut at generic processing method
126
    def _default_inventories_provider(self, revision_ids):
127
        """An inventories provider that queries the repository."""
128
        present = []
129
        inventories = []
130
        for revision_id in revision_ids:
131
            if self.repo.has_revision(revision_id):
132
                present.append(revision_id)
133
                rev_tree = self.repo.revision_tree(revision_id)
134
            else:
135
                rev_tree = self.repo.revision_tree(None)
136
            inventories.append(rev_tree.inventory)
137
        return present, inventories
0.64.44 by Ian Clatworthy
smart caching of serialised inventories
138
139
140
class ImportRevisionLoader(RevisionLoader):
141
    """A RevisionLoader optimised for importing.
142
        
143
    This implementation allows caching of the serialised inventory texts.
144
    """
145
146
    def __init__(self, repo, inventories_provider=None, inv_parent_texts=None):
147
        """See RevisionLoader.__init__."""
148
        RevisionLoader.__init__(self, repo, inventories_provider)
149
        if inv_parent_texts is not None:
150
            self.inv_parent_texts = inv_parent_texts
151
        else:
152
            self.inv_parent_texts = {}
153
154
    def _add_inventory(self, revision_id, inv, parents):
155
        """See RevisionLoader._add_inventory."""
156
        # Code taken from bzrlib.repository.add_inventory
157
        assert self.repo.is_in_write_group()
158
        _mod_revision.check_not_reserved_id(revision_id)
159
        assert inv.revision_id is None or inv.revision_id == revision_id, \
160
            "Mismatch between inventory revision" \
161
            " id and insertion revid (%r, %r)" % (inv.revision_id, revision_id)
162
        assert inv.root is not None
163
        inv_lines = self.repo._serialise_inventory_to_lines(inv)
164
        inv_vf = self.repo.get_inventory_weave()
165
166
        # Code taken from bzrlib.repository._inventory_add_lines
167
        final_parents = []
168
        for parent in parents:
169
            if parent in inv_vf:
170
                final_parents.append(parent)
171
        sha1, num_bytes, parent_text = inv_vf.add_lines(revision_id,
172
            final_parents, inv_lines, self.inv_parent_texts,
173
            check_content=False)
174
        self.inv_parent_texts[revision_id] = parent_text
175
        return sha1