/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/bzr/smart/bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2017-08-07 11:49:46 UTC
  • mto: (6747.3.4 avoid-set-revid-3)
  • mto: This revision was merged to the branch mainline in revision 6750.
  • Revision ID: jelmer@jelmer.uk-20170807114946-luclmxuawyzhpiot
Avoid setting revision_ids.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006-2010 Canonical Ltd
 
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Server-side bzrdir related request implmentations."""
 
18
 
 
19
from __future__ import absolute_import
 
20
 
 
21
from ... import (
 
22
    bencode,
 
23
    branch,
 
24
    errors,
 
25
    repository,
 
26
    urlutils,
 
27
    )
 
28
from .. import (
 
29
    BzrProber,
 
30
    )
 
31
from ..bzrdir import (
 
32
    BzrDir,
 
33
    BzrDirFormat,
 
34
    )
 
35
from ...controldir import (
 
36
    network_format_registry,
 
37
    )
 
38
from .request import (
 
39
    FailedSmartServerResponse,
 
40
    SmartServerRequest,
 
41
    SuccessfulSmartServerResponse,
 
42
    )
 
43
 
 
44
 
 
45
class SmartServerRequestOpenBzrDir(SmartServerRequest):
 
46
 
 
47
    def do(self, path):
 
48
        try:
 
49
            t = self.transport_from_client_path(path)
 
50
        except errors.PathNotChild:
 
51
            # The client is trying to ask about a path that they have no access
 
52
            # to.
 
53
            # Ideally we'd return a FailedSmartServerResponse here rather than
 
54
            # a "successful" negative, but we want to be compatibile with
 
55
            # clients that don't anticipate errors from this method.
 
56
            answer = 'no'
 
57
        else:
 
58
            bzr_prober = BzrProber()
 
59
            try:
 
60
                bzr_prober.probe_transport(t)
 
61
            except (errors.NotBranchError, errors.UnknownFormatError):
 
62
                answer = 'no'
 
63
            else:
 
64
                answer = 'yes'
 
65
        return SuccessfulSmartServerResponse((answer,))
 
66
 
 
67
 
 
68
class SmartServerRequestOpenBzrDir_2_1(SmartServerRequest):
 
69
 
 
70
    def do(self, path):
 
71
        """Is there a BzrDir present, and if so does it have a working tree?
 
72
 
 
73
        New in 2.1.
 
74
        """
 
75
        try:
 
76
            t = self.transport_from_client_path(path)
 
77
        except errors.PathNotChild:
 
78
            # The client is trying to ask about a path that they have no access
 
79
            # to.
 
80
            return SuccessfulSmartServerResponse(('no',))
 
81
        try:
 
82
            bd = BzrDir.open_from_transport(t)
 
83
        except errors.NotBranchError:
 
84
            answer = ('no',)
 
85
        else:
 
86
            answer = ('yes',)
 
87
            if bd.has_workingtree():
 
88
                answer += ('yes',)
 
89
            else:
 
90
                answer += ('no',)
 
91
        return SuccessfulSmartServerResponse(answer)
 
92
 
 
93
 
 
94
class SmartServerRequestBzrDir(SmartServerRequest):
 
95
 
 
96
    def do(self, path, *args):
 
97
        """Open a BzrDir at path, and return `self.do_bzrdir_request(*args)`."""
 
98
        try:
 
99
            self._bzrdir = BzrDir.open_from_transport(
 
100
                self.transport_from_client_path(path))
 
101
        except errors.NotBranchError as e:
 
102
            return FailedSmartServerResponse(('nobranch',))
 
103
        return self.do_bzrdir_request(*args)
 
104
 
 
105
    def _boolean_to_yes_no(self, a_boolean):
 
106
        if a_boolean:
 
107
            return 'yes'
 
108
        else:
 
109
            return 'no'
 
110
 
 
111
    def _format_to_capabilities(self, repo_format):
 
112
        rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
 
113
        tree_ref = self._boolean_to_yes_no(
 
114
            repo_format.supports_tree_reference)
 
115
        external_lookup = self._boolean_to_yes_no(
 
116
            repo_format.supports_external_lookups)
 
117
        return rich_root, tree_ref, external_lookup
 
118
 
 
119
    def _repo_relpath(self, current_transport, repository):
 
120
        """Get the relative path for repository from current_transport."""
 
121
        # the relpath of the bzrdir in the found repository gives us the
 
122
        # path segments to pop-out.
 
123
        relpath = repository.user_transport.relpath(
 
124
            current_transport.base)
 
125
        if len(relpath):
 
126
            segments = ['..'] * len(relpath.split('/'))
 
127
        else:
 
128
            segments = []
 
129
        return '/'.join(segments)
 
130
 
 
131
 
 
132
class SmartServerBzrDirRequestDestroyBranch(SmartServerRequestBzrDir):
 
133
 
 
134
    def do_bzrdir_request(self, name=None):
 
135
        """Destroy the branch with the specified name.
 
