17
17
"""Server-side branch related request implmentations."""
19
from __future__ import absolute_import
24
revision as _mod_revision,
26
from ...controldir import ControlDir
27
from ...sixish import text_type
28
from .request import (
20
from bzrlib import errors
21
from bzrlib.bzrdir import BzrDir
22
from bzrlib.smart.request import (
29
23
FailedSmartServerResponse,
30
24
SmartServerRequest,
31
25
SuccessfulSmartServerResponse,
48
42
:return: A SmartServerResponse from self.do_with_branch().
50
44
transport = self.transport_from_client_path(path)
51
controldir = ControlDir.open_from_transport(transport)
52
if controldir.get_branch_reference() is not None:
45
bzrdir = BzrDir.open_from_transport(transport)
46
if bzrdir.get_branch_reference() is not None:
53
47
raise errors.NotBranchError(transport.base)
54
branch = controldir.open_branch(ignore_fallbacks=True)
48
branch = bzrdir.open_branch(ignore_fallbacks=True)
55
49
return self.do_with_branch(branch, *args)
68
62
processed. The physical lock state won't be changed.
70
64
# XXX: write a test for LockContention
71
with branch.repository.lock_write(token=repo_token), \
72
branch.lock_write(token=branch_token):
65
branch.repository.lock_write(token=repo_token)
67
branch.lock_write(token=branch_token)
73
69
return self.do_with_locked_branch(branch, *args)
76
class SmartServerBranchBreakLock(SmartServerBranchRequest):
78
def do_with_branch(self, branch):
79
"""Break a branch lock.
82
return SuccessfulSmartServerResponse((b'ok', ), )
73
branch.repository.unlock()
85
76
class SmartServerBranchGetConfigFile(SmartServerBranchRequest):
90
81
The body is not utf8 decoded - its the literal bytestream from disk.
93
content = branch.control_transport.get_bytes('branch.conf')
84
content = branch._transport.get_bytes('branch.conf')
94
85
except errors.NoSuchFile:
96
return SuccessfulSmartServerResponse((b'ok', ), content)
99
class SmartServerBranchPutConfigFile(SmartServerBranchRequest):
100
"""Set the configuration data for a branch.
105
def do_with_branch(self, branch, branch_token, repo_token):
106
"""Set the content of branch.conf.
108
The body is not utf8 decoded - its the literal bytestream for disk.
110
self._branch = branch
111
self._branch_token = branch_token
112
self._repo_token = repo_token
113
# Signal we want a body
116
def do_body(self, body_bytes):
117
with self._branch.repository.lock_write(token=self._repo_token), \
118
self._branch.lock_write(token=self._branch_token):
119
self._branch.control_transport.put_bytes(
120
'branch.conf', body_bytes)
121
return SuccessfulSmartServerResponse((b'ok', ))
87
return SuccessfulSmartServerResponse( ('ok', ), content)
124
90
class SmartServerBranchGetParent(SmartServerBranchRequest):
173
139
self.branch.unlock()
176
class SmartServerBranchHeadsToFetch(SmartServerBranchRequest):
178
def do_with_branch(self, branch):
179
"""Return the heads-to-fetch for a Branch as two bencoded lists.
181
See Branch.heads_to_fetch.
185
must_fetch, if_present_fetch = branch.heads_to_fetch()
186
return SuccessfulSmartServerResponse(
187
(list(must_fetch), list(if_present_fetch)))
190
142
class SmartServerBranchRequestGetStackedOnURL(SmartServerBranchRequest):
192
144
def do_with_branch(self, branch):
193
145
stacked_on_url = branch.get_stacked_on_url()
194
return SuccessfulSmartServerResponse((b'ok', stacked_on_url.encode('ascii')))
146
return SuccessfulSmartServerResponse(('ok', stacked_on_url))
197
149
class SmartServerRequestRevisionHistory(SmartServerBranchRequest):
202
154
The revision list is returned as the body content,
203
155
with each revision utf8 encoded and \x00 joined.
205
with branch.lock_read():
206
graph = branch.repository.get_graph()
207
stop_revisions = (None, _mod_revision.NULL_REVISION)
208
history = list(graph.iter_lefthand_ancestry(
209
branch.last_revision(), stop_revisions))
210
157
return SuccessfulSmartServerResponse(
211
(b'ok', ), (b'\x00'.join(reversed(history))))
158
('ok', ), ('\x00'.join(branch.revision_history())))
214
161
class SmartServerBranchRequestLastRevisionInfo(SmartServerBranchRequest):
219
166
The revno is encoded in decimal, the revision_id is encoded as utf8.
221
168
revno, last_revision = branch.last_revision_info()
222
return SuccessfulSmartServerResponse(
223
(b'ok', str(revno).encode('ascii'), last_revision))
226
class SmartServerBranchRequestRevisionIdToRevno(SmartServerBranchRequest):
228
def do_with_branch(self, branch, revid):
229
"""Return branch.revision_id_to_revno().
233
The revno is encoded in decimal, the revision_id is encoded as utf8.
236
dotted_revno = branch.revision_id_to_dotted_revno(revid)
237
except errors.NoSuchRevision:
238
return FailedSmartServerResponse((b'NoSuchRevision', revid))
239
return SuccessfulSmartServerResponse(
240
(b'ok', ) + tuple([b'%d' % x for x in dotted_revno]))
169
return SuccessfulSmartServerResponse(('ok', str(revno), last_revision))
243
172
class SmartServerSetTipRequest(SmartServerLockedBranchRequest):
248
177
def do_with_locked_branch(self, branch, *args):
250
179
return self.do_tip_change_with_locked_branch(branch, *args)
251
except errors.TipChangeRejected as e:
180
except errors.TipChangeRejected, e:
253
if isinstance(msg, text_type):
182
if isinstance(msg, unicode):
254
183
msg = msg.encode('utf-8')
255
return FailedSmartServerResponse((b'TipChangeRejected', msg))
184
return FailedSmartServerResponse(('TipChangeRejected', msg))
258
187
class SmartServerBranchRequestSetConfigOption(SmartServerLockedBranchRequest):
261
190
def do_with_locked_branch(self, branch, value, name, section):
264
branch._get_config().set_option(
265
value.decode('utf-8'), name.decode('utf-8'),
266
section.decode('utf-8') if section is not None else None)
267
return SuccessfulSmartServerResponse(())
270
class SmartServerBranchRequestSetConfigOptionDict(SmartServerLockedBranchRequest):
271
"""Set an option in the branch configuration.
276
def do_with_locked_branch(self, branch, value_dict, name, section):
277
utf8_dict = bencode.bdecode(value_dict)
279
for key, value in utf8_dict.items():
280
value_dict[key.decode('utf8')] = value.decode('utf8')
284
section = section.decode('utf-8')
285
branch._get_config().set_option(value_dict, name.decode('utf-8'), section)
193
branch._get_config().set_option(value.decode('utf8'), name, section)
286
194
return SuccessfulSmartServerResponse(())
289
197
class SmartServerBranchRequestSetLastRevision(SmartServerSetTipRequest):
291
199
def do_tip_change_with_locked_branch(self, branch, new_last_revision_id):
292
if new_last_revision_id == b'null:':
293
branch.set_last_revision_info(0, new_last_revision_id)
200
if new_last_revision_id == 'null:':
201
branch.set_revision_history([])
295
203
if not branch.repository.has_revision(new_last_revision_id):
296
204
return FailedSmartServerResponse(
297
(b'NoSuchRevision', new_last_revision_id))
298
branch.generate_revision_history(new_last_revision_id, None, None)
299
return SuccessfulSmartServerResponse((b'ok',))
205
('NoSuchRevision', new_last_revision_id))
206
branch.set_revision_history(branch._lefthand_history(
207
new_last_revision_id, None, None))
208
return SuccessfulSmartServerResponse(('ok',))
302
211
class SmartServerBranchRequestSetLastRevisionEx(SmartServerSetTipRequest):
333
242
relation = branch._revision_relations(
334
243
last_rev, new_last_revision_id, graph)
335
244
if relation == 'diverged' and not allow_divergence:
336
return FailedSmartServerResponse((b'Diverged',))
245
return FailedSmartServerResponse(('Diverged',))
337
246
if relation == 'a_descends_from_b' and do_not_overwrite_descendant:
338
247
return SuccessfulSmartServerResponse(
339
(b'ok', last_revno, last_rev))
248
('ok', last_revno, last_rev))
340
249
new_revno = graph.find_distance_to_null(
341
250
new_last_revision_id, [(last_rev, last_revno)])
342
251
branch.set_last_revision_info(new_revno, new_last_revision_id)
343
252
except errors.GhostRevisionsHaveNoRevno:
344
253
return FailedSmartServerResponse(
345
(b'NoSuchRevision', new_last_revision_id))
254
('NoSuchRevision', new_last_revision_id))
346
255
return SuccessfulSmartServerResponse(
347
(b'ok', new_revno, new_last_revision_id))
256
('ok', new_revno, new_last_revision_id))
350
259
class SmartServerBranchRequestSetLastRevisionInfo(SmartServerSetTipRequest):
351
260
"""Branch.set_last_revision_info. Sets the revno and the revision ID of
352
261
the specified branch.
357
266
def do_tip_change_with_locked_branch(self, branch, new_revno,
360
269
branch.set_last_revision_info(int(new_revno), new_last_revision_id)
361
270
except errors.NoSuchRevision:
362
271
return FailedSmartServerResponse(
363
(b'NoSuchRevision', new_last_revision_id))
364
return SuccessfulSmartServerResponse((b'ok',))
272
('NoSuchRevision', new_last_revision_id))
273
return SuccessfulSmartServerResponse(('ok',))
367
276
class SmartServerBranchRequestSetParentLocation(SmartServerLockedBranchRequest):
378
287
class SmartServerBranchRequestLockWrite(SmartServerBranchRequest):
380
def do_with_branch(self, branch, branch_token=b'', repo_token=b''):
381
if branch_token == b'':
289
def do_with_branch(self, branch, branch_token='', repo_token=''):
290
if branch_token == '':
382
291
branch_token = None
383
if repo_token == b'':
384
293
repo_token = None
386
repo_token = branch.repository.lock_write(
387
token=repo_token).repository_token
295
repo_token = branch.repository.lock_write(token=repo_token)
389
branch_token = branch.lock_write(
390
token=branch_token).token
297
branch_token = branch.lock_write(token=branch_token)
392
299
# this leaves the repository with 1 lock
393
300
branch.repository.unlock()
394
301
except errors.LockContention:
395
return FailedSmartServerResponse((b'LockContention',))
302
return FailedSmartServerResponse(('LockContention',))
396
303
except errors.TokenMismatch:
397
return FailedSmartServerResponse((b'TokenMismatch',))
304
return FailedSmartServerResponse(('TokenMismatch',))
398
305
except errors.UnlockableTransport:
399
return FailedSmartServerResponse((b'UnlockableTransport',))
400
except errors.LockFailed as e:
401
return FailedSmartServerResponse((b'LockFailed', str(e.lock), str(e.why)))
306
return FailedSmartServerResponse(('UnlockableTransport',))
307
except errors.LockFailed, e:
308
return FailedSmartServerResponse(('LockFailed', str(e.lock), str(e.why)))
402
309
if repo_token is None:
405
312
branch.repository.leave_lock_in_place()
406
313
branch.leave_lock_in_place()
408
return SuccessfulSmartServerResponse((b'ok', branch_token, repo_token))
315
return SuccessfulSmartServerResponse(('ok', branch_token, repo_token))
411
318
class SmartServerBranchRequestUnlock(SmartServerBranchRequest):
413
320
def do_with_branch(self, branch, branch_token, repo_token):
415
with branch.repository.lock_write(token=repo_token):
322
branch.repository.lock_write(token=repo_token)
416
324
branch.lock_write(token=branch_token)
326
branch.repository.unlock()
417
327
except errors.TokenMismatch:
418
return FailedSmartServerResponse((b'TokenMismatch',))
328
return FailedSmartServerResponse(('TokenMismatch',))
420
330
branch.repository.dont_leave_lock_in_place()
421
331
branch.dont_leave_lock_in_place()
423
return SuccessfulSmartServerResponse((b'ok',))
426
class SmartServerBranchRequestGetPhysicalLockStatus(SmartServerBranchRequest):
427
"""Get the physical lock status for a branch.
432
def do_with_branch(self, branch):
433
if branch.get_physical_lock_status():
434
return SuccessfulSmartServerResponse((b'yes',))
436
return SuccessfulSmartServerResponse((b'no',))
333
return SuccessfulSmartServerResponse(('ok',))