/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Martin Pool
  • Date: 2006-01-13 06:38:56 UTC
  • mto: (1185.65.28 storage)
  • mto: This revision was merged to the branch mainline in revision 1550.
  • Revision ID: mbp@sourcefrog.net-20060113063856-484eed116191727b
Pass through wrapped function name and docstrign 
in needs_read_lock and needs_write_lock decorators.  Test this works.
(Suggestion from John)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 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
from cStringIO import StringIO
 
18
 
 
19
from bzrlib.lockable_files import LockableFiles
 
20
from bzrlib.tree import EmptyTree
 
21
from bzrlib.revision import NULL_REVISION
 
22
from bzrlib.store import copy_all
 
23
from bzrlib.store.weave import WeaveStore
 
24
from bzrlib.store.text import TextStore
 
25
import bzrlib.xml5
 
26
from bzrlib.tree import RevisionTree
 
27
from bzrlib.errors import InvalidRevisionId
 
28
from bzrlib.testament import Testament
 
29
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
30
 
 
31
 
 
32
 
 
33
class Repository(object):
 
34
    """Repository holding history for one or more branches.
 
35
 
 
36
    The repository holds and retrieves historical information including
 
37
    revisions and file history.  It's normally accessed only by the Branch,
 
38
    which views a particular line of development through that history.
 
39
 
 
40
    The Repository builds on top of Stores and a Transport, which respectively 
 
41
    describe the disk data format and the way of accessing the (possibly 
 
42
    remote) disk.
 
43
    """
 
44
 
 
45
    def __init__(self, transport, branch_format):
 
46
        object.__init__(self)
 
47
        self.control_files = LockableFiles(transport.clone(bzrlib.BZRDIR), 'README')
 
48
 
 
49
        dir_mode = self.control_files._dir_mode
 
50
        file_mode = self.control_files._file_mode
 
51
 
 
52
        def get_weave(name, prefixed=False):
 
53
            if name:
 
54
                name = bzrlib.BZRDIR + '/' + unicode(name)
 
55
            else:
 
56
                name = bzrlib.BZRDIR
 
57
            relpath = self.control_files._escape(name)
 
58
            weave_transport = transport.clone(relpath)
 
59
            ws = WeaveStore(weave_transport, prefixed=prefixed,
 
60
                            dir_mode=dir_mode,
 
61
                            file_mode=file_mode)
 
62
            if self.control_files._transport.should_cache():
 
63
                ws.enable_cache = True
 
64
            return ws
 
65
 
 
66
        def get_store(name, compressed=True, prefixed=False):
 
67
            # FIXME: This approach of assuming stores are all entirely compressed
 
68
            # or entirely uncompressed is tidy, but breaks upgrade from 
 
69
            # some existing branches where there's a mixture; we probably 
 
70
            # still want the option to look for both.
 
71
            if name:
 
72
                name = bzrlib.BZRDIR + '/' + unicode(name)
 
73
            else:
 
74
                name = bzrlib.BZRDIR
 
75
            relpath = self.control_files._escape(name)
 
76
            store = TextStore(transport.clone(relpath),
 
77
                              prefixed=prefixed, compressed=compressed,
 
78
                              dir_mode=dir_mode,
 
79
                              file_mode=file_mode)
 
80
            #if self._transport.should_cache():
 
81
            #    cache_path = os.path.join(self.cache_root, name)
 
82
            #    os.mkdir(cache_path)
 
83
            #    store = bzrlib.store.CachedStore(store, cache_path)
 
84
            return store
 
85
 
 
86
        if branch_format == 4:
 
87
            self.inventory_store = get_store('inventory-store')
 
88
            self.text_store = get_store('text-store')
 
89
            self.revision_store = get_store('revision-store')
 
90
        elif branch_format == 5:
 
91
            self.control_weaves = get_weave('')
 
92
            self.weave_store = get_weave('weaves')
 
93
            self.revision_store = get_store('revision-store', compressed=False)
 
94
        elif branch_format == 6:
 
95
            self.control_weaves = get_weave('')
 
96
            self.weave_store = get_weave('weaves', prefixed=True)
 
97
            self.revision_store = get_store('revision-store', compressed=False,
 
98
                                            prefixed=True)
 
99
        self.revision_store.register_suffix('sig')
 
100
 
 
101
    def lock_write(self):
 
102
        self.control_files.lock_write()
 
103
 
 
104
    def lock_read(self):
 
105
        self.control_files.lock_read()
 
106
 
 
107
    def unlock(self):
 
108
        self.control_files.unlock()
 
109
 
 
110
    def copy(self, destination):
 
111
        destination.control_weaves.copy_multi(self.control_weaves, 
 
112
                ['inventory'])
 
113
        copy_all(self.weave_store, destination.weave_store)
 
114
        copy_all(self.revision_store, destination.revision_store)
 
115
 
 
116
    def has_revision(self, revision_id):
 
117
        """True if this branch has a copy of the revision.
 
118
 
 
119
        This does not necessarily imply the revision is merge
 
120
        or on the mainline."""
 
121
        return (revision_id is None
 
122
                or self.revision_store.has_id(revision_id))
 
123
 
 
124
    @needs_read_lock
 
125
    def get_revision_xml_file(self, revision_id):
 
126
        """Return XML file object for revision object."""
 
127
        if not revision_id or not isinstance(revision_id, basestring):
 
128
            raise InvalidRevisionId(revision_id=revision_id, branch=self)
 
129
        try:
 
130
            return self.revision_store.get(revision_id)
 
131
        except (IndexError, KeyError):
 