136
 
 
137
        New in 2.5.0.
 
138
        :return: On success, 'ok'.
 
139
        """
 
140
        try:
 
141
            self._bzrdir.destroy_branch(name)
 
142
        except errors.NotBranchError as e:
 
143
            return FailedSmartServerResponse(('nobranch',))
 
144
        return SuccessfulSmartServerResponse(('ok',))
 
145
 
 
146
 
 
147
class SmartServerBzrDirRequestHasWorkingTree(SmartServerRequestBzrDir):
 
148
 
 
149
    def do_bzrdir_request(self, name=None):
 
150
        """Check whether there is a working tree present.
 
151
 
 
152
        New in 2.5.0.
 
153
 
 
154
        :return: If there is a working tree present, 'yes'.
 
155
            Otherwise 'no'.
 
156
        """
 
157
        if self._bzrdir.has_workingtree():
 
158
            return SuccessfulSmartServerResponse(('yes', ))
 
159
        else:
 
160
            return SuccessfulSmartServerResponse(('no', ))
 
161
 
 
162
 
 
163
class SmartServerBzrDirRequestDestroyRepository(SmartServerRequestBzrDir):
 
164
 
 
165
    def do_bzrdir_request(self, name=None):
 
166
        """Destroy the repository.
 
167
 
 
168
        New in 2.5.0.
 
169
 
 
170
        :return: On success, 'ok'.
 
171
        """
 
172
        try:
 
173
            self._bzrdir.destroy_repository()
 
174
        except errors.NoRepositoryPresent as e:
 
175
            return FailedSmartServerResponse(('norepository',))
 
176
        return SuccessfulSmartServerResponse(('ok',))
 
177
 
 
178
 
 
179
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
 
180
 
 
181
    def do_bzrdir_request(self, require_stacking):
 
182
        """Get the format that should be used when cloning from this dir.
 
183
 
 
184
        New in 1.13.
 
185
        
 
186
        :return: on success, a 3-tuple of network names for (control,
 
187
            repository, branch) directories, where '' signifies "not present".
 
188
            If this BzrDir contains a branch reference then this will fail with
 
189
            BranchReference; clients should resolve branch references before
 
190
            calling this RPC.
 
191
        """
 
192
        try:
 
193
            branch_ref = self._bzrdir.get_branch_reference()
 
194
        except errors.NotBranchError:
 
195
            branch_ref = None
 
196
        if branch_ref is not None:
 
197
            # The server shouldn't try to resolve references, and it quite
 
198
            # possibly can't reach them anyway.  The client needs to resolve
 
199
            # the branch reference to determine the cloning_metadir.
 
200
            return FailedSmartServerResponse(('BranchReference',))
 
201
        if require_stacking == "True":
 
202
            require_stacking = True
 
203
        else:
 
204
            require_stacking = False
 
205
        control_format = self._bzrdir.cloning_metadir(
 
206
            require_stacking=require_stacking)
 
207
        control_name = control_format.network_name()
 
208
        if not control_format.fixed_components:
 
209
            branch_name = ('branch',
 
210
                control_format.get_branch_format().network_name())
 
211
            repository_name = control_format.repository_format.network_name()
 
212
        else:
 
213
            # Only MetaDir has delegated formats today.
 
214
            branch_name = ('branch', '')
 
215
            repository_name = ''
 
216
        return SuccessfulSmartServerResponse((control_name, repository_name,
 
217
            branch_name))
 
218
 
 
219
 
 
220
class SmartServerBzrDirRequestCheckoutMetaDir(SmartServerRequestBzrDir):
 
221
    """Get the format to use for checkouts.
 
222
 
 
223
    New in 2.5.
 
224
 
 
225
    :return: on success, a 3-tuple of network names for (control,
 
226
        repository, branch) directories, where '' signifies "not present".
 
