~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/bzrdir.py

merge merge tweaks from aaron, which includes latest .dev

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