~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/bzrdir.py

  • Committer: Aaron Bentley
  • Date: 2005-07-26 14:06:11 UTC
  • mto: (1092.1.41) (1185.3.4) (974.1.47)
  • mto: This revision was merged to the branch mainline in revision 982.
  • Revision ID: abentley@panoramicfeedback.com-20050726140611-403e366f3c79c1f1
Fixed python invocation

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