227
        If this BzrDir contains a branch reference then this will fail with
 
228
        BranchReference; clients should resolve branch references before
 
229
        calling this RPC (they should not try to create a checkout of a
 
230
        checkout).
 
231
    """
 
232
 
 
233
    def do_bzrdir_request(self):
 
234
        try:
 
235
            branch_ref = self._bzrdir.get_branch_reference()
 
236
        except errors.NotBranchError:
 
237
            branch_ref = None
 
238
        if branch_ref is not None:
 
239
            # The server shouldn't try to resolve references, and it quite
 
240
            # possibly can't reach them anyway.  The client needs to resolve
 
241
            # the branch reference to determine the cloning_metadir.
 
242
            return FailedSmartServerResponse(('BranchReference',))
 
243
        control_format = self._bzrdir.checkout_metadir()
 
244
        control_name = control_format.network_name()
 
245
        if not control_format.fixed_components:
 
246
            branch_name = control_format.get_branch_format().network_name()
 
247
            repo_name = control_format.repository_format.network_name()
 
248
        else:
 
249
            branch_name = ''
 
250
            repo_name = ''
 
251
        return SuccessfulSmartServerResponse(
 
252
            (control_name, repo_name, branch_name))
 
253
 
 
254
 
 
255
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
 
256
 
 
257
    def do(self, path, network_name):
 
258
        """Create a branch in the bzr dir at path.
 
259
 
 
260
        This operates precisely like 'bzrdir.create_branch'.
 
261
 
 
262
        If a bzrdir is not present, an exception is propogated
 
263
        rather than 'no branch' because these are different conditions (and
 
264
        this method should only be called after establishing that a bzr dir
 
265
        exists anyway).
 
266
 
 
267
        This is the initial version of this method introduced to the smart
 
268
        server for 1.13.
 
269
 
 
270
        :param path: The path to the bzrdir.
 
271
        :param network_name: The network name of the branch type to create.
 
272
        :return: ('ok', branch_format, repo_path, rich_root, tree_ref,
 
273
            external_lookup, repo_format)
 
274
        """
 
275
        bzrdir = BzrDir.open_from_transport(
 
276
            self.transport_from_client_path(path))
 
277
        format = branch.network_format_registry.get(network_name)
 
278
        bzrdir.branch_format = format
 
279
        result = format.initialize(bzrdir, name="")
 
280
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
281
            result.repository._format)
 
282
        branch_format = result._format.network_name()
 
283
        repo_format = result.repository._format.network_name()
 
284
        repo_path = self._repo_relpath(bzrdir.root_transport,
 
285
            result.repository)
 
286
        # branch format, repo relpath, rich_root, tree_ref, external_lookup,
 
287
        # repo_network_name
 
288
        return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
 
289
            rich_root, tree_ref, external_lookup, repo_format))
 
290
 
 
291
 
 
292
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
 
293
 
 
294
    def do(self, path, network_name, shared):
 
295
        """Create a repository in the bzr dir at path.
 
296
 
 
297
        This operates precisely like 'bzrdir.create_repository'.
 
298
 
 
299
        If a bzrdir is not present, an exception is propagated
 
300
        rather than 'no branch' because these are different conditions (and
 
301
        this method should only be called after establishing that a bzr dir
 
302
        exists anyway).
 
303
 
 
304
        This is the initial version of this method introduced to the smart
 
305
        server for 1.13.
 
306
 
 
307
        :param path: The path to the bzrdir.
 
308
        :param network_name: The network name of the repository type to create.
 
309
        :param shared: The value to pass create_repository for the shared
 
310
            parameter.
 
311
        :return: (ok, rich_root, tree_ref, external_lookup, network_name)
 
312
        """
 
313
        bzrdir = BzrDir.open_from_transport(
 
314
            self.transport_from_client_path(path))
 
315
        shared = shared == 'True'
 
316
        format = repository.network_format_registry.get(network_name)
 
317
        bzrdir.repository_format = format
 
318
        result = format.initialize(bzrdir, shared=shared)
 
319
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
320
            result._format)
 
321
        return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
 
322
            external_lookup, result._format.network_name()))
 
323
 
 
324
 
 
325
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
 
326
 
 
327
    def _find(self, path):
 
328
        """try to find a repository from path upwards
 
