~bzr-pqm/bzr/bzr.dev

5218.2.2 by John Arbash Meinel
Bring in the global chk change, which includes some more bzr.dev code.
1
# Copyright (C) 2006-2010 Canonical Ltd
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
16
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
17
"""Server-side branch related request implmentations."""
18
6379.6.3 by Jelmer Vernooij
Use absolute_import.
19
from __future__ import absolute_import
20
5227.1.2 by Andrew Bennetts
Add Branch.set_config_option_dict RPC (and VFS fallback), fixes #430382.
21
from bzrlib import (
22
    bencode,
23
    errors,
6165.4.16 by Jelmer Vernooij
Don't provide Branch.iter_reverse_revision_history.
24
    revision as _mod_revision,
5227.1.2 by Andrew Bennetts
Add Branch.set_config_option_dict RPC (and VFS fallback), fixes #430382.
25
    )
6207.3.3 by jelmer at samba
Fix tests and the like.
26
from bzrlib.controldir import ControlDir
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
27
from bzrlib.smart.request import (
28
    FailedSmartServerResponse,
29
    SmartServerRequest,
30
    SuccessfulSmartServerResponse,
31
    )
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
32
33
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
34
class SmartServerBranchRequest(SmartServerRequest):
2692.1.10 by Andrew Bennetts
More docstring polish
35
    """Base class for handling common branch request logic.
36
    """
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
37
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
38
    def do(self, path, *args):
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
39
        """Execute a request for a branch at path.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
40
2692.1.10 by Andrew Bennetts
More docstring polish
41
        All Branch requests take a path to the branch as their first argument.
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
42
43
        If the branch is a branch reference, NotBranchError is raised.
2692.1.10 by Andrew Bennetts
More docstring polish
44
45
        :param path: The path for the repository as received from the
46
            client.
47
        :return: A SmartServerResponse from self.do_with_branch().
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
48
        """
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
49
        transport = self.transport_from_client_path(path)
6207.3.3 by jelmer at samba
Fix tests and the like.
50
        controldir = ControlDir.open_from_transport(transport)
51
        if controldir.get_branch_reference() is not None:
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
52
            raise errors.NotBranchError(transport.base)
6207.3.3 by jelmer at samba
Fix tests and the like.
53
        branch = controldir.open_branch(ignore_fallbacks=True)
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
54
        return self.do_with_branch(branch, *args)
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
55
56
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
57
class SmartServerLockedBranchRequest(SmartServerBranchRequest):
58
    """Base class for handling common branch request logic for requests that
59
    need a write lock.
60
    """
61
62
    def do_with_branch(self, branch, branch_token, repo_token, *args):
63
        """Execute a request for a branch.
64
65
        A write lock will be acquired with the given tokens for the branch and
66
        repository locks.  The lock will be released once the request is
67
        processed.  The physical lock state won't be changed.
68
        """
69
        # XXX: write a test for LockContention
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
70
        branch.repository.lock_write(token=repo_token)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
71
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
72
            branch.lock_write(token=branch_token)
73
            try:
74
                return self.do_with_locked_branch(branch, *args)
75
            finally:
76
                branch.unlock()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
77
        finally:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
78
            branch.repository.unlock()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
79
80
6280.4.4 by Jelmer Vernooij
Add Branch.break_lock.
81
class SmartServerBranchBreakLock(SmartServerBranchRequest):
82
83
    def do_with_branch(self, branch):
84
        """Break a branch lock.
85
        """
86
        branch.break_lock()
87
        return SuccessfulSmartServerResponse(('ok', ), )
88
89
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
90
class SmartServerBranchGetConfigFile(SmartServerBranchRequest):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
91
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
92
    def do_with_branch(self, branch):
3407.2.1 by Martin Pool
Deprecate LockableFiles.get
93
        """Return the content of branch.conf
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
94
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
95
        The body is not utf8 decoded - its the literal bytestream from disk.
96
        """
97
        try:
6270.1.9 by Jelmer Vernooij
add Branch.set_config_file.
98
            content = branch.control_transport.get_bytes('branch.conf')
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
99
        except errors.NoSuchFile:
