~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/bzrdir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-08-31 00:27:39 UTC
  • mfrom: (4664.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090831002739-vd6487doda1b2k9h
(robertc) Fix bug 416732 by not adding root directories to expected
        items when checking non rich root repositories. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Server-side bzrdir related request implmentations."""
18
18
 
19
19
 
20
 
from bzrlib import errors
21
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
20
from bzrlib import branch, errors, repository, urlutils
 
21
from bzrlib.bzrdir import (
 
22
    BzrDir,
 
23
    BzrDirFormat,
 
24
    BzrDirMetaFormat1,
 
25
    network_format_registry,
 
26
    )
22
27
from bzrlib.smart.request import (
23
28
    FailedSmartServerResponse,
24
29
    SmartServerRequest,
51
56
        return SuccessfulSmartServerResponse((answer,))
52
57
 
53
58
 
54
 
class SmartServerRequestFindRepository(SmartServerRequest):
 
59
class SmartServerRequestBzrDir(SmartServerRequest):
 
60
 
 
61
    def do(self, path, *args):
 
62
        """Open a BzrDir at path, and return self.do_bzrdir_request(*args)."""
 
63
        try:
 
64
            self._bzrdir = BzrDir.open_from_transport(
 
65
                self.transport_from_client_path(path))
 
66
        except errors.NotBranchError:
 
67
            return FailedSmartServerResponse(('nobranch', ))
 
68
        return self.do_bzrdir_request(*args)
55
69
 
56
70
    def _boolean_to_yes_no(self, a_boolean):
57
71
        if a_boolean:
59
73
        else:
60
74
            return 'no'
61
75
 
62
 
    def _find(self, path):
63
 
        """try to find a repository from path upwards
64
 
        
65
 
        This operates precisely like 'bzrdir.find_repository'.
66
 
        
67
 
        :return: (relpath, rich_root, tree_ref, external_lookup) flags. All are
68
 
            strings, relpath is a / prefixed path, and the other three are
69
 
            either 'yes' or 'no'.
70
 
        :raises errors.NoRepositoryPresent: When there is no repository
71
 
            present.
72
 
        """
73
 
        bzrdir = BzrDir.open_from_transport(
74
 
            self.transport_from_client_path(path))
75
 
        repository = bzrdir.find_repository()
76
 
        # the relpath of the bzrdir in the found repository gives us the 
 
76
    def _format_to_capabilities(self, repo_format):
 
77
        rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
 
78
        tree_ref = self._boolean_to_yes_no(
 
79
            repo_format.supports_tree_reference)
 
80
        external_lookup = self._boolean_to_yes_no(
 
81
            repo_format.supports_external_lookups)
 
82
        return rich_root, tree_ref, external_lookup
 
83
 
 
84
    def _repo_relpath(self, current_transport, repository):
 
85
        """Get the relative path for repository from current_transport."""
 
86
        # the relpath of the bzrdir in the found repository gives us the
77
87
        # path segments to pop-out.
78
88
        relpath = repository.bzrdir.root_transport.relpath(
79
 
            bzrdir.root_transport.base)
 
89
            current_transport.base)
80
90
        if len(relpath):
81
91
            segments = ['..'] * len(relpath.split('/'))
82
92
        else:
83
93
            segments = []
84
 
        rich_root = self._boolean_to_yes_no(repository.supports_rich_root())
85
 
        tree_ref = self._boolean_to_yes_no(
86
 
            repository._format.supports_tree_reference)
87
 
        external_lookup = self._boolean_to_yes_no(
88
 
            repository._format.supports_external_lookups)
89
 
        return '/'.join(segments), rich_root, tree_ref, external_lookup
 
94
        return '/'.join(segments)
 
95
 
 
96
 
 
97
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
 
98
 
 
99
    def do_bzrdir_request(self, require_stacking):
 
100
        """Get the format that should be used when cloning from this dir.
 
101
 
 
102
        New in 1.13.
 
103
        
 
104
        :return: on success, a 3-tuple of network names for (control,
 
105
            repository, branch) directories, where '' signifies "not present".
 
106
            If this BzrDir contains a branch reference then this will fail with
 
107
            BranchReference; clients should resolve branch references before
 
108
            calling this RPC.
 
109
        """
 
110
        try:
 
111
            branch_ref = self._bzrdir.get_branch_reference()
 
112
        except errors.NotBranchError:
 
113
            branch_ref = None
 
114
        if branch_ref is not None:
 
115
            # The server shouldn't try to resolve references, and it quite
 
116
            # possibly can't reach them anyway.  The client needs to resolve
 
117
            # the branch reference to determine the cloning_metadir.
 
118
            return FailedSmartServerResponse(('BranchReference',))
 
119
        if require_stacking == "True":
 
120
            require_stacking = True
 
121
        else:
 
122
            require_stacking = False
 
123
        control_format = self._bzrdir.cloning_metadir(
 
124
            require_stacking=require_stacking)
 
125
        control_name = control_format.network_name()
 
126
        # XXX: There should be a method that tells us that the format does/does
 
127
        # not have subformats.
 
128
        if isinstance(control_format, BzrDirMetaFormat1):
 
129
            branch_name = ('branch',
 
130
                control_format.get_branch_format().network_name())
 
131
            repository_name = control_format.repository_format.network_name()
 
132
        else:
 
133
            # Only MetaDir has delegated formats today.
 
134
            branch_name = ('branch', '')
 
135
            repository_name = ''
 
136
        return SuccessfulSmartServerResponse((control_name, repository_name,
 
137
            branch_name))
 
138
 
 
139
 
 
140
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
 
141
 
 
142
    def do(self, path, network_name):
 
143
        """Create a branch in the bzr dir at path.
 
144
 
 
145
        This operates precisely like 'bzrdir.create_branch'.
 
146
 
 
147
        If a bzrdir is not present, an exception is propogated
 
148
        rather than 'no branch' because these are different conditions (and
 
149
        this method should only be called after establishing that a bzr dir
 
150
        exists anyway).
 
151
 
 
152
        This is the initial version of this method introduced to the smart
 
153
        server for 1.13.
 
154
 
 
155
        :param path: The path to the bzrdir.
 
156
        :param network_name: The network name of the branch type to create.
 
157
        :return: (ok, network_name)
 
158
        """
 
159
        bzrdir = BzrDir.open_from_transport(
 
160
            self.transport_from_client_path(path))
 
161
        format = branch.network_format_registry.get(network_name)
 
162
        bzrdir.branch_format = format
 
163
        result = format.initialize(bzrdir)
 
164
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
165
            result.repository._format)
 
166
        branch_format = result._format.network_name()
 
167
        repo_format = result.repository._format.network_name()
 
168
        repo_path = self._repo_relpath(bzrdir.root_transport,
 
169
            result.repository)
 
170
        # branch format, repo relpath, rich_root, tree_ref, external_lookup,
 
171
        # repo_network_name
 
172
        return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
 
173
            rich_root, tree_ref, external_lookup, repo_format))
 
174
 
 
175
 
 
176
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
 
177
 
 
178
    def do(self, path, network_name, shared):
 
179
        """Create a repository in the bzr dir at path.
 
180
 
 
181
        This operates precisely like 'bzrdir.create_repository'.
 
182
 
 
183
        If a bzrdir is not present, an exception is propagated
 
184
        rather than 'no branch' because these are different conditions (and
 
185
        this method should only be called after establishing that a bzr dir
 
186
        exists anyway).
 
187
 
 
188
        This is the initial version of this method introduced to the smart
 
189
        server for 1.13.
 
190
 
 
191
        :param path: The path to the bzrdir.
 
192
        :param network_name: The network name of the repository type to create.
 
193
        :param shared: The value to pass create_repository for the shared
 
194
            parameter.
 
195
        :return: (ok, rich_root, tree_ref, external_lookup, network_name)
 
196
        """
 
197
        bzrdir = BzrDir.open_from_transport(
 
198
            self.transport_from_client_path(path))
 
199
        shared = shared == 'True'
 
200
        format = repository.network_format_registry.get(network_name)
 
201
        bzrdir.repository_format = format
 
202
        result = format.initialize(bzrdir, shared=shared)
 
203
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
204
            result._format)
 
205
        return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
 
206
            external_lookup, result._format.network_name()))
 
207
 
 
208
 
 
209
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
 
210
 
 
211
    def _find(self, path):
 
212
        """try to find a repository from path upwards
 
213
 
 
214
        This operates precisely like 'bzrdir.find_repository'.
 
215
 
 
216
        :return: (relpath, rich_root, tree_ref, external_lookup, network_name).
 
217
            All are strings, relpath is a / prefixed path, the next three are
 
218
            either 'yes' or 'no', and the last is a repository format network
 
219
            name.
 
220
        :raises errors.NoRepositoryPresent: When there is no repository
 
221
            present.
 
222
        """
 
223
        bzrdir = BzrDir.open_from_transport(
 
224
            self.transport_from_client_path(path))
 
225
        repository = bzrdir.find_repository()
 
226
        path = self._repo_relpath(bzrdir.root_transport, repository)
 
227
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
228
            repository._format)
 
229
        network_name = repository._format.network_name()
 
230
        return path, rich_root, tree_ref, external_lookup, network_name
90
231
 
91
232
 
92
233
class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):
93
234
 
94
235
    def do(self, path):
95
236
        """try to find a repository from path upwards
96
 
        
 
237
 
97
238
        This operates precisely like 'bzrdir.find_repository'.
98
 
        
99
 
        If a bzrdir is not present, an exception is propogated
 
239
 
 
240
        If a bzrdir is not present, an exception is propagated
100
241
        rather than 'no branch' because these are different conditions.
101
242
 
102
243
        This is the initial version of this method introduced with the smart
106
247
        :return: norepository or ok, relpath.
107
248
        """
108
249
        try:
109
 
            path, rich_root, tree_ref, external_lookup = self._find(path)
 
250
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
110
251
            return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
111
252
        except errors.NoRepositoryPresent:
112
253
            return FailedSmartServerResponse(('norepository', ))
116
257
 
117
258
    def do(self, path):
118
259
        """try to find a repository from path upwards
119
 
        
 
260
 
120
261
        This operates precisely like 'bzrdir.find_repository'.
121
 
        
122
 
        If a bzrdir is not present, an exception is propogated
 
262
 
 
263
        If a bzrdir is not present, an exception is propagated
123
264
        rather than 'no branch' because these are different conditions.
124
265
 
125
266
        This is the second edition of this method introduced in bzr 1.3, which
126
267
        returns information about the supports_external_lookups format
127
268
        attribute too.
128
269
 
129
 
        :return: norepository or ok, relpath.
 
270
        :return: norepository or ok, relpath, rich_root, tree_ref,
 
271
            external_lookup.
130
272
        """
131
273
        try:
132
 
            path, rich_root, tree_ref, external_lookup = self._find(path)
 
274
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
133
275
            return SuccessfulSmartServerResponse(
134
276
                ('ok', path, rich_root, tree_ref, external_lookup))
135
277
        except errors.NoRepositoryPresent:
136
278
            return FailedSmartServerResponse(('norepository', ))
137
279
 
138
280
 
 
281
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
 
282
 
 
283
    def do(self, path):
 
284
        """try to find a repository from path upwards
 
285
 
 
286
        This operates precisely like 'bzrdir.find_repository'.
 
287
 
 
288
        If a bzrdir is not present, an exception is propogated
 
289
        rather than 'no branch' because these are different conditions.
 
290
 
 
291
        This is the third edition of this method introduced in bzr 1.13, which
 
292
        returns information about the network name of the repository format.
 
293
 
 
294
        :return: norepository or ok, relpath, rich_root, tree_ref,
 
295
            external_lookup, network_name.
 
296
        """
 
297
        try:
 
298
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
 
299
            return SuccessfulSmartServerResponse(
 
300
                ('ok', path, rich_root, tree_ref, external_lookup, name))
 
301
        except errors.NoRepositoryPresent:
 
302
            return FailedSmartServerResponse(('norepository', ))
 
303
 
 
304
 
 
305
class SmartServerBzrDirRequestConfigFile(SmartServerRequestBzrDir):
 
306
 
 
307
    def do_bzrdir_request(self):
 
308
        """Get the configuration bytes for a config file in bzrdir.
 
309
        
 
310
        The body is not utf8 decoded - it is the literal bytestream from disk.
 
311
        """
 
312
        config = self._bzrdir._get_config()
 
313
        if config is None:
 
314
            content = ''
 
315
        else:
 
316
            content = config._get_config_file().read()
 
317
        return SuccessfulSmartServerResponse((), content)
 
318
 
 
319
 
139
320
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
140
321
 
141
322
    def do(self, path):
149
330
        return SuccessfulSmartServerResponse(('ok', ))
150
331
 
151
332
 
152
 
class SmartServerRequestOpenBranch(SmartServerRequest):
153
 
 
154
 
    def do(self, path):
155
 
        """try to open a branch at path and return ok/nobranch.
156
 
        
157
 
        If a bzrdir is not present, an exception is propogated
158
 
        rather than 'no branch' because these are different conditions.
 
333
class SmartServerRequestBzrDirInitializeEx(SmartServerRequestBzrDir):
 
334
 
 
335
    def parse_NoneTrueFalse(self, arg):
 
336
        if not arg:
 
337
            return None
 
338
        if arg == 'False':
 
339
            return False
 
340
        if arg == 'True':
 
341
            return True
 
342
        raise AssertionError("invalid arg %r" % arg)
 
343
 
 
344
    def parse_NoneString(self, arg):
 
345
        return arg or None
 
346
 
 
347
    def _serialize_NoneTrueFalse(self, arg):
 
348
        if arg is False:
 
349
            return 'False'
 
350
        if not arg:
 
351
            return ''
 
352
        return 'True'
 
353
 
 
354
    def do(self, bzrdir_network_name, path, use_existing_dir, create_prefix,
 
355
        force_new_repo, stacked_on, stack_on_pwd, repo_format_name,
 
356
        make_working_trees, shared_repo):
 
357
        """Initialize a bzrdir at path as per
 
358
        BzrDirFormat.initialize_on_transport_ex.
 
359
 
 
360
        New in 1.16.  (Replaces BzrDirFormat.initialize_ex verb from 1.15).
 
361
 
 
362
        :return: return SuccessfulSmartServerResponse((repo_path, rich_root,
 
363
            tree_ref, external_lookup, repo_network_name,
 
364
            repo_bzrdir_network_name, bzrdir_format_network_name,
 
365
            NoneTrueFalse(stacking), final_stack, final_stack_pwd,
 
366
            repo_lock_token))
159
367
        """
160
 
        bzrdir = BzrDir.open_from_transport(
161
 
            self.transport_from_client_path(path))
 
368
        target_transport = self.transport_from_client_path(path)
 
369
        format = network_format_registry.get(bzrdir_network_name)
 
370
        use_existing_dir = self.parse_NoneTrueFalse(use_existing_dir)
 
371
        create_prefix = self.parse_NoneTrueFalse(create_prefix)
 
372
        force_new_repo = self.parse_NoneTrueFalse(force_new_repo)
 
373
        stacked_on = self.parse_NoneString(stacked_on)
 
374
        stack_on_pwd = self.parse_NoneString(stack_on_pwd)
 
375
        make_working_trees = self.parse_NoneTrueFalse(make_working_trees)
 
376
        shared_repo = self.parse_NoneTrueFalse(shared_repo)
 
377
        if stack_on_pwd == '.':
 
378
            stack_on_pwd = target_transport.base
 
379
        repo_format_name = self.parse_NoneString(repo_format_name)
 
380
        repo, bzrdir, stacking, repository_policy = \
 
381
            format.initialize_on_transport_ex(target_transport,
 
382
            use_existing_dir=use_existing_dir, create_prefix=create_prefix,
 
383
            force_new_repo=force_new_repo, stacked_on=stacked_on,
 
384
            stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
 
385
            make_working_trees=make_working_trees, shared_repo=shared_repo)
 
386
        if repo is None:
 
387
            repo_path = ''
 
388
            repo_name = ''
 
389
            rich_root = tree_ref = external_lookup = ''
 
390
            repo_bzrdir_name = ''
 
391
            final_stack = None
 
392
            final_stack_pwd = None
 
393
            repo_lock_token = ''
 
394
        else:
 
395
            repo_path = self._repo_relpath(bzrdir.root_transport, repo)
 
396
            if repo_path == '':
 
397
                repo_path = '.'
 
398
            rich_root, tree_ref, external_lookup = self._format_to_capabilities(
 
399
                repo._format)
 
400
            repo_name = repo._format.network_name()
 
401
            repo_bzrdir_name = repo.bzrdir._format.network_name()
 
402
            final_stack = repository_policy._stack_on
 
403
            final_stack_pwd = repository_policy._stack_on_pwd
 
404
            # It is returned locked, but we need to do the lock to get the lock
 
405
            # token.
 
406
            repo.unlock()
 
407
            repo_lock_token = repo.lock_write() or ''
 
408
            if repo_lock_token:
 
409
                repo.leave_lock_in_place()
 
410
            repo.unlock()
 
411
        final_stack = final_stack or ''
 
412
        final_stack_pwd = final_stack_pwd or ''
 
413
 
 
414
        # We want this to be relative to the bzrdir.
 
415
        if final_stack_pwd:
 
416
            final_stack_pwd = urlutils.relative_url(
 
417
                target_transport.base, final_stack_pwd)
 
418
 
 
419
        # Can't meaningfully return a root path.
 
420
        if final_stack.startswith('/'):
 
421
            client_path = self._root_client_path + final_stack[1:]
 
422
            final_stack = urlutils.relative_url(
 
423
                self._root_client_path, client_path)
 
424
            final_stack_pwd = '.'
 
425
 
 
426
        return SuccessfulSmartServerResponse((repo_path, rich_root, tree_ref,
 
427
            external_lookup, repo_name, repo_bzrdir_name,
 
428
            bzrdir._format.network_name(),
 
429
            self._serialize_NoneTrueFalse(stacking), final_stack,
 
430
            final_stack_pwd, repo_lock_token))
 
431
 
 
432
 
 
433
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
 
434
 
 
435
    def do_bzrdir_request(self):
 
436
        """open a branch at path and return the branch reference or branch."""
162
437
        try:
163
 
            reference_url = bzrdir.get_branch_reference()
 
438
            reference_url = self._bzrdir.get_branch_reference()
164
439
            if reference_url is None:
165
440
                return SuccessfulSmartServerResponse(('ok', ''))
166
441
            else:
167
442
                return SuccessfulSmartServerResponse(('ok', reference_url))
168
443
        except errors.NotBranchError:
169
444
            return FailedSmartServerResponse(('nobranch', ))
 
445
 
 
446
 
 
447
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
 
448
 
 
449
    def do_bzrdir_request(self):
 
450
        """open a branch at path and return the reference or format."""
 
451
        try:
 
452
            reference_url = self._bzrdir.get_branch_reference()
 
453
            if reference_url is None:
 
454
                br = self._bzrdir.open_branch(ignore_fallbacks=True)
 
455
                format = br._format.network_name()
 
456
                return SuccessfulSmartServerResponse(('branch', format))
 
457
            else:
 
458
                return SuccessfulSmartServerResponse(('ref', reference_url))
 
459
        except errors.NotBranchError:
 
460
            return FailedSmartServerResponse(('nobranch', ))