17
17
"""Server-side repository related request implmentations."""
20
23
from bzrlib import errors
21
24
from bzrlib.bzrdir import BzrDir
22
from bzrlib.smart.request import SmartServerRequest, SmartServerResponse
25
from bzrlib.smart.request import (
26
FailedSmartServerResponse,
28
SuccessfulSmartServerResponse,
25
32
class SmartServerRepositoryRequest(SmartServerRequest):
61
68
# Note that we return an empty body, rather than omitting the body.
62
69
# This way the client knows that it can always expect to find a body
63
70
# in the response for this method, even in the error case.
64
return SmartServerResponse(('nosuchrevision', revision_id), '')
71
return FailedSmartServerResponse(('nosuchrevision', revision_id), '')
66
73
for revision, parents in revision_graph.items():
67
74
lines.append(' '.join([revision,] + parents))
69
return SmartServerResponse(('ok', ), '\n'.join(lines))
76
return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
72
79
class SmartServerRequestHasRevision(SmartServerRepositoryRequest):
82
89
if repository.has_revision(revision_id):
83
return SmartServerResponse(('yes', ))
90
return SuccessfulSmartServerResponse(('yes', ))
85
return SmartServerResponse(('no', ))
92
return SuccessfulSmartServerResponse(('no', ))
88
95
class SmartServerRepositoryGatherStats(SmartServerRepositoryRequest):
138
145
shared, and ('no', ) if it is not.
140
147
if repository.is_shared():
141
return SmartServerResponse(('yes', ))
148
return SuccessfulSmartServerResponse(('yes', ))
143
return SmartServerResponse(('no', ))
150
return SuccessfulSmartServerResponse(('no', ))
146
153
class SmartServerRepositoryLockWrite(SmartServerRepositoryRequest):
153
160
token = repository.lock_write(token=token)
154
161
except errors.LockContention, e:
155
return SmartServerResponse(('LockContention',))
162
return FailedSmartServerResponse(('LockContention',))
156
163
except errors.UnlockableTransport:
157
return SmartServerResponse(('UnlockableTransport',))
164
return FailedSmartServerResponse(('UnlockableTransport',))
158
165
repository.leave_lock_in_place()
159
166
repository.unlock()
160
167
if token is None:
162
return SmartServerResponse(('ok', token))
169
return SuccessfulSmartServerResponse(('ok', token))
165
172
class SmartServerRepositoryUnlock(SmartServerRepositoryRequest):
169
176
repository.lock_write(token=token)
170
177
except errors.TokenMismatch, e:
171
return SmartServerResponse(('TokenMismatch',))
178
return FailedSmartServerResponse(('TokenMismatch',))
172
179
repository.dont_leave_lock_in_place()
173
180
repository.unlock()
174
return SmartServerResponse(('ok',))
181
return SuccessfulSmartServerResponse(('ok',))
184
class SmartServerRepositoryTarball(SmartServerRepositoryRequest):
185
"""Get the raw repository files as a tarball.
187
The returned tarball contains a .bzr control directory which in turn
188
contains a repository.
190
This takes one parameter, compression, which currently must be
193
This is used to implement the Repository.copy_content_into operation.
196
def do_repository_request(self, repository, compression):
197
from bzrlib import osutils
198
repo_transport = repository.control_files._transport
199
tmp_dirname, tmp_repo = self._copy_to_tempdir(repository)
201
controldir_name = tmp_dirname + '/.bzr'
202
return self._tarfile_response(controldir_name, compression)
204
osutils.rmtree(tmp_dirname)
206
def _copy_to_tempdir(self, from_repo):
207
tmp_dirname = tempfile.mkdtemp(prefix='tmpbzrclone')
208
tmp_bzrdir = from_repo.bzrdir._format.initialize(tmp_dirname)
209
tmp_repo = from_repo._format.initialize(tmp_bzrdir)
210
from_repo.copy_content_into(tmp_repo)
211
return tmp_dirname, tmp_repo
213
def _tarfile_response(self, tmp_dirname, compression):
214
temp = tempfile.NamedTemporaryFile()
216
self._tarball_of_dir(tmp_dirname, compression, temp.name)
217
# all finished; write the tempfile out to the network
219
return SuccessfulSmartServerResponse(('ok',), temp.read())
220
# FIXME: Don't read the whole thing into memory here; rather stream it
221
# out from the file onto the network. mbp 20070411
225
def _tarball_of_dir(self, dirname, compression, tarfile_name):
226
tarball = tarfile.open(tarfile_name, mode='w:' + compression)
228
# The tarball module only accepts ascii names, and (i guess)
229
# packs them with their 8bit names. We know all the files
230
# within the repository have ASCII names so the should be safe
232
dirname = dirname.encode(sys.getfilesystemencoding())
233
# python's tarball module includes the whole path by default so
235
assert dirname.endswith('.bzr')
236
tarball.add(dirname, '.bzr') # recursive by default