~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/bzrdir.py

  • Committer: Robert Collins
  • Date: 2009-03-26 23:16:06 UTC
  • mto: This revision was merged to the branch mainline in revision 4216.
  • Revision ID: robertc@robertcollins.net-20090326231606-rh98suac20x246pk
Review caught a bogus change to test_last_modified_revision_after_commit_link_unchanged_ric.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Server-side bzrdir related request implmentations."""
18
18
 
19
19
 
20
 
from bzrlib import branch, errors, repository, urlutils
21
 
from bzrlib.bzrdir import (
22
 
    BzrDir,
23
 
    BzrDirFormat,
24
 
    BzrDirMetaFormat1,
25
 
    BzrProber,
26
 
    )
27
 
from bzrlib.controldir import (
28
 
    network_format_registry,
29
 
    )
 
20
from bzrlib import branch, errors, repository
 
21
from bzrlib.bzrdir import BzrDir, BzrDirFormat, BzrDirMetaFormat1
30
22
from bzrlib.smart.request import (
31
23
    FailedSmartServerResponse,
32
24
    SmartServerRequest,
37
29
class SmartServerRequestOpenBzrDir(SmartServerRequest):
38
30
 
39
31
    def do(self, path):
 
32
        from bzrlib.bzrdir import BzrDirFormat
40
33
        try:
41
34
            t = self.transport_from_client_path(path)
42
35
        except errors.PathNotChild:
47
40
            # clients that don't anticipate errors from this method.
48
41
            answer = 'no'
49
42
        else:
50
 
            bzr_prober = BzrProber()
 
43
            default_format = BzrDirFormat.get_default_format()
 
44
            real_bzrdir = default_format.open(t, _found=True)
51
45
            try:
52
 
                bzr_prober.probe_transport(t)
 
46
                real_bzrdir._format.probe_transport(t)
53
47
            except (errors.NotBranchError, errors.UnknownFormatError):
54
48
                answer = 'no'
55
49
            else:
57
51
        return SuccessfulSmartServerResponse((answer,))
58
52
 
59
53
 
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
54
class SmartServerRequestBzrDir(SmartServerRequest):
87
55
 
88
56
    def do(self, path, *args):
89
 
        """Open a BzrDir at path, and return `self.do_bzrdir_request(*args)`."""
 
57
        """Open a BzrDir at path, and return self.do_bzrdir_request(*args)."""
90
58
        try:
91
59
            self._bzrdir = BzrDir.open_from_transport(
92
60
                self.transport_from_client_path(path))
93
 
        except errors.NotBranchError, e:
94
 
            return FailedSmartServerResponse(('nobranch',))
 
61
        except errors.NotBranchError:
 
62
            return FailedSmartServerResponse(('nobranch', ))
95
63
        return self.do_bzrdir_request(*args)
96
64
 
97
65
    def _boolean_to_yes_no(self, a_boolean):
112
80
        """Get the relative path for repository from current_transport."""
113
81
        # the relpath of the bzrdir in the found repository gives us the
114
82
        # path segments to pop-out.
115
 
        relpath = repository.user_transport.relpath(
 
83
        relpath = repository.bzrdir.root_transport.relpath(
116
84
            current_transport.base)
117
85
        if len(relpath):
118
86
            segments = ['..'] * len(relpath.split('/'))
124
92
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
125
93
 
126
94
    def do_bzrdir_request(self, require_stacking):
127
 
        """Get the format that should be used when cloning from this dir.
128
 
 
129
 
        New in 1.13.
130
 
        
131
 
        :return: on success, a 3-tuple of network names for (control,
132
 
            repository, branch) directories, where '' signifies "not present".
133
 
            If this BzrDir contains a branch reference then this will fail with
134
 
            BranchReference; clients should resolve branch references before
135
 
            calling this RPC.