329
 
 
330
        This operates precisely like 'bzrdir.find_repository'.
 
331
 
 
332
        :return: (relpath, rich_root, tree_ref, external_lookup, network_name).
 
333
            All are strings, relpath is a / prefixed path, the next three are
 
334
            either 'yes' or 'no', and the last is a repository format network
 
335
            name.
 
336
        :raises errors.NoRepositoryPresent: When there is no repository
 
337
            present.
 
338
        """
 
339
        bzrdir = BzrDir.open_from_transport(
 
340
            self.transport_from_client_path(path))
 
341
        repository = bzrdir.find_repository()
 
342
        path = self._repo_relpath(bzrdir.root_transport, repository)
 
343
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
344
            repository._format)
 
345
        network_name = repository._format.network_name()
 
346
        return path, rich_root, tree_ref, external_lookup, network_name
 
347
 
 
348
 
 
349
class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):
 
350
 
 
351
    def do(self, path):
 
352
        """try to find a repository from path upwards
 
353
 
 
354
        This operates precisely like 'bzrdir.find_repository'.
 
355
 
 
356
        If a bzrdir is not present, an exception is propagated
 
357
        rather than 'no branch' because these are different conditions.
 
358
 
 
359
        This is the initial version of this method introduced with the smart
 
360
        server. Modern clients will try the V2 method that adds support for the
 
361
        supports_external_lookups attribute.
 
362
 
 
363
        :return: norepository or ok, relpath.
 
364
        """
 
365
        try:
 
366
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
 
367
            return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
 
368
        except errors.NoRepositoryPresent:
 
369
            return FailedSmartServerResponse(('norepository', ))
 
370
 
 
371
 
 
372
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
 
373
 
 
374
    def do(self, path):
 
375
        """try to find a repository from path upwards
 
376
 
 
377
        This operates precisely like 'bzrdir.find_repository'.
 
378
 
 
379
        If a bzrdir is not present, an exception is propagated
 
380
        rather than 'no branch' because these are different conditions.
 
381
 
 
382
        This is the second edition of this method introduced in bzr 1.3, which
 
383
        returns information about the supports_external_lookups format
 
384
        attribute too.
 
385
 
 
386
        :return: norepository or ok, relpath, rich_root, tree_ref,
 
387
            external_lookup.
 
388
        """
 
389
        try:
 
390
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
 
391
            return SuccessfulSmartServerResponse(
 
392
                ('ok', path, rich_root, tree_ref, external_lookup))
 
393
        except errors.NoRepositoryPresent:
 
394
            return FailedSmartServerResponse(('norepository', ))
 
395
 
 
396
 
 
397
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
 
398
 
 
399
    def do(self, path):
 
400
        """try to find a repository from path upwards
 
401
 
 
402
        This operates precisely like 'bzrdir.find_repository'.
 
403
 
 
404
        If a bzrdir is not present, an exception is propogated
 
405
        rather than 'no branch' because these are different conditions.
 
406
 
 
407
        This is the third edition of this method introduced in bzr 1.13, which
 
408
        returns information about the network name of the repository format.
 
409
 
 
410
        :return: norepository or ok, relpath, rich_root, tree_ref,
 
411
            external_lookup, network_name.
 
412
        """
 
413
        try:
 
414
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
 
415
            return SuccessfulSmartServerResponse(
 
416
                ('ok', path, rich_root, tree_ref, external_lookup, name))
 
417
        except errors.NoRepositoryPresent:
 
418
            return FailedSmartServerResponse(('norepository', ))
 
419
 
 
420
 
 
421
class SmartServerBzrDirRequestConfigFile(SmartServerRequestBzrDir):
 
422
 
 
423
    def do_bzrdir_request(self):
 
424
        """Get the configuration bytes for a config file in bzrdir.
 
425
        
 
426
        The body is not utf8 decoded - it is the literal bytestream from disk.
 
427
        """
 
428
        config = self._bzrdir._get_config()
 
429
        if config is None:
 
430
            content = ''
 
431
        else:
 
432
            content = config._get_config_file().read()
 
433
        return SuccessfulSmartServerResponse((), content)
 
434
 
 
435
 
 
436
class SmartServerBzrDirRequestGetBranches(SmartServerRequestBzrDir):
 
437
 
 
438
    def do_bzrdir_request(self):
 
439
        """Get the branches in a control directory.
 