100
            content = ''
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
101
        return SuccessfulSmartServerResponse( ('ok', ), content)
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
102
103
6270.1.17 by Jelmer Vernooij
s/set_config_file/put_config_file.
104
class SmartServerBranchPutConfigFile(SmartServerBranchRequest):
6270.1.10 by Jelmer Vernooij
Fix testing Branch.set_config_file.
105
    """Set the configuration data for a branch.
106
107
    New in 2.5.
108
    """
109
110
    def do_with_branch(self, branch, branch_token, repo_token):
6270.1.9 by Jelmer Vernooij
add Branch.set_config_file.
111
        """Set the content of branch.conf.
112
113
        The body is not utf8 decoded - its the literal bytestream for disk.
114
        """
115
        self._branch = branch
6270.1.10 by Jelmer Vernooij
Fix testing Branch.set_config_file.
116
        self._branch_token = branch_token
117
        self._repo_token = repo_token
6270.1.9 by Jelmer Vernooij
add Branch.set_config_file.
118
        # Signal we want a body
119
        return None
120
121
    def do_body(self, body_bytes):
6270.1.10 by Jelmer Vernooij
Fix testing Branch.set_config_file.
122
        self._branch.repository.lock_write(token=self._repo_token)
6270.1.9 by Jelmer Vernooij
add Branch.set_config_file.
123
        try:
6270.1.10 by Jelmer Vernooij
Fix testing Branch.set_config_file.
124
            self._branch.lock_write(token=self._branch_token)
125
            try:
126
                self._branch.control_transport.put_bytes(
127
                    'branch.conf', body_bytes)
128
            finally:
129
                self._branch.unlock()
6270.1.9 by Jelmer Vernooij
add Branch.set_config_file.
130
        finally:
6270.1.10 by Jelmer Vernooij
Fix testing Branch.set_config_file.
131
            self._branch.repository.unlock()
132
        return SuccessfulSmartServerResponse(('ok', ))
6270.1.9 by Jelmer Vernooij
add Branch.set_config_file.
133
134
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
135
class SmartServerBranchGetParent(SmartServerBranchRequest):
136
137
    def do_with_branch(self, branch):
138
        """Return the parent of branch."""
139
        parent = branch._get_parent_location() or ''
4083.1.4 by Andrew Bennetts
Fix trivial bug in get_parent RPC.
140
        return SuccessfulSmartServerResponse((parent,))
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
141
142
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
143
class SmartServerBranchGetTagsBytes(SmartServerBranchRequest):
144
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,))
149
150
4556.2.1 by Andrew Bennetts
Add Branch.set_tags_bytes RPC, with HPSS call count acceptance test. Also fixes serialisation of LockDir, and uses external_url() in LockDir's repr and contention message.
151
class SmartServerBranchSetTagsBytes(SmartServerLockedBranchRequest):
152
4760.1.1 by Andrew Bennetts
Add optional jail_root argument to SmartServerRequest and friends, and use it in the WSGI glue. Allows opening branches in shared repos via bzr+http (assuming the repo should be accessible).
153
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
4556.2.2 by Andrew Bennetts
Handle failures more gracefully.
154
        SmartServerLockedBranchRequest.__init__(
4760.1.1 by Andrew Bennetts
Add optional jail_root argument to SmartServerRequest and friends, and use it in the WSGI glue. Allows opening branches in shared repos via bzr+http (assuming the repo should be accessible).
155
            self, backing_transport, root_client_path, jail_root)
4556.2.2 by Andrew Bennetts
Handle failures more gracefully.
156
        self.locked = False
157
        
4556.2.1 by Andrew Bennetts
Add Branch.set_tags_bytes RPC, with HPSS call count acceptance test. Also fixes serialisation of LockDir, and uses external_url() in LockDir's repr and contention message.
158
    def do_with_locked_branch(self, branch):
4556.2.4 by Andrew Bennetts
Add NEWS entry, docstring.
159
        """Call _set_tags_bytes for a branch.
160
161
        New in 1.18.
162
        """