136
 
        """
 
95
        """Get the format that should be used when cloning from this dir."""
137
96
        try:
138
97
            branch_ref = self._bzrdir.get_branch_reference()
139
98
        except errors.NotBranchError:
140
99
            branch_ref = None
141
 
        if branch_ref is not None:
142
 
            # The server shouldn't try to resolve references, and it quite
143
 
            # possibly can't reach them anyway.  The client needs to resolve
144
 
            # the branch reference to determine the cloning_metadir.
145
 
            return FailedSmartServerResponse(('BranchReference',))
146
100
        if require_stacking == "True":
147
101
            require_stacking = True
148
102
        else:
150
104
        control_format = self._bzrdir.cloning_metadir(
151
105
            require_stacking=require_stacking)
152
106
        control_name = control_format.network_name()
153
 
        # XXX: There should be a method that tells us that the format does/does
154
 
        # not have subformats.
 
107
        # XXX: There should be a method that tells us that the format does/does not
 
108
        # have subformats.
155
109
        if isinstance(control_format, BzrDirMetaFormat1):
156
 
            branch_name = ('branch',
157
 
                control_format.get_branch_format().network_name())
 
110
            if branch_ref is not None:
 
111
                # If there's a branch reference, the client will have to resolve
 
112
                # the branch reference to figure out the cloning metadir
 
113
                branch_name = ('ref', branch_ref)
 
114
            else:
 
115
                branch_name = ('branch',
 
116
                    control_format.get_branch_format().network_name())
158
117
            repository_name = control_format.repository_format.network_name()
159
118
        else:
160
119
            # Only MetaDir has delegated formats today.
181
140
 
182
141
        :param path: The path to the bzrdir.
183
142
        :param network_name: The network name of the branch type to create.
184
 
        :return: ('ok', branch_format, repo_path, rich_root, tree_ref,
185
 
            external_lookup, repo_format)
 
143
        :return: (ok, network_name)
186
144
        """
187
145
        bzrdir = BzrDir.open_from_transport(
188
146
            self.transport_from_client_path(path))
208
166
 
209
167
        This operates precisely like 'bzrdir.create_repository'.
210
168
 
211
 
        If a bzrdir is not present, an exception is propagated
 
169
        If a bzrdir is not present, an exception is propogated
212
170
        rather than 'no branch' because these are different conditions (and
213
171
        this method should only be called after establishing that a bzr dir
214
172
        exists anyway).
265
223
 
266
224
        This operates precisely like 'bzrdir.find_repository'.
267
225
 
268
 
        If a bzrdir is not present, an exception is propagated
 
226
        If a bzrdir is not present, an exception is propogated
269
227
        rather than 'no branch' because these are different conditions.
270
228
 
271
229
        This is the initial version of this method introduced with the smart
288
246
 
289
247
        This operates precisely like 'bzrdir.find_repository'.
290
248
 
291
 
        If a bzrdir is not present, an exception is propagated
 
249
        If a bzrdir is not present, an exception is propogated
292
250
        rather than 'no branch' because these are different conditions.
293
251
 
294
252
        This is the second edition of this method introduced in bzr 1.3, which
330
288
            return FailedSmartServerResponse(('norepository', ))
331
289
 
332
290
 
333
 
class SmartServerBzrDirRequestConfigFile(SmartServerRequestBzrDir):
334
 
 
335
 
    def do_bzrdir_request(self):
336
 
        """Get the configuration bytes for a config file in bzrdir.
337
 
        
338
 
        The body is not utf8 decoded - it is the literal bytestream from disk.
339
 
        """
340
 
        config = self._bzrdir._get_config()
341
 
        if config is None:
342
 
            content = ''
343
 
        else:
344
 
            content = config._get_config_file().read()
345
 
        return SuccessfulSmartServerResponse((), content)
346
 
 
347
 
 
348
291
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
349
292
 
350
293
    def do(self, path):
358
301
        return SuccessfulSmartServerResponse(('ok', ))
359
302
 
360
303
 
361
 