440
        
 
441
        The body is a bencoded dictionary, with values similar to the return
 
442
        value of the open branch request.
 
443
        """
 
444
        branches = self._bzrdir.get_branches()
 
445
        ret = {}
 
446
        for name, b in branches.items():
 
447
            if name is None:
 
448
                name = ""
 
449
            ret[name] = ("branch", b._format.network_name())
 
450
        return SuccessfulSmartServerResponse(
 
451
            ("success", ), bencode.bencode(ret))
 
452
 
 
453
 
 
454
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
 
455
 
 
456
    def do(self, path):
 
457
        """Initialize a bzrdir at path.
 
458
 
 
459
        The default format of the server is used.
 
460
        :return: SmartServerResponse(('ok', ))
 
461
        """
 
462
        target_transport = self.transport_from_client_path(path)
 
463
        BzrDirFormat.get_default_format().initialize_on_transport(target_transport)
 
464
        return SuccessfulSmartServerResponse(('ok', ))
 
465
 
 
466
 
 
467
class SmartServerRequestBzrDirInitializeEx(SmartServerRequestBzrDir):
 
468
 
 
469
    def parse_NoneTrueFalse(self, arg):
 
470
        if not arg:
 
471
            return None
 
472
        if arg == 'False':
 
473
            return False
 
474
        if arg == 'True':
 
475
            return True
 
476
        raise AssertionError("invalid arg %r" % arg)
 
477
 
 
478
    def parse_NoneString(self, arg):
 
479
        return arg or None
 
480
 
 
481
    def _serialize_NoneTrueFalse(self, arg):
 
482
        if arg is False:
 
483
            return 'False'
 
484
        if not arg:
 
485
            return ''
 
486
        return 'True'
 
487
 
 
488
    def do(self, bzrdir_network_name, path, use_existing_dir, create_prefix,
 
489
        force_new_repo, stacked_on, stack_on_pwd, repo_format_name,
 
490
        make_working_trees, shared_repo):
 
491
        """Initialize a bzrdir at path as per
 
492
        BzrDirFormat.initialize_on_transport_ex.
 
493
 
 
494
        New in 1.16.  (Replaces BzrDirFormat.initialize_ex verb from 1.15).
 
495
 
 
496
        :return: return SuccessfulSmartServerResponse((repo_path, rich_root,
 
497
            tree_ref, external_lookup, repo_network_name,
 
498
            repo_bzrdir_network_name, bzrdir_format_network_name,
 
499
            NoneTrueFalse(stacking), final_stack, final_stack_pwd,
 
500
            repo_lock_token))
 