4556.2.1 by Andrew Bennetts
Add Branch.set_tags_bytes RPC, with HPSS call count acceptance test. Also fixes serialisation of LockDir, and uses external_url() in LockDir's repr and contention message.
163
        # We need to keep this branch locked until we get a body with the tags
164
        # bytes.
165
        self.branch = branch
166
        self.branch.lock_write()
4556.2.2 by Andrew Bennetts
Handle failures more gracefully.
167
        self.locked = True
4556.2.1 by Andrew Bennetts
Add Branch.set_tags_bytes RPC, with HPSS call count acceptance test. Also fixes serialisation of LockDir, and uses external_url() in LockDir's repr and contention message.
168
169
    def do_body(self, bytes):
170
        self.branch._set_tags_bytes(bytes)
171
        return SuccessfulSmartServerResponse(())
172
173
    def do_end(self):
4556.2.8 by Andrew Bennetts
Add TODO comment.
174
        # TODO: this request shouldn't have to do this housekeeping manually.
175
        # Some of this logic probably belongs in a base class.
4556.2.2 by Andrew Bennetts
Handle failures more gracefully.
176
        if not self.locked:
177
            # We never acquired the branch successfully in the first place, so
178
            # there's nothing more to do.
179
            return
4556.2.1 by Andrew Bennetts
Add Branch.set_tags_bytes RPC, with HPSS call count acceptance test. Also fixes serialisation of LockDir, and uses external_url() in LockDir's repr and contention message.
180
        try:
181
            return SmartServerLockedBranchRequest.do_end(self)
182
        finally:
4556.2.2 by Andrew Bennetts
Handle failures more gracefully.
183
            # Only try unlocking if we locked successfully in the first place
4556.2.1 by Andrew Bennetts
Add Branch.set_tags_bytes RPC, with HPSS call count acceptance test. Also fixes serialisation of LockDir, and uses external_url() in LockDir's repr and contention message.
184
            self.branch.unlock()
185
186
5672.1.4 by Andrew Bennetts
Fix final bzr-loom test by adding RemoteBranch.heads_to_fetch that can ask the remote branch for the heads to fetch (but uses the cheaper default logic if it knows the remote format has an identical heads_to_fetch as Branch.heads_to_fetch).
187
class SmartServerBranchHeadsToFetch(SmartServerBranchRequest):
188
5741.1.11 by Jelmer Vernooij
Don't make heads_to_fetch() take a stop_revision.
189
    def do_with_branch(self, branch):
5672.1.4 by Andrew Bennetts
Fix final bzr-loom test by adding RemoteBranch.heads_to_fetch that can ask the remote branch for the heads to fetch (but uses the cheaper default logic if it knows the remote format has an identical heads_to_fetch as Branch.heads_to_fetch).
190
        """Return the heads-to-fetch for a Branch as two bencoded lists.
191
        
192
        See Branch.heads_to_fetch.
193
194
        New in 2.4.
195
        """
5741.1.11 by Jelmer Vernooij
Don't make heads_to_fetch() take a stop_revision.
196
        must_fetch, if_present_fetch = branch.heads_to_fetch()
5672.1.4 by Andrew Bennetts
Fix final bzr-loom test by adding RemoteBranch.heads_to_fetch that can ask the remote branch for the heads to fetch (but uses the cheaper default logic if it knows the remote format has an identical heads_to_fetch as Branch.heads_to_fetch).
197
        return SuccessfulSmartServerResponse(
198
            (list(must_fetch), list(if_present_fetch)))
199
200
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
201
class SmartServerBranchRequestGetStackedOnURL(SmartServerBranchRequest):
202
203
    def do_with_branch(self, branch):
204
        stacked_on_url = branch.get_stacked_on_url()
205
        return SuccessfulSmartServerResponse(('ok', stacked_on_url))
206
207
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
208
class SmartServerRequestRevisionHistory(SmartServerBranchRequest):
209
210
    def do_with_branch(self, branch):
211
        """Get the revision history for the branch.
212
213
        The revision list is returned as the body content,
214
        with each revision utf8 encoded and \x00 joined.
215
        """
6165.4.23 by Jelmer Vernooij
Fix tests.
216
        branch.lock_read()
