/brz/remove-bazaar

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