/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/remote.py

Implement a remote Repository.has_revision method.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006 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
# TODO: At some point, handle upgrades by just passing the whole request
 
18
# across to run on the server.
 
19
 
 
20
from urlparse import urlparse
 
21
 
 
22
from bzrlib import branch, errors, repository
 
23
from bzrlib.bzrdir import BzrDir, BzrDirFormat, RemoteBzrDirFormat
 
24
from bzrlib.branch import BranchReferenceFormat
 
25
from bzrlib.smart import client, vfs
 
26
from bzrlib.urlutils import unescape
 
27
 
 
28
# Note: RemoteBzrDirFormat is in bzrdir.py
 
29
 
 
30
class RemoteBzrDir(BzrDir):
 
31
    """Control directory on a remote server, accessed by HPSS."""
 
32
 
 
33
    def __init__(self, transport):
 
34
        BzrDir.__init__(self, transport, RemoteBzrDirFormat())
 
35
        self.client = transport.get_smart_client()
 
36
        # this object holds a delegated bzrdir that uses file-level operations
 
37
        # to talk to the other side
 
38
        # XXX: We should go into find_format, but not allow it to find
 
39
        # RemoteBzrDirFormat and make sure it finds the real underlying format.
 
40
        
 
41
        # THIS IS A COMPLETE AND UTTER LIE.
 
42
        # XXX: XXX: XXX: must be removed before merging to mainline
 
43
        # SMART_SERVER_MERGE_BLOCKER
 
44
        default_format = BzrDirFormat.get_default_format()
 
45
        self._real_bzrdir = default_format.open(transport, _found=True)
 
46
        path = self._path_for_remote_call()
 
47
        #self._real_bzrdir._format.probe_transport(transport)
 
48
        response = client.SmartClient(self.client).call('probe_dont_use', path)
 
49
        if response == ('no',):
 
50
            raise errors.NotBranchError(path=transport.base)
 
51
        self._branch = None
 
52
 
 
53
    def create_repository(self, shared=False):
 
54
        return RemoteRepository(
 
55
            self, self._real_bzrdir.create_repository(shared=shared))
 
56
 
 
57
    def create_branch(self):
 
58
        real_branch = self._real_bzrdir.create_branch()
 
59
        real_repository = real_branch.repository
 
60
        remote_repository = RemoteRepository(self, real_repository)
 
61
        return RemoteBranch(self, remote_repository, real_branch)
 
62
 
 
63
    def create_workingtree(self, revision_id=None):
 
64
        real_workingtree = self._real_bzrdir.create_workingtree(revision_id=revision_id)
 
65
        return RemoteWorkingTree(self, real_workingtree)
 
66
 
 
67
    def open_branch(self, _unsupported=False):
 
68
        assert _unsupported == False, 'unsupported flag support not implemented yet.'
 
69
        path = self._path_for_remote_call()
 
70
        response = client.SmartClient(self.client).call('BzrDir.open_branch', path)
 
71
        assert response[0] == 'ok', 'unexpected response code %s' % response[0]
 
72
        if response[0] != 'ok':
 
73
            # this should probably be a regular translate no ?
 
74
            raise errors.NotBranchError(path=self.root_transport.base)
 
75
        if response[1] == '':
 
76
            # branch at this location.
 
77
            if vfs.vfs_enabled():
 
78
                # if the VFS is enabled, create a local object using the VFS.
 
79
                real_branch = self._real_bzrdir.open_branch(unsupported=_unsupported)
 
80
                # This branch accessed through the smart server, so wrap the
 
81
                # file-level objects.
 
82
                real_repository = real_branch.repository
 
83
                remote_repository = RemoteRepository(self, real_repository)
 
84
                return RemoteBranch(self, remote_repository, real_branch)
 
85
            else:
 
86
                # otherwise just create a proxy for the branch.
 
87
                return RemoteBranch(self, self.find_repository())
 
88
        else:
 
89
            # a branch reference, use the existing BranchReference logic.
 
90
            format = BranchReferenceFormat()
 
91
            return format.open(self, _found=True, location=response[1])
 
92
 
 
93
    def open_repository(self):
 
94
        path = self._path_for_remote_call()
 
95
        response = client.SmartClient(self.client).call('BzrDir.find_repository', path)
 
96
        assert response[0] == 'ok', 'unexpected response code %s' % response[0]
 
97
        if response[1] == '':
 
98
            if vfs.vfs_enabled():
 
99
                return RemoteRepository(self, self._real_bzrdir.open_repository())
 
100
            else:
 
101
                return RemoteRepository(self)
 
102
        else:
 
103
            raise errors.NoRepositoryPresent(self)
 
104
 
 
105
    def open_workingtree(self):
 
106
        return RemoteWorkingTree(self, self._real_bzrdir.open_workingtree())
 
107
 
 
108
    def _path_for_remote_call(self):
 
109
        """Return the path to be used for this bzrdir in a remote call."""
 
110
        return unescape(urlparse(self.root_transport.base)[2])
 
111
 
 
112
    def get_branch_transport(self, branch_format):
 
113
        return self._real_bzrdir.get_branch_transport(branch_format)
 
114
 
 
115
    def get_repository_transport(self, repository_format):
 
116
        return self._real_bzrdir.get_repository_transport(repository_format)
 
117
 
 
118
    def get_workingtree_transport(self, workingtree_format):
 
119
        return self._real_bzrdir.get_workingtree_transport(workingtree_format)
 
120
 
 
121
    def can_convert_format(self):
 
122
        """Upgrading of remote bzrdirs is not supported yet."""
 
123
        return False
 
124
 
 
125
    def needs_format_conversion(self, format=None):
 