217
        try:
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))
222
        finally:
223
            branch.unlock()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
224
        return SuccessfulSmartServerResponse(
6165.4.11 by Jelmer Vernooij
More test fixes.
225
            ('ok', ), ('\x00'.join(reversed(history))))
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
226
227
228
class SmartServerBranchRequestLastRevisionInfo(SmartServerBranchRequest):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
229
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
230
    def do_with_branch(self, branch):
231
        """Return branch.last_revision_info().
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
232
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
233
        The revno is encoded in decimal, the revision_id is encoded as utf8.
234
        """
235
        revno, last_revision = branch.last_revision_info()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
236
        return SuccessfulSmartServerResponse(('ok', str(revno), last_revision))
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
237
238
6263.1.2 by Jelmer Vernooij
Add ``Branch.revision_id_to_revno`` smart verb.
239
class SmartServerBranchRequestRevisionIdToRevno(SmartServerBranchRequest):
240
241
    def do_with_branch(self, branch, revid):
242
        """Return branch.revision_id_to_revno().
243
6263.1.4 by Jelmer Vernooij
Mention version in which Branch.revision_id_to_revno was introduced.
244
        New in 2.5.
245
6263.1.2 by Jelmer Vernooij
Add ``Branch.revision_id_to_revno`` smart verb.
246
        The revno is encoded in decimal, the revision_id is encoded as utf8.
247
        """
248
        try:
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)))
254
255
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
256
class SmartServerSetTipRequest(SmartServerLockedBranchRequest):
257
    """Base class for handling common branch request logic for requests that
258
    update the branch tip.
259
    """
260
261
    def do_with_locked_branch(self, branch, *args):
262
        try:
263
            return self.do_tip_change_with_locked_branch(branch, *args)
264
        except errors.TipChangeRejected, e:
265
            msg = e.msg
266
            if isinstance(msg, unicode):
267
                msg = msg.encode('utf-8')
268
            return FailedSmartServerResponse(('TipChangeRejected', msg))
269
270
4226.2.1 by Robert Collins
Set branch config options via a smart method.
271
class SmartServerBranchRequestSetConfigOption(SmartServerLockedBranchRequest):
272
    """Set an option in the branch configuration."""
273
274
    def do_with_locked_branch(self, branch, value, name, section):
275
        if not section:
276
            section = None
4226.2.2 by Robert Collins
Fix setting config options to support unicode values and don't attempt to reset repositories _fallback_repositories as the simple approach fails to work.
277
        branch._get_config().set_option(value.decode('utf8'), name, section)
4226.2.1 by Robert Collins
Set branch config options via a smart method.
278
        return SuccessfulSmartServerResponse(())
279
280
5227.1.2 by Andrew Bennetts
Add Branch.set_config_option_dict RPC (and VFS fallback), fixes #430382.
281
class SmartServerBranchRequestSetConfigOptionDict(SmartServerLockedBranchRequest):
282
    """Set an option in the branch configuration.
283
    
284
    New in 2.2.
285
    """
286
287
    def do_with_locked_branch(self, branch, value_dict, name, section):
288
        utf8_dict = bencode.bdecode(value_dict)
289
        value_dict = {}
290
        for key, value in utf8_dict.items():
291
            value_dict[key.decode('utf8')] = value.decode('utf8')
292
        if not section:
293
            section = None
294
        branch._get_config().set_option(value_dict, name, section)
295
        return SuccessfulSmartServerResponse(())
296
297
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
298
class SmartServerBranchRequestSetLastRevision(SmartServerSetTipRequest):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
299
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
300
    def do_tip_change_with_locked_branch(self, branch, new_last_revision_id):
2018.5.170 by Andrew Bennetts
Use 'null:' instead of '' to mean NULL_REVISION on the wire.
301
        if new_last_revision_id == 'null:':
5718.8.18 by Jelmer Vernooij
Translate local set_rh calls to remote set_rh calls.
302
            branch._set_revision_history([])
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
303
        else:
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
304
            if not branch.repository.has_revision(new_last_revision_id):
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
305
                return FailedSmartServerResponse(
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
306
                    ('NoSuchRevision', new_last_revision_id))
