~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:':
6498.3.4 by Jelmer Vernooij
Remove more .set_revision_history / .revision_history references.
302
            branch.set_last_revision_info(0, new_last_revision_id)
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))
6498.3.4 by Jelmer Vernooij
Remove more .set_revision_history / .revision_history references.
307
            branch.generate_revision_history(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.
308
        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.
309
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
310
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
311
class SmartServerBranchRequestSetLastRevisionEx(SmartServerSetTipRequest):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
312
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
313
    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.
314
            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.
315
        """Set the last revision of the branch.
316
317
        New in 1.6.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
318
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.
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
325
            last revision.
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
326
        :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.
327
            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.
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
330
            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.
331
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
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
335
            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.
336
        """
3441.5.28 by Andrew Bennetts
Another review tweak: rename do_not_overwrite_descendant to allow_overwrite_descendant.
337
        do_not_overwrite_descendant = not allow_overwrite_descendant
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
338
        try:
3441.5.18 by Andrew Bennetts
Fix some test failures.
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)
3441.5.23 by Andrew Bennetts
Fix test failures.
352
        except errors.GhostRevisionsHaveNoRevno:
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
353
            return FailedSmartServerResponse(
354
                ('NoSuchRevision', new_last_revision_id))
3441.5.18 by Andrew Bennetts
Fix some test failures.
355
        return SuccessfulSmartServerResponse(
356
            ('ok', new_revno, new_last_revision_id))
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
357
358
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
359
class SmartServerBranchRequestSetLastRevisionInfo(SmartServerSetTipRequest):
3297.4.2 by Andrew Bennetts
Add backwards compatibility for servers older than 1.4.
360
    """Branch.set_last_revision_info.  Sets the revno and the revision ID of
361
    the specified branch.
362
363
    New in bzrlib 1.4.
364
    """
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
365
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
366
    def do_tip_change_with_locked_branch(self, branch, new_revno,
367
            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.
368
        try:
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))
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
373
        return SuccessfulSmartServerResponse(('ok',))
374
375
4288.1.7 by Robert Collins
Add new remote server verb Branch.set_parent_location, dropping roundtrips further on push operations.
376
class SmartServerBranchRequestSetParentLocation(SmartServerLockedBranchRequest):
377
    """Set the parent location for a branch.
378
    
379
    Takes a location to set, which must be utf8 encoded.
380
    """
381
382
    def do_with_locked_branch(self, branch, location):
383
        branch._set_parent_location(location)
384
        return SuccessfulSmartServerResponse(())
385
386
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
387
class SmartServerBranchRequestLockWrite(SmartServerBranchRequest):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
388
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
389
    def do_with_branch(self, branch, branch_token='', repo_token=''):
390
        if branch_token == '':
391
            branch_token = None
392
        if repo_token == '':
393
            repo_token = None
394
        try:
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
395
            repo_token = branch.repository.lock_write(
396
                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).
397
            try:
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
398
                branch_token = branch.lock_write(
399
                    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).
400
            finally:
3015.2.6 by Robert Collins
In the RemoteServer branch methods handle repositories that cannot be remotely locked like pack repositories.
401
                # 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).
402
                branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
403
        except errors.LockContention:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
404
            return FailedSmartServerResponse(('LockContention',))
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
405
        except errors.TokenMismatch:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
406
            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.
407
        except errors.UnlockableTransport:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
408
            return FailedSmartServerResponse(('UnlockableTransport',))
2872.5.3 by Martin Pool
Pass back LockFailed from smart server lock methods
409
        except errors.LockFailed, e:
410
            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.
411
        if repo_token is None:
412
            repo_token = ''
413
        else:
414
            branch.repository.leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
415
        branch.leave_lock_in_place()
416
        branch.unlock()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
417
        return SuccessfulSmartServerResponse(('ok', branch_token, repo_token))
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
418
419
420
class SmartServerBranchRequestUnlock(SmartServerBranchRequest):
421
422
    def do_with_branch(self, branch, branch_token, repo_token):
423
        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).
424
            branch.repository.lock_write(token=repo_token)
425
            try:
426
                branch.lock_write(token=branch_token)
427
            finally:
428
                branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
429
        except errors.TokenMismatch:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
430
            return FailedSmartServerResponse(('TokenMismatch',))
3015.2.6 by Robert Collins
In the RemoteServer branch methods handle repositories that cannot be remotely locked like pack repositories.
431
        if repo_token:
432
            branch.repository.dont_leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
433
        branch.dont_leave_lock_in_place()
434
        branch.unlock()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
435
        return SuccessfulSmartServerResponse(('ok',))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
436
6280.6.2 by Jelmer Vernooij
Add HPSS calls Repository.get_physical_lock_status and Branch.get_physical_lock_status.
437
438
class SmartServerBranchRequestGetPhysicalLockStatus(SmartServerBranchRequest):
439
    """Get the physical lock status for a branch.
440
441
    New in 2.5.
442
    """
443
444
    def do_with_branch(self, branch):
445
        if branch.get_physical_lock_status():
446
            return SuccessfulSmartServerResponse(('yes',))
447
        else:
448
            return SuccessfulSmartServerResponse(('no',))