126
        """Upgrading of remote bzrdirs is not supported yet."""
 
127
        return False
 
128
 
 
129
 
 
130
class RemoteRepositoryFormat(repository.RepositoryFormat):
 
131
    """Format for repositories accessed over rpc.
 
132
 
 
133
    Instances of this repository are represented by RemoteRepository
 
134
    instances.
 
135
    """
 
136
 
 
137
    _matchingbzrdir = RemoteBzrDirFormat
 
138
 
 
139
    def initialize(self, a_bzrdir, shared=False):
 
140
        assert isinstance(a_bzrdir, RemoteBzrDir)
 
141
        return a_bzrdir.create_repository(shared=shared)
 
142
    
 
143
    def open(self, a_bzrdir):
 
144
        assert isinstance(a_bzrdir, RemoteBzrDir)
 
145
        return a_bzrdir.open_repository()
 
146
 
 
147
    def get_format_description(self):
 
148
        return 'bzr remote repository'
 
149
 
 
150
    def __eq__(self, other):
 
151
        return self.__class__ == other.__class__
 
152
 
 
153
    rich_root_data = False
 
154
 
 
155
 
 
156
class RemoteRepository(object):
 
157
    """Repository accessed over rpc.
 
158
 
 
159
    For the moment everything is delegated to IO-like operations over
 
160
    the transport.
 
161
    """
 
162
 
 
163
    def __init__(self, remote_bzrdir, real_repository=None):
 
164
        """Create a RemoteRepository instance.
 
165
        
 
166
        :param remote_bzrdir: The bzrdir hosting this repository.
 
167
        :param real_repository: If not None, a local implementation of the
 
168
            repository logic for the repository, usually accessing the data
 
169
            via the VFS.
 
170
        """
 
171
        if real_repository:
 
172
            self._real_repository = real_repository
 
173
        self.bzrdir = remote_bzrdir
 
174
        self._client = client.SmartClient(self.bzrdir.client)
 
175
        self._format = RemoteRepositoryFormat()
 
176
 
 
177
    def has_revision(self, revision_id):
 
178
        """See Repository.has_revision()."""
 
179
        path = self.bzrdir._path_for_remote_call().encode('utf8')
 
180
        response = self._client.call('Repository.has_revision', path, revision_id.encode('utf8'))
 
181
        assert response[0] in ('ok', 'no'), 'unexpected response code %s' % response[0]
 
182
        return response[0] == 'ok'
 
183
 
 
184
 
 
185
class RemoteBranchFormat(branch.BranchFormat):
 
186
 
 
187
    def open(self, a_bzrdir):
 
188
        assert isinstance(a_bzrdir, RemoteBzrDir)
 
189
        return a_bzrdir.open_branch()
 
190
 
 
191
    def initialize(self, a_bzrdir):
 
192
        assert isinstance(a_bzrdir, RemoteBzrDir)
 
193
        return a_bzrdir.create_branch()
 
194
 
 
195
 
 
196
class RemoteBranch(branch.Branch):
 
197
    """Branch stored on a server accessed by HPSS RPC.
 
198
 
 
199
    At the moment most operations are mapped down to simple file operations.
 
200
    """
 
201
 
 
202
    def __init__(self, remote_bzrdir, remote_repository, real_branch=None):
 
203
        """Create a RemoteBranch instance.
 
204
 
 
205
        :param real_branch: An optional local implementation of the branch
 
206
            format, usually accessing the data via the VFS.
 
207
        """
 
208
        self.bzrdir = remote_bzrdir
 
209
        self._client = client.SmartClient(self.bzrdir.client)
 
210
        self.repository = remote_repository
 
211
        if real_branch is not None:
 
212
            self._real_branch = real_branch
 
213
        self._format = RemoteBranchFormat()
 
214
 
 
215
    def lock_read(self):
 
216
        return self._real_branch.lock_read()
 
217
 
 
218
    def lock_write(self):
 
219
        return self._real_branch.lock_write()
 
220
 
 
221
    def unlock(self):
 
222
        return self._real_branch.unlock()
 
223
 
 
224
    def break_lock(self):
 
225
        return self._real_branch.break_lock()
 
226
 
 
227
    def revision_history(self):
 
228
        """See Branch.revision_history()."""
 
229
        # XXX: TODO: this does not cache the revision history for the duration
 
230
        # of a lock, which is a bug - see the code for regular branches
 
231
        # for details.
 
232
        path = self.bzrdir._path_for_remote_call()
 
233
        response = self._client.call2('Branch.revision_history', path)
 
234
        assert response[0][0] == 'ok', 'unexpected response code %s' % response[0]
 
235
        result = response[1].read_body_bytes().decode('utf8').split('\x00')
 
236
        if result == ['']:
 
237
            return []
 
238
        return result
 
239
 
 
240
    def set_revision_history(self, rev_history):
 
241
        return self._real_branch.set_revision_history(rev_history)
 
242
 
 
243
    def get_parent(self):
 
244
        return self._real_branch.get_parent()
 
245
        
 
246
    def set_parent(self, url):
 
247
        return self._real_branch.set_parent(url)
 
248
        
 
249
 
 
250
class RemoteWorkingTree(object):
 
251
 
 
252
    def __init__(self, remote_bzrdir, real_workingtree):
 
253
        self.real_workingtree = real_workingtree
 
254
        self.bzrdir = remote_bzrdir
 
255
 
 
256
    def __getattr__(self, name):
 
257
        # XXX: temporary way to lazily delegate everything to the real
 
258
        # workingtree
 
259
        return getattr(self.real_workingtree, name)
 
260
 
 
261