5718.8.18 by Jelmer Vernooij
Translate local set_rh calls to remote set_rh calls.
307
            branch._set_revision_history(branch._lefthand_history(
308
                new_last_revision_id, None, None))
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
309
        return SuccessfulSmartServerResponse(('ok',))
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
310
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
311
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
312
class SmartServerBranchRequestSetLastRevisionEx(SmartServerSetTipRequest):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
313
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
314
    def do_tip_change_with_locked_branch(self, branch, new_last_revision_id,
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
315
            allow_divergence, allow_overwrite_descendant):
3441.5.25 by Andrew Bennetts
Rename Branch.set_last_revision_descendant verb to Branch.set_last_revision_ex. It's a cop out, but at least it's not misleading.
316
        """Set the last revision of the branch.
317
318
        New in 1.6.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
319
3441.5.25 by Andrew Bennetts
Rename Branch.set_last_revision_descendant verb to Branch.set_last_revision_ex. It's a cop out, but at least it's not misleading.
320
        :param new_last_revision_id: the revision ID to set as the last
321
            revision of the branch.
322
        :param allow_divergence: A flag.  If non-zero, change the revision ID
323
            even if the new_last_revision_id's ancestry has diverged from the
324
            current last revision.  If zero, a 'Diverged' error will be
325
            returned if new_last_revision_id is not a descendant of the current
326
            last revision.
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
327
        :param allow_overwrite_descendant:  A flag.  If zero and
3441.5.25 by Andrew Bennetts
Rename Branch.set_last_revision_descendant verb to Branch.set_last_revision_ex. It's a cop out, but at least it's not misleading.
328
            new_last_revision_id is not a descendant of the current last
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
329
            revision, then the last revision will not be changed.  If non-zero
330
            and there is no divergence, then the last revision is always
331
            changed.
3441.5.25 by Andrew Bennetts
Rename Branch.set_last_revision_descendant verb to Branch.set_last_revision_ex. It's a cop out, but at least it's not misleading.
332
333
        :returns: on success, a tuple of ('ok', revno, revision_id), where
334
            revno and revision_id are the new values of the current last
335
            revision info.  The revision_id might be different to the
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
336
            new_last_revision_id if allow_overwrite_descendant was not set.
3441.5.25 by Andrew Bennetts
Rename Branch.set_last_revision_descendant verb to Branch.set_last_revision_ex. It's a cop out, but at least it's not misleading.
337
        """
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
338
        do_not_overwrite_descendant = not allow_overwrite_descendant
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
339
        try:
3441.5.18 by Andrew Bennetts
Fix some test failures.
340
            last_revno, last_rev = branch.last_revision_info()
341
            graph = branch.repository.get_graph()
342
            if not allow_divergence or do_not_overwrite_descendant:
343
                relation = branch._revision_relations(
344
                    last_rev, new_last_revision_id, graph)
345
                if relation == 'diverged' and not allow_divergence:
346
                    return FailedSmartServerResponse(('Diverged',))
347
                if relation == 'a_descends_from_b' and do_not_overwrite_descendant:
348
                    return SuccessfulSmartServerResponse(
349
                        ('ok', last_revno, last_rev))
350
            new_revno = graph.find_distance_to_null(
351
                new_last_revision_id, [(last_rev, last_revno)])
352
            branch.set_last_revision_info(new_revno, new_last_revision_id)
3441.5.23 by Andrew Bennetts
Fix test failures.
353
        except errors.GhostRevisionsHaveNoRevno:
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
354
            return FailedSmartServerResponse(
355
                ('NoSuchRevision', new_last_revision_id))
3441.5.18 by Andrew Bennetts
Fix some test failures.
356
        return SuccessfulSmartServerResponse(
357
            ('ok', new_revno, new_last_revision_id))
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
358
359
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
360
class SmartServerBranchRequestSetLastRevisionInfo(SmartServerSetTipRequest):
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
361
    """Branch.set_last_revision_info.  Sets the revno and the revision ID of
362
    the specified branch.
363
364
    New in bzrlib 1.4.
365
    """
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
366
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
367
    def do_tip_change_with_locked_branch(self, branch, new_revno,
368
            new_last_revision_id):