class SmartServerRequestBzrDirInitializeEx(SmartServerRequestBzrDir):
362
 
 
363
 
    def parse_NoneTrueFalse(self, arg):
364
 
        if not arg:
365
 
            return None
366
 
        if arg == 'False':
367
 
            return False
368
 
        if arg == 'True':
369
 
            return True
370
 
        raise AssertionError("invalid arg %r" % arg)
371
 
 
372
 
    def parse_NoneString(self, arg):
373
 
        return arg or None
374
 
 
375
 
    def _serialize_NoneTrueFalse(self, arg):
376
 
        if arg is False:
377
 
            return 'False'
378
 
        if not arg:
379
 
            return ''
380
 
        return 'True'
381
 
 
382
 
    def do(self, bzrdir_network_name, path, use_existing_dir, create_prefix,
383
 
        force_new_repo, stacked_on, stack_on_pwd, repo_format_name,
384
 
        make_working_trees, shared_repo):
385
 
        """Initialize a bzrdir at path as per
386
 
        BzrDirFormat.initialize_on_transport_ex.
387
 
 
388
 
        New in 1.16.  (Replaces BzrDirFormat.initialize_ex verb from 1.15).
389
 
 
390
 
        :return: return SuccessfulSmartServerResponse((repo_path, rich_root,
391
 
            tree_ref, external_lookup, repo_network_name,
392
 
            repo_bzrdir_network_name, bzrdir_format_network_name,
393
 
            NoneTrueFalse(stacking), final_stack, final_stack_pwd,
394
 
            repo_lock_token))
395
 
        """
396
 
        target_transport = self.transport_from_client_path(path)
397
 
        format = network_format_registry.get(bzrdir_network_name)
398
 
        use_existing_dir = self.parse_NoneTrueFalse(use_existing_dir)
399
 
        create_prefix = self.parse_NoneTrueFalse(create_prefix)
400
 
        force_new_repo = self.parse_NoneTrueFalse(force_new_repo)
401
 
        stacked_on = self.parse_NoneString(stacked_on)
402
 
        stack_on_pwd = self.parse_NoneString(stack_on_pwd)
403
 
        make_working_trees = self.parse_NoneTrueFalse(make_working_trees)
404
 
        shared_repo = self.parse_NoneTrueFalse(shared_repo)
405
 
        if stack_on_pwd == '.':
406
 
            stack_on_pwd = target_transport.base
407
 
        repo_format_name = self.parse_NoneString(repo_format_name)
408
 
        repo, bzrdir, stacking, repository_policy = \
409
 
            format.initialize_on_transport_ex(target_transport,
410
 
            use_existing_dir=use_existing_dir, create_prefix=create_prefix,
411
 
            force_new_repo=force_new_repo, stacked_on=stacked_on,
412
 
            stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
413
 
            make_working_trees=make_working_trees, shared_repo=shared_repo)
414
 
        if repo is None:
415
 
            repo_path = ''
416
 
            repo_name = ''
417
 
            rich_root = tree_ref = external_lookup = ''
418
 
            repo_bzrdir_name = ''
419
 
            final_stack = None
420
 
            final_stack_pwd = None
421
 
            repo_lock_token = ''
422
 
        else:
423
 
            repo_path = self._repo_relpath(bzrdir.root_transport, repo)
424
 
            if repo_path == '':
425
 
                repo_path = '.'
426
 
            rich_root, tree_ref, external_lookup = self._format_to_capabilities(
427
 
                repo._format)
428
 
            repo_name = repo._format.network_name()
429
 
            repo_bzrdir_name = repo.bzrdir._format.network_name()
430
 
            final_stack = repository_policy._stack_on
431
 
            final_stack_pwd = repository_policy._stack_on_pwd
432
 
            # It is returned locked, but we need to do the lock to get the lock
433
 
            # token.
434
 
            repo.unlock()
435
 
            repo_lock_token = repo.lock_write().repository_token or ''
436
 
            if repo_lock_token:
437
 
                repo.leave_lock_in_place()