501
        """
 
502
        target_transport = self.transport_from_client_path(path)
 
503
        format = network_format_registry.get(bzrdir_network_name)
 
504
        use_existing_dir = self.parse_NoneTrueFalse(use_existing_dir)
 
505
        create_prefix = self.parse_NoneTrueFalse(create_prefix)
 
506
        force_new_repo = self.parse_NoneTrueFalse(force_new_repo)
 
507
        stacked_on = self.parse_NoneString(stacked_on)
 
508
        stack_on_pwd = self.parse_NoneString(stack_on_pwd)
 
509
        make_working_trees = self.parse_NoneTrueFalse(make_working_trees)
 
510
        shared_repo = self.parse_NoneTrueFalse(shared_repo)
 
511
        if stack_on_pwd == '.':
 
512
            stack_on_pwd = target_transport.base
 
513
        repo_format_name = self.parse_NoneString(repo_format_name)
 
514
        repo, bzrdir, stacking, repository_policy = \
 
515
            format.initialize_on_transport_ex(target_transport,
 
516
            use_existing_dir=use_existing_dir, create_prefix=create_prefix,
 
517
            force_new_repo=force_new_repo, stacked_on=stacked_on,
 
518
            stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
 
519
            make_working_trees=make_working_trees, shared_repo=shared_repo)
 
520
        if repo is None:
 
521
            repo_path = ''
 
522
            repo_name = ''
 
523
            rich_root = tree_ref = external_lookup = ''
 
524
            repo_bzrdir_name = ''
 
525
            final_stack = None
 
526
            final_stack_pwd = None
 
527
            repo_lock_token = ''
 
528
        else:
 
529
            repo_path = self._repo_relpath(bzrdir.root_transport, repo)
 
530
            if repo_path == '':
 
531
                repo_path = '.'
 
532
            rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
533
                repo._format)
 
534
            repo_name = repo._format.network_name()
 
535
            repo_bzrdir_name = repo.controldir._format.network_name()
 
536
            final_stack = repository_policy._stack_on
 
537
            final_stack_pwd = repository_policy._stack_on_pwd
 
538
            # It is returned locked, but we need to do the lock to get the lock
 
539
            # token.
 
540
            repo.unlock()
 
541
            repo_lock_token = repo.lock_write().repository_token or ''
 
542
            if repo_lock_token:
 
543
                repo.leave_lock_in_place()
 
544
            repo.unlock()
 
545
        final_stack = final_stack or ''
 
546
        final_stack_pwd = final_stack_pwd or ''
 
547
 
 
548
        # We want this to be relative to the bzrdir.
 
549
        if final_stack_pwd:
 
550
            final_stack_pwd = urlutils.relative_url(
 
551
                target_transport.base, final_stack_pwd)
 
552
 
 
553
        # Can't meaningfully return a root path.
 
554
        if final_stack.startswith('/'):
 
555
            client_path = self._root_client_path + final_stack[1:]
 
556
            final_stack = urlutils.relative_url(
 
557
                self._root_client_path, client_path)
 
558
            final_stack_pwd = '.'
 
559
 
 
560
        return SuccessfulSmartServerResponse((repo_path, rich_root, tree_ref,
 
561
            external_lookup, repo_name, repo_bzrdir_name,
 
562
            bzrdir._format.network_name(),
 
563
            self._serialize_NoneTrueFalse(stacking), final_stack,
 
564
            final_stack_pwd, repo_lock_token))
 
565
 
 
566
 
 
567
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
 
568
 
 
569
    def do_bzrdir_request(self):
 
570
        """open a branch at path and return the branch reference or branch."""
 
571
        try:
 
572
            reference_url = self._bzrdir.get_branch_reference()
 
573
            if reference_url is None:
 
574
                return SuccessfulSmartServerResponse(('ok', ''))
 
575
            else:
 
576
                return SuccessfulSmartServerResponse(('ok', reference_url))
 
577
        except errors.NotBranchError as e:
 
578
            return FailedSmartServerResponse(('nobranch',))
 
579
 
 
580
 
 
581
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
 
582
 
 
583
    def do_bzrdir_request(self):
 
584
        """open a branch at path and return the reference or format."""
 
585
        try:
 
586
            reference_url = self._bzrdir.get_branch_reference()
 
587
            if reference_url is None:
 
588
                br = self._bzrdir.open_branch(ignore_fallbacks=True)
 
589
                format = br._format.network_name()
 
590
                return SuccessfulSmartServerResponse(('branch', format))
 
591
            else:
 
592
                return SuccessfulSmartServerResponse(('ref', reference_url))
 
593
        except errors.NotBranchError as e:
 
594
            return FailedSmartServerResponse(('nobranch',))
 
595
 
 
596
 
 
597
class SmartServerRequestOpenBranchV3(SmartServerRequestBzrDir):
 
598
 
 
599
    def do_bzrdir_request(self):
 
600
        """Open a branch at path and return the reference or format.
 
601
        
 
602
        This version introduced in 2.1.
 
603
 
 
604
        Differences to SmartServerRequestOpenBranchV2:
 
605
          * can return 2-element ('nobranch', extra), where 'extra' is a string
 
606
            with an explanation like 'location is a repository'.  Previously
 
607
            a 'nobranch' response would never have more than one element.
 
608
        """
 
609
        try:
 
610
            reference_url = self._bzrdir.get_branch_reference()
 
611
            if reference_url is None:
 
612
                br = self._bzrdir.open_branch(ignore_fallbacks=True)
 
613
                format = br._format.network_name()
 
614
                return SuccessfulSmartServerResponse(('branch', format))
 
615
            else:
 
616
                return SuccessfulSmartServerResponse(('ref', reference_url))
 
617
        except errors.NotBranchError as e:
 
618
            # Stringify the exception so that its .detail attribute will be
 
619
            # filled out.
 
620
            str(e)
 
621
            resp = ('nobranch',)
 
622
            detail = e.detail
 
623
            if detail:
 
624
                if detail.startswith(': '):
 
625
                    detail = detail[2:]
 
626
                resp += (detail,)
 
627
            return FailedSmartServerResponse(resp)
 
628