~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/bzrdir.py

  • Committer: Patch Queue Manager
  • Date: 2012-01-18 16:23:31 UTC
  • mfrom: (6439.1.1 work)
  • Revision ID: pqm@pqm.ubuntu.com-20120118162331-md4sf1tw6hyuw344
(vila) Ensure people get an easy access to the release details from
 announcements. (Vincent Ladeuil)

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