66
78
branch.repository.unlock()
81
class SmartServerBranchBreakLock(SmartServerBranchRequest):
83
def do_with_branch(self, branch):
84
"""Break a branch lock.
87
return SuccessfulSmartServerResponse(('ok', ), )
69
90
class SmartServerBranchGetConfigFile(SmartServerBranchRequest):
71
92
def do_with_branch(self, branch):
72
"""Return the content of branch.control_files.get('branch.conf').
93
"""Return the content of branch.conf
74
95
The body is not utf8 decoded - its the literal bytestream from disk.
77
content = branch.control_files.get('branch.conf').read()
98
content = branch.control_transport.get_bytes('branch.conf')
78
99
except errors.NoSuchFile:
80
101
return SuccessfulSmartServerResponse( ('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(('ok', ))
135
class SmartServerBranchGetParent(SmartServerBranchRequest):
137
def do_with_branch(self, branch):
138
"""Return the parent of branch."""
139
parent = branch._get_parent_location() or ''
140
return SuccessfulSmartServerResponse((parent,))
143
class SmartServerBranchGetTagsBytes(SmartServerBranchRequest):
145
def do_with_branch(self, branch):
146
"""Return the _get_tags_bytes for a branch."""
147
bytes = branch._get_tags_bytes()
148
return SuccessfulSmartServerResponse((bytes,))
151
class SmartServerBranchSetTagsBytes(SmartServerLockedBranchRequest):
153
def __init__(self, backing_transport, root_client_path='/', jail_root=None):
154
SmartServerLockedBranchRequest.__init__(
155
self, backing_transport, root_client_path, jail_root)
158
def do_with_locked_branch(self, branch):
159
"""Call _set_tags_bytes for a branch.
163
# We need to keep this branch locked until we get a body with the tags
166
self.branch.lock_write()
169
def do_body(self, bytes):
170
self.branch._set_tags_bytes(bytes)
171
return SuccessfulSmartServerResponse(())
174
# TODO: this request shouldn't have to do this housekeeping manually.
175
# Some of this logic probably belongs in a base class.
177
# We never acquired the branch successfully in the first place, so
178
# there's nothing more to do.
181
return SmartServerLockedBranchRequest.do_end(self)
183
# Only try unlocking if we locked successfully in the first place
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)))
201
class SmartServerBranchRequestGetStackedOnURL(SmartServerBranchRequest):
203
def do_with_branch(self, branch):
204
stacked_on_url = branch.get_stacked_on_url()
205
return SuccessfulSmartServerResponse(('ok', stacked_on_url))
83
208
class SmartServerRequestRevisionHistory(SmartServerBranchRequest):
85
210
def do_with_branch(self, branch):
88
213
The revision list is returned as the body content,
89
214
with each revision utf8 encoded and \x00 joined.
218
graph = branch.repository.get_graph()
219
stop_revisions = (None, _mod_revision.NULL_REVISION)
220
history = list(graph.iter_lefthand_ancestry(
221
branch.last_revision(), stop_revisions))
91
224
return SuccessfulSmartServerResponse(
92
('ok', ), ('\x00'.join(branch.revision_history())))
225
('ok', ), ('\x00'.join(reversed(history))))
95
228
class SmartServerBranchRequestLastRevisionInfo(SmartServerBranchRequest):
97
230
def do_with_branch(self, branch):
98
231
"""Return branch.last_revision_info().
100
233
The revno is encoded in decimal, the revision_id is encoded as utf8.
102
235
revno, last_revision = branch.last_revision_info()
103
236
return SuccessfulSmartServerResponse(('ok', str(revno), last_revision))
106
class SmartServerBranchRequestSetLastRevision(SmartServerLockedBranchRequest):
239
class SmartServerBranchRequestRevisionIdToRevno(SmartServerBranchRequest):
241
def do_with_branch(self, branch, revid):
242
"""Return branch.revision_id_to_revno().
246
The revno is encoded in decimal, the revision_id is encoded as utf8.
249
dotted_revno = branch.revision_id_to_dotted_revno(revid)
250
except errors.NoSuchRevision:
251
return FailedSmartServerResponse(('NoSuchRevision', revid))
252
return SuccessfulSmartServerResponse(
253
('ok', ) + tuple(map(str, dotted_revno)))
256
class SmartServerSetTipRequest(SmartServerLockedBranchRequest):
257
"""Base class for handling common branch request logic for requests that
258
update the branch tip.
261
def do_with_locked_branch(self, branch, *args):
263
return self.do_tip_change_with_locked_branch(branch, *args)
264
except errors.TipChangeRejected, e:
266
if isinstance(msg, unicode):
267
msg = msg.encode('utf-8')
268
return FailedSmartServerResponse(('TipChangeRejected', msg))
271
class SmartServerBranchRequestSetConfigOption(SmartServerLockedBranchRequest):
272
"""Set an option in the branch configuration."""
274
def do_with_locked_branch(self, branch, value, name, section):
277
branch._get_config().set_option(value.decode('utf8'), name, section)
278
return SuccessfulSmartServerResponse(())
281
class SmartServerBranchRequestSetConfigOptionDict(SmartServerLockedBranchRequest):
282
"""Set an option in the branch configuration.
108
def do_with_locked_branch(self, branch, new_last_revision_id):
287
def do_with_locked_branch(self, branch, value_dict, name, section):
288
utf8_dict = bencode.bdecode(value_dict)
290
for key, value in utf8_dict.items():
291
value_dict[key.decode('utf8')] = value.decode('utf8')
294
branch._get_config().set_option(value_dict, name, section)
295
return SuccessfulSmartServerResponse(())
298
class SmartServerBranchRequestSetLastRevision(SmartServerSetTipRequest):
300
def do_tip_change_with_locked_branch(self, branch, new_last_revision_id):
109
301
if new_last_revision_id == 'null:':
110
branch.set_revision_history([])
302
branch.set_last_revision_info(0, new_last_revision_id)
112
304
if not branch.repository.has_revision(new_last_revision_id):
113
305
return FailedSmartServerResponse(
114
306
('NoSuchRevision', new_last_revision_id))
115
branch.generate_revision_history(new_last_revision_id)
116
return SuccessfulSmartServerResponse(('ok',))
307
branch.generate_revision_history(new_last_revision_id, None, None)
308
return SuccessfulSmartServerResponse(('ok',))
311
class SmartServerBranchRequestSetLastRevisionEx(SmartServerSetTipRequest):
313
def do_tip_change_with_locked_branch(self, branch, new_last_revision_id,
314
allow_divergence, allow_overwrite_descendant):
315
"""Set the last revision of the branch.
319
:param new_last_revision_id: the revision ID to set as the last
320
revision of the branch.
321
:param allow_divergence: A flag. If non-zero, change the revision ID
322
even if the new_last_revision_id's ancestry has diverged from the
323
current last revision. If zero, a 'Diverged' error will be
324
returned if new_last_revision_id is not a descendant of the current
326
:param allow_overwrite_descendant: A flag. If zero and
327
new_last_revision_id is not a descendant of the current last
328
revision, then the last revision will not be changed. If non-zero
329
and there is no divergence, then the last revision is always
332
:returns: on success, a tuple of ('ok', revno, revision_id), where
333
revno and revision_id are the new values of the current last
334
revision info. The revision_id might be different to the
335
new_last_revision_id if allow_overwrite_descendant was not set.
337
do_not_overwrite_descendant = not allow_overwrite_descendant
339
last_revno, last_rev = branch.last_revision_info()
340
graph = branch.repository.get_graph()
341
if not allow_divergence or do_not_overwrite_descendant:
342
relation = branch._revision_relations(
343
last_rev, new_last_revision_id, graph)
344
if relation == 'diverged' and not allow_divergence:
345
return FailedSmartServerResponse(('Diverged',))
346
if relation == 'a_descends_from_b' and do_not_overwrite_descendant:
347
return SuccessfulSmartServerResponse(
348
('ok', last_revno, last_rev))
349
new_revno = graph.find_distance_to_null(
350
new_last_revision_id, [(last_rev, last_revno)])
351
branch.set_last_revision_info(new_revno, new_last_revision_id)
352
except errors.GhostRevisionsHaveNoRevno:
353
return FailedSmartServerResponse(
354
('NoSuchRevision', new_last_revision_id))
355
return SuccessfulSmartServerResponse(
356
('ok', new_revno, new_last_revision_id))
359
class SmartServerBranchRequestSetLastRevisionInfo(SmartServerSetTipRequest):
360
"""Branch.set_last_revision_info. Sets the revno and the revision ID of
361
the specified branch.
366
def do_tip_change_with_locked_branch(self, branch, new_revno,
367
new_last_revision_id):
369
branch.set_last_revision_info(int(new_revno), new_last_revision_id)
370
except errors.NoSuchRevision:
371
return FailedSmartServerResponse(
372
('NoSuchRevision', new_last_revision_id))
373
return SuccessfulSmartServerResponse(('ok',))
376
class SmartServerBranchRequestSetParentLocation(SmartServerLockedBranchRequest):
377
"""Set the parent location for a branch.
379
Takes a location to set, which must be utf8 encoded.
382
def do_with_locked_branch(self, branch, location):
383
branch._set_parent_location(location)
384
return SuccessfulSmartServerResponse(())
119
387
class SmartServerBranchRequestLockWrite(SmartServerBranchRequest):
121
389
def do_with_branch(self, branch, branch_token='', repo_token=''):
122
390
if branch_token == '':
123
391
branch_token = None
124
392
if repo_token == '':
125
393
repo_token = None
127
repo_token = branch.repository.lock_write(token=repo_token)
395
repo_token = branch.repository.lock_write(
396
token=repo_token).repository_token
129
branch_token = branch.lock_write(token=branch_token)
398
branch_token = branch.lock_write(
399
token=branch_token).branch_token
401
# this leaves the repository with 1 lock
131
402
branch.repository.unlock()
132
403
except errors.LockContention:
133
404
return FailedSmartServerResponse(('LockContention',))