1
# Copyright (C) 2006 Canonical Ltd
1
# Copyright (C) 2006-2010 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""Server-side branch related request implmentations."""
19
from __future__ import absolute_import
20
from bzrlib import errors
21
from bzrlib.bzrdir import BzrDir
22
from bzrlib.smart.request import (
24
revision as _mod_revision,
26
from ...controldir import ControlDir
27
from .request import (
23
28
FailedSmartServerResponse,
24
29
SmartServerRequest,
25
30
SuccessfulSmartServerResponse,
42
47
:return: A SmartServerResponse from self.do_with_branch().
44
49
transport = self.transport_from_client_path(path)
45
bzrdir = BzrDir.open_from_transport(transport)
46
if bzrdir.get_branch_reference() is not None:
50
controldir = ControlDir.open_from_transport(transport)
51
if controldir.get_branch_reference() is not None:
47
52
raise errors.NotBranchError(transport.base)
48
branch = bzrdir.open_branch(ignore_fallbacks=True)
53
branch = controldir.open_branch(ignore_fallbacks=True)
49
54
return self.do_with_branch(branch, *args)
73
78
branch.repository.unlock()
81
class SmartServerBranchBreakLock(SmartServerBranchRequest):
83
def do_with_branch(self, branch):
84
"""Break a branch lock.
87
return SuccessfulSmartServerResponse((b'ok', ), )
76
90
class SmartServerBranchGetConfigFile(SmartServerBranchRequest):
78
92
def do_with_branch(self, branch):
81
95
The body is not utf8 decoded - its the literal bytestream from disk.
84
content = branch._transport.get_bytes('branch.conf')
98
content = branch.control_transport.get_bytes('branch.conf')
85
99
except errors.NoSuchFile:
87
return SuccessfulSmartServerResponse( ('ok', ), content)
101
return SuccessfulSmartServerResponse((b'ok', ), content)
104
class SmartServerBranchPutConfigFile(SmartServerBranchRequest):
105
"""Set the configuration data for a branch.
110
def do_with_branch(self, branch, branch_token, repo_token):
111
"""Set the content of branch.conf.
113
The body is not utf8 decoded - its the literal bytestream for disk.
115
self._branch = branch
116
self._branch_token = branch_token
117
self._repo_token = repo_token
118
# Signal we want a body
121
def do_body(self, body_bytes):
122
self._branch.repository.lock_write(token=self._repo_token)
124
self._branch.lock_write(token=self._branch_token)
126
self._branch.control_transport.put_bytes(
127
'branch.conf', body_bytes)
129
self._branch.unlock()
131
self._branch.repository.unlock()
132
return SuccessfulSmartServerResponse((b'ok', ))
90
135
class SmartServerBranchGetParent(SmartServerBranchRequest):
92
137
def do_with_branch(self, branch):
93
138
"""Return the parent of branch."""
94
139
parent = branch._get_parent_location() or ''
95
return SuccessfulSmartServerResponse((parent,))
140
return SuccessfulSmartServerResponse((parent.encode('utf-8'),))
98
143
class SmartServerBranchGetTagsBytes(SmartServerBranchRequest):
139
184
self.branch.unlock()
187
class SmartServerBranchHeadsToFetch(SmartServerBranchRequest):
189
def do_with_branch(self, branch):
190
"""Return the heads-to-fetch for a Branch as two bencoded lists.
192
See Branch.heads_to_fetch.
196
must_fetch, if_present_fetch = branch.heads_to_fetch()
197
return SuccessfulSmartServerResponse(
198
(list(must_fetch), list(if_present_fetch)))
142
201
class SmartServerBranchRequestGetStackedOnURL(SmartServerBranchRequest):
144
203
def do_with_branch(self, branch):
145
204
stacked_on_url = branch.get_stacked_on_url()
146
return SuccessfulSmartServerResponse(('ok', stacked_on_url))
205
return SuccessfulSmartServerResponse((b'ok', stacked_on_url))
149
208
class SmartServerRequestRevisionHistory(SmartServerBranchRequest):
154
213
The revision list is returned as the body content,
155
214
with each revision utf8 encoded and \x00 joined.
216
with branch.lock_read():
217
graph = branch.repository.get_graph()
218
stop_revisions = (None, _mod_revision.NULL_REVISION)
219
history = list(graph.iter_lefthand_ancestry(
220
branch.last_revision(), stop_revisions))
157
221
return SuccessfulSmartServerResponse(
158
('ok', ), ('\x00'.join(branch.revision_history())))
222
(b'ok', ), (b'\x00'.join(reversed(history))))
161
225
class SmartServerBranchRequestLastRevisionInfo(SmartServerBranchRequest):
166
230
The revno is encoded in decimal, the revision_id is encoded as utf8.
168
232
revno, last_revision = branch.last_revision_info()
169
return SuccessfulSmartServerResponse(('ok', str(revno), last_revision))
233
return SuccessfulSmartServerResponse(
234
(b'ok', str(revno).encode('ascii'), last_revision))
237
class SmartServerBranchRequestRevisionIdToRevno(SmartServerBranchRequest):
239
def do_with_branch(self, branch, revid):
240
"""Return branch.revision_id_to_revno().
244
The revno is encoded in decimal, the revision_id is encoded as utf8.
247
dotted_revno = branch.revision_id_to_dotted_revno(revid)
248
except errors.NoSuchRevision:
249
return FailedSmartServerResponse((b'NoSuchRevision', revid))
250
return SuccessfulSmartServerResponse(
251
(b'ok', ) + tuple([str(x).encode('ascii') for x in dotted_revno]))
172
254
class SmartServerSetTipRequest(SmartServerLockedBranchRequest):
177
259
def do_with_locked_branch(self, branch, *args):
179
261
return self.do_tip_change_with_locked_branch(branch, *args)
180
except errors.TipChangeRejected, e:
262
except errors.TipChangeRejected as e:
182
264
if isinstance(msg, unicode):
183
265
msg = msg.encode('utf-8')
194
276
return SuccessfulSmartServerResponse(())
279
class SmartServerBranchRequestSetConfigOptionDict(SmartServerLockedBranchRequest):
280
"""Set an option in the branch configuration.
285
def do_with_locked_branch(self, branch, value_dict, name, section):
286
utf8_dict = bencode.bdecode(value_dict)
288
for key, value in utf8_dict.items():
289
value_dict[key.decode('utf8')] = value.decode('utf8')
292
branch._get_config().set_option(value_dict, name, section)
293
return SuccessfulSmartServerResponse(())
197
296
class SmartServerBranchRequestSetLastRevision(SmartServerSetTipRequest):
199
298
def do_tip_change_with_locked_branch(self, branch, new_last_revision_id):
200
if new_last_revision_id == 'null:':
201
branch.set_revision_history([])
299
if new_last_revision_id == b'null:':
300
branch.set_last_revision_info(0, new_last_revision_id)
203
302
if not branch.repository.has_revision(new_last_revision_id):
204
303
return FailedSmartServerResponse(
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',))
304
(b'NoSuchRevision', new_last_revision_id))
305
branch.generate_revision_history(new_last_revision_id, None, None)
306
return SuccessfulSmartServerResponse((b'ok',))
211
309
class SmartServerBranchRequestSetLastRevisionEx(SmartServerSetTipRequest):
245
343
return FailedSmartServerResponse(('Diverged',))
246
344
if relation == 'a_descends_from_b' and do_not_overwrite_descendant:
247
345
return SuccessfulSmartServerResponse(
248
('ok', last_revno, last_rev))
346
(b'ok', last_revno, last_rev))
249
347
new_revno = graph.find_distance_to_null(
250
348
new_last_revision_id, [(last_rev, last_revno)])
251
349
branch.set_last_revision_info(new_revno, new_last_revision_id)
252
350
except errors.GhostRevisionsHaveNoRevno:
253
351
return FailedSmartServerResponse(
254
('NoSuchRevision', new_last_revision_id))
352
(b'NoSuchRevision', new_last_revision_id))
255
353
return SuccessfulSmartServerResponse(
256
('ok', new_revno, new_last_revision_id))
354
(b'ok', new_revno, new_last_revision_id))
259
357
class SmartServerBranchRequestSetLastRevisionInfo(SmartServerSetTipRequest):
260
358
"""Branch.set_last_revision_info. Sets the revno and the revision ID of
261
359
the specified branch.
266
364
def do_tip_change_with_locked_branch(self, branch, new_revno,
269
367
branch.set_last_revision_info(int(new_revno), new_last_revision_id)
270
368
except errors.NoSuchRevision:
271
369
return FailedSmartServerResponse(
272
('NoSuchRevision', new_last_revision_id))
273
return SuccessfulSmartServerResponse(('ok',))
370
(b'NoSuchRevision', new_last_revision_id))
371
return SuccessfulSmartServerResponse((b'ok',))
276
374
class SmartServerBranchRequestSetParentLocation(SmartServerLockedBranchRequest):
287
385
class SmartServerBranchRequestLockWrite(SmartServerBranchRequest):
289
def do_with_branch(self, branch, branch_token='', repo_token=''):
290
if branch_token == '':
387
def do_with_branch(self, branch, branch_token=b'', repo_token=b''):
388
if branch_token == b'':
291
389
branch_token = None
390
if repo_token == b'':
293
391
repo_token = None
295
393
repo_token = branch.repository.lock_write(
296
394
token=repo_token).repository_token
298
396
branch_token = branch.lock_write(
299
token=branch_token).branch_token
397
token=branch_token).token
301
399
# this leaves the repository with 1 lock
302
400
branch.repository.unlock()
303
401
except errors.LockContention:
304
return FailedSmartServerResponse(('LockContention',))
402
return FailedSmartServerResponse((b'LockContention',))
305
403
except errors.TokenMismatch:
306
return FailedSmartServerResponse(('TokenMismatch',))
404
return FailedSmartServerResponse((b'TokenMismatch',))
307
405
except errors.UnlockableTransport:
308
return FailedSmartServerResponse(('UnlockableTransport',))
309
except errors.LockFailed, e:
310
return FailedSmartServerResponse(('LockFailed', str(e.lock), str(e.why)))
406
return FailedSmartServerResponse((b'UnlockableTransport',))
407
except errors.LockFailed as e:
408
return FailedSmartServerResponse((b'LockFailed', str(e.lock), str(e.why)))
311
409
if repo_token is None:
314
412
branch.repository.leave_lock_in_place()
315
413
branch.leave_lock_in_place()
317
return SuccessfulSmartServerResponse(('ok', branch_token, repo_token))
415
return SuccessfulSmartServerResponse((b'ok', branch_token, repo_token))
320
418
class SmartServerBranchRequestUnlock(SmartServerBranchRequest):
328
426
branch.repository.unlock()
329
427
except errors.TokenMismatch:
330
return FailedSmartServerResponse(('TokenMismatch',))
428
return FailedSmartServerResponse((b'TokenMismatch',))
332
430
branch.repository.dont_leave_lock_in_place()
333
431
branch.dont_leave_lock_in_place()
335
return SuccessfulSmartServerResponse(('ok',))
433
return SuccessfulSmartServerResponse((b'ok',))
436
class SmartServerBranchRequestGetPhysicalLockStatus(SmartServerBranchRequest):
437
"""Get the physical lock status for a branch.
442
def do_with_branch(self, branch):
443
if branch.get_physical_lock_status():
444
return SuccessfulSmartServerResponse((b'yes',))
446
return SuccessfulSmartServerResponse((b'no',))