132
            raise bzrlib.errors.NoSuchRevision(self, revision_id)
 
133
 
 
134
    def get_revision_xml(self, revision_id):
 
135
        return self.get_revision_xml_file(revision_id).read()
 
136
 
 
137
    def get_revision(self, revision_id):
 
138
        """Return the Revision object for a named revision"""
 
139
        xml_file = self.get_revision_xml_file(revision_id)
 
140
 
 
141
        try:
 
142
            r = bzrlib.xml5.serializer_v5.read_revision(xml_file)
 
143
        except SyntaxError, e:
 
144
            raise bzrlib.errors.BzrError('failed to unpack revision_xml',
 
145
                                         [revision_id,
 
146
                                          str(e)])
 
147
            
 
148
        assert r.revision_id == revision_id
 
149
        return r
 
150
 
 
151
    def get_revision_sha1(self, revision_id):
 
152
        """Hash the stored value of a revision, and return it."""
 
153
        # In the future, revision entries will be signed. At that
 
154
        # point, it is probably best *not* to include the signature
 
155
        # in the revision hash. Because that lets you re-sign
 
156
        # the revision, (add signatures/remove signatures) and still
 
157
        # have all hash pointers stay consistent.
 
158
        # But for now, just hash the contents.
 
159
        return bzrlib.osutils.sha_file(self.get_revision_xml_file(revision_id))
 
160
 
 
161
    @needs_write_lock
 
162
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
 
163
        self.revision_store.add(StringIO(gpg_strategy.sign(plaintext)), 
 
164
                                revision_id, "sig")
 
165
 
 
166
    def get_inventory_weave(self):
 
167
        return self.control_weaves.get_weave('inventory',
 
168
            self.get_transaction())
 
169
 
 
170
    def get_inventory(self, revision_id):
 
171
        """Get Inventory object by hash."""
 
172
        xml = self.get_inventory_xml(revision_id)
 
173
        return bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
 
174
 
 
175
    def get_inventory_xml(self, revision_id):
 
176
        """Get inventory XML as a file object."""
 
177
        try:
 
178
            assert isinstance(revision_id, basestring), type(revision_id)
 
179
            iw = self.get_inventory_weave()
 
180
            return iw.get_text(iw.lookup(revision_id))
 
181
        except IndexError:
 
182
            raise bzrlib.errors.HistoryMissing(self, 'inventory', revision_id)
 
183
 
 
184
    def get_inventory_sha1(self, revision_id):
 
185
        """Return the sha1 hash of the inventory entry
 
186
        """
 
187
        return self.get_revision(revision_id).inventory_sha1
 
188
 
 
189
    def get_revision_inventory(self, revision_id):
 
190
        """Return inventory of a past revision."""
 
191
        # TODO: Unify this with get_inventory()
 
192
        # bzr 0.0.6 and later imposes the constraint that the inventory_id
 
193
        # must be the same as its revision, so this is trivial.
 
194
        if revision_id == None:
 
195
            # This does not make sense: if there is no revision,
 
196
            # then it is the current tree inventory surely ?!
 
197
            # and thus get_root_id() is something that looks at the last
 
198
            # commit on the branch, and the get_root_id is an inventory check.
 
199
            raise NotImplementedError
 
200
            # return Inventory(self.get_root_id())
 
201
        else:
 
202
            return self.get_inventory(revision_id)
 
203
 
 
204
    def revision_tree(self, revision_id):
 
205
        """Return Tree for a revision on this branch.
 
206
 
 
207
        `revision_id` may be None for the null revision, in which case
 
208
        an `EmptyTree` is returned."""
 
209
        # TODO: refactor this to use an existing revision object
 
210
        # so we don't need to read it in twice.
 
211
        if revision_id == None or revision_id == NULL_REVISION:
 
212
            return EmptyTree()
 
213
        else:
 
214
            inv = self.get_revision_inventory(revision_id)
 
215
            return RevisionTree(self, inv, revision_id)
 
216
 
 
217
    def get_ancestry(self, revision_id):
 
218
        """Return a list of revision-ids integrated by a revision.
 
219
        
 
220
        This is topologically sorted.
 
221
        """
 
222
        if revision_id is None:
 
223
            return [None]
 
224
        w = self.get_inventory_weave()
 
225
        return [None] + map(w.idx_to_name,
 
226
                            w.inclusions([w.lookup(revision_id)]))
 
227
 
 
228
    @needs_read_lock
 
229
    def print_file(self, file, revision_id):
 
230
        """Print `file` to stdout."""
 
231
        tree = self.revision_tree(revision_id)
 
232
        # use inventory as it was in that revision
 
233
        file_id = tree.inventory.path2id(file)
 
234
        if not file_id:
 
235
            raise BzrError("%r is not present in revision %s" % (file, revno))
 
236
            try:
 
237
                revno = self.revision_id_to_revno(revision_id)
 
238
            except errors.NoSuchRevision:
 
239
                # TODO: This should not be BzrError,
 
240
                # but NoSuchFile doesn't fit either
 
241
                raise BzrError('%r is not present in revision %s' 
 
242
                                % (file, revision_id))
 
243
            else:
 
244
                raise BzrError('%r is not present in revision %s'
 
245
                                % (file, revno))
 
246
        tree.print_file(file_id)
 
247
 
 
248
    def get_transaction(self):
 
249
        return self.control_files.get_transaction()
 
250
 
 
251
    def sign_revision(self, revision_id, gpg_strategy):
 
252
        plaintext = Testament.from_revision(self, revision_id).as_short_text()
 
253
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)