3297.4.3 by Andrew Bennetts
Add more tests, handle NoSuchRevision in case the remote branch's format can raise it.
369
        try:
370
            branch.set_last_revision_info(int(new_revno), new_last_revision_id)
371
        except errors.NoSuchRevision:
372
            return FailedSmartServerResponse(
373
                ('NoSuchRevision', new_last_revision_id))
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
374
        return SuccessfulSmartServerResponse(('ok',))
375
376
4288.1.7 by Robert Collins
Add new remote server verb Branch.set_parent_location, dropping roundtrips further on push operations.
377
class SmartServerBranchRequestSetParentLocation(SmartServerLockedBranchRequest):
378
    """Set the parent location for a branch.
379
    
380
    Takes a location to set, which must be utf8 encoded.
381
    """
382
383
    def do_with_locked_branch(self, branch, location):
384
        branch._set_parent_location(location)
385
        return SuccessfulSmartServerResponse(())
386
387
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
388
class SmartServerBranchRequestLockWrite(SmartServerBranchRequest):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
389
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
390
    def do_with_branch(self, branch, branch_token='', repo_token=''):
391
        if branch_token == '':
392
            branch_token = None
393
        if repo_token == '':
394
            repo_token = None
395
        try:
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
396
            repo_token = branch.repository.lock_write(
397
                token=repo_token).repository_token
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
398
            try:
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
399
                branch_token = branch.lock_write(
400
                    token=branch_token).branch_token
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
401
            finally:
3015.2.6 by Robert Collins
In the RemoteServer branch methods handle repositories that cannot be remotely locked like pack repositories.
402
                # this leaves the repository with 1 lock
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
403
                branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
404
        except errors.LockContention:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
405
            return FailedSmartServerResponse(('LockContention',))
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
406
        except errors.TokenMismatch:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
407
            return FailedSmartServerResponse(('TokenMismatch',))
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
408
        except errors.UnlockableTransport:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
409
            return FailedSmartServerResponse(('UnlockableTransport',))
2872.5.3 by Martin Pool
Pass back LockFailed from smart server lock methods
410
        except errors.LockFailed, e:
411
            return FailedSmartServerResponse(('LockFailed', str(e.lock), str(e.why)))
3015.2.6 by Robert Collins
In the RemoteServer branch methods handle repositories that cannot be remotely locked like pack repositories.
412
        if repo_token is None:
413
            repo_token = ''
414
        else:
415
            branch.repository.leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
416
        branch.leave_lock_in_place()
417
        branch.unlock()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
418
        return SuccessfulSmartServerResponse(('ok', branch_token, repo_token))
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
419
420
421
class SmartServerBranchRequestUnlock(SmartServerBranchRequest):
422
423
    def do_with_branch(self, branch, branch_token, repo_token):
424
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
425
            branch.repository.lock_write(token=repo_token)
426
            try:
427
                branch.lock_write(token=branch_token)
428
            finally:
429
                branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
430
        except errors.TokenMismatch:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
431
            return FailedSmartServerResponse(('TokenMismatch',))
3015.2.6 by Robert Collins
In the RemoteServer branch methods handle repositories that cannot be remotely locked like pack repositories.
432
        if repo_token:
433
            branch.repository.dont_leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
434
        branch.dont_leave_lock_in_place()
435
        branch.unlock()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
436
        return SuccessfulSmartServerResponse(('ok',))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
437
6280.6.2 by Jelmer Vernooij
Add HPSS calls Repository.get_physical_lock_status and Branch.get_physical_lock_status.
438
439
class SmartServerBranchRequestGetPhysicalLockStatus(SmartServerBranchRequest):
440
    """Get the physical lock status for a branch.
441
442
    New in 2.5.
443
    """
444
445
    def do_with_branch(self, branch):
446
        if branch.get_physical_lock_status():
447
            return SuccessfulSmartServerResponse(('yes',))
448
        else:
449
            return SuccessfulSmartServerResponse(('no',))