/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.17 by Robert Collins
Merge from integration, mode-changes are broken.
54
55
    def __init__(self, transport, branch_format, 
56
                 dir_mode=None, file_mode=None):
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
57
        object.__init__(self)
1185.67.13 by Aaron Bentley
Moved the .bzr constraint out of LockableFiles
58
        self.control_files = LockableFiles(transport, bzrlib.BZRDIR, 'README')
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
59
        def get_weave(name, prefixed=False):
1185.67.1 by Aaron Bentley
Merged the mainline
60
            relpath = self.control_files._rel_controlfilename(unicode(name))
1185.67.12 by Aaron Bentley
Removed LockableFiles.make_transport
61
            weave_transport = transport.clone(relpath)
1185.65.17 by Robert Collins
Merge from integration, mode-changes are broken.
62
            ws = WeaveStore(weave_transport, prefixed=prefixed,
63
                            dir_mode=dir_mode,
64
                            file_mode=file_mode)
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
65
            if self.control_files._transport.should_cache():
66
                ws.enable_cache = True
67
            return ws
68
69
        def get_store(name, compressed=True, prefixed=False):
70
            # FIXME: This approach of assuming stores are all entirely compressed
71
            # or entirely uncompressed is tidy, but breaks upgrade from 
72
            # some existing branches where there's a mixture; we probably 
73
            # still want the option to look for both.
1185.65.15 by Robert Collins
Merge from integration.
74
            name = unicode(name)
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
75
            relpath = self.control_files._rel_controlfilename(name)
1185.67.12 by Aaron Bentley
Removed LockableFiles.make_transport
76
            store = TextStore(transport.clone(relpath),
1185.65.17 by Robert Collins
Merge from integration, mode-changes are broken.
77
                              prefixed=prefixed, compressed=compressed,
78
                              dir_mode=dir_mode,
79
                              file_mode=file_mode)
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
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
1185.66.8 by Aaron Bentley
Applied Jelmer's patch to make clone a branch operation
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
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
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)
1185.65.17 by Robert Collins
Merge from integration, mode-changes are broken.
215
            return RevisionTree(self, inv, revision_id)
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
216
1185.66.2 by Aaron Bentley
Moved get_ancestry to RevisionStorage
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
1185.65.4 by Aaron Bentley
Fixed cat command
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))
1185.65.15 by Robert Collins
Merge from integration.
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))
1185.65.4 by Aaron Bentley
Fixed cat command
246
        tree.print_file(file_id)
247
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
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)