438
 
            repo.unlock()
439
 
        final_stack = final_stack or ''
440
 
        final_stack_pwd = final_stack_pwd or ''
441
 
 
442
 
        # We want this to be relative to the bzrdir.
443
 
        if final_stack_pwd:
444
 
            final_stack_pwd = urlutils.relative_url(
445
 
                target_transport.base, final_stack_pwd)
446
 
 
447
 
        # Can't meaningfully return a root path.
448
 
        if final_stack.startswith('/'):
449
 
            client_path = self._root_client_path + final_stack[1:]
450
 
            final_stack = urlutils.relative_url(
451
 
                self._root_client_path, client_path)
452
 
            final_stack_pwd = '.'
453
 
 
454
 
        return SuccessfulSmartServerResponse((repo_path, rich_root, tree_ref,
455
 
            external_lookup, repo_name, repo_bzrdir_name,
456
 
            bzrdir._format.network_name(),
457
 
            self._serialize_NoneTrueFalse(stacking), final_stack,
458
 
            final_stack_pwd, repo_lock_token))
459
 
 
460
 
 
461
304
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
462
305
 
463
306
    def do_bzrdir_request(self):
468
311
                return SuccessfulSmartServerResponse(('ok', ''))
469
312
            else:
470
313
                return SuccessfulSmartServerResponse(('ok', reference_url))
471
 
        except errors.NotBranchError, e:
472
 
            return FailedSmartServerResponse(('nobranch',))
 
314
        except errors.NotBranchError:
 
315
            return FailedSmartServerResponse(('nobranch', ))
473
316
 
474
317
 
475
318
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
479
322
        try:
480
323
            reference_url = self._bzrdir.get_branch_reference()
481
324
            if reference_url is None:
482
 
                br = self._bzrdir.open_branch(ignore_fallbacks=True)
483
 
                format = br._format.network_name()
484
 
                return SuccessfulSmartServerResponse(('branch', format))
485
 
            else:
486
 
                return SuccessfulSmartServerResponse(('ref', reference_url))
487
 
        except errors.NotBranchError, e:
488
 
            return FailedSmartServerResponse(('nobranch',))
489
 
 
490
 
 
491
 
class SmartServerRequestOpenBranchV3(SmartServerRequestBzrDir):
492
 
 
493
 
    def do_bzrdir_request(self):
494
 
        """Open a branch at path and return the reference or format.
495
 
        
496
 
        This version introduced in 2.1.
497
 
 
498
 
        Differences to SmartServerRequestOpenBranchV2:
499
 
          * can return 2-element ('nobranch', extra), where 'extra' is a string
500
 
            with an explanation like 'location is a repository'.  Previously
501
 
            a 'nobranch' response would never have more than one element.
502
 
        """
503
 
        try:
504
 
            reference_url = self._bzrdir.get_branch_reference()
505
 
            if reference_url is None:
506
 
                br = self._bzrdir.open_branch(ignore_fallbacks=True)
507
 
                format = br._format.network_name()
508
 
                return SuccessfulSmartServerResponse(('branch', format))
509
 
            else:
510
 
                return SuccessfulSmartServerResponse(('ref', reference_url))
511
 
        except errors.NotBranchError, e:
512
 
            # Stringify the exception so that its .detail attribute will be
513
 
            # filled out.
514
 
            str(e)
515
 
            resp = ('nobranch',)
516
 
            detail = e.detail
517
 
            if detail:
518
 
                if detail.startswith(': '):
519
 
                    detail = detail[2:]
520
 
                resp += (detail,)
521
 
            return FailedSmartServerResponse(resp)
522
 
 
 
325
                format = self._bzrdir.open_branch()._format.network_name()
 
326
                return SuccessfulSmartServerResponse(('branch', format))
 
327
            else:
 
328
                return SuccessfulSmartServerResponse(('ref', reference_url))
 
329
        except errors.NotBranchError:
 
330
            return FailedSmartServerResponse(('nobranch', ))