/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
from __future__ import absolute_import
 
18
 
17
19
import bz2
18
 
import os
19
 
import re
20
 
import sys
21
20
import zlib
22
21
 
23
 
from .. import (
 
22
from bzrlib import (
24
23
    bencode,
25
24
    branch,
26
 
    bzr as _mod_bzr,
 
25
    bzrdir as _mod_bzrdir,
27
26
    config as _mod_config,
28
27
    controldir,
29
28
    debug,
30
29
    errors,
31
30
    gpg,
32
31
    graph,
 
32
    inventory_delta,
33
33
    lock,
34
34
    lockdir,
35
35
    osutils,
36
36
    registry,
37
37
    repository as _mod_repository,
38
38
    revision as _mod_revision,
 
39
    static_tuple,
 
40
    symbol_versioning,
 
41
    testament as _mod_testament,
39
42
    urlutils,
40
 
    )
41
 
from . import (
42
 
    branch as bzrbranch,
43
 
    bzrdir as _mod_bzrdir,
44
 
    inventory_delta,
45
 
    testament as _mod_testament,
46
43
    vf_repository,
47
44
    vf_search,
48
45
    )
49
 
from .branch import BranchReferenceFormat
50
 
from ..branch import BranchWriteLockResult
51
 
from ..decorators import only_raises
52
 
from ..errors import (
 
46
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
 
47
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
48
from bzrlib.errors import (
53
49
    NoSuchRevision,
54
50
    SmartProtocolError,
55
51
    )
56
 
from ..i18n import gettext
57
 
from .inventory import Inventory
58
 
from .inventorytree import InventoryRevisionTree
59
 
from ..lockable_files import LockableFiles
60
 
from .smart import client, vfs, repository as smart_repo
61
 
from .smart.client import _SmartClient
62
 
from ..revision import NULL_REVISION
63
 
from ..repository import RepositoryWriteLockResult, _LazyListJoin
64
 
from .serializer import format_registry as serializer_format_registry
65
 
from ..trace import mutter, note, warning, log_exception_quietly
66
 
from .versionedfile import FulltextContentFactory
 
52
from bzrlib.i18n import gettext
 
53
from bzrlib.inventory import Inventory
 
54
from bzrlib.lockable_files import LockableFiles
 
55
from bzrlib.smart import client, vfs, repository as smart_repo
 
56
from bzrlib.smart.client import _SmartClient
 
57
from bzrlib.revision import NULL_REVISION
 
58
from bzrlib.revisiontree import InventoryRevisionTree
 
59
from bzrlib.repository import RepositoryWriteLockResult, _LazyListJoin
 
60
from bzrlib.serializer import format_registry as serializer_format_registry
 
61
from bzrlib.trace import mutter, note, warning, log_exception_quietly
 
62
from bzrlib.versionedfile import FulltextContentFactory
67
63
 
68
64
 
69
65
_DEFAULT_SEARCH_DEPTH = 100
75
71
    def _call(self, method, *args, **err_context):
76
72
        try:
77
73
            return self._client.call(method, *args)
78
 
        except errors.ErrorFromSmartServer as err:
 
74
        except errors.ErrorFromSmartServer, err:
79
75
            self._translate_error(err, **err_context)
80
76
 
81
77
    def _call_expecting_body(self, method, *args, **err_context):
82
78
        try:
83
79
            return self._client.call_expecting_body(method, *args)
84
 
        except errors.ErrorFromSmartServer as err:
 
80
        except errors.ErrorFromSmartServer, err:
85
81
            self._translate_error(err, **err_context)
86
82
 
87
83
    def _call_with_body_bytes(self, method, args, body_bytes, **err_context):
88
84
        try:
89
85
            return self._client.call_with_body_bytes(method, args, body_bytes)
90
 
        except errors.ErrorFromSmartServer as err:
 
86
        except errors.ErrorFromSmartServer, err:
91
87
            self._translate_error(err, **err_context)
92
88
 
93
89
    def _call_with_body_bytes_expecting_body(self, method, args, body_bytes,
95
91
        try:
96
92
            return self._client.call_with_body_bytes_expecting_body(
97
93
                method, args, body_bytes)
98
 
        except errors.ErrorFromSmartServer as err:
 
94
        except errors.ErrorFromSmartServer, err:
99
95
            self._translate_error(err, **err_context)
100
96
 
101
97
 
102
98
def response_tuple_to_repo_format(response):
103
99
    """Convert a response tuple describing a repository format to a format."""
104
100
    format = RemoteRepositoryFormat()
105
 
    format._rich_root_data = (response[0] == b'yes')
106
 
    format._supports_tree_reference = (response[1] == b'yes')
107
 
    format._supports_external_lookups = (response[2] == b'yes')
 
101
    format._rich_root_data = (response[0] == 'yes')
 
102
    format._supports_tree_reference = (response[1] == 'yes')
 
103
    format._supports_external_lookups = (response[2] == 'yes')
108
104
    format._network_name = response[3]
109
105
    return format
110
106
 
111
107
 
112
 
# Note that RemoteBzrDirProber lives in breezy.bzrdir so breezy.bzr.remote
 
108
# Note that RemoteBzrDirProber lives in bzrlib.bzrdir so bzrlib.remote
113
109
# does not have to be imported unless a remote format is involved.
114
110
 
115
111
class RemoteBzrDirFormat(_mod_bzrdir.BzrDirMetaFormat1):
129
125
 
130
126
    def __repr__(self):
131
127
        return "%s(_network_name=%r)" % (self.__class__.__name__,
132
 
                                         self._network_name)
 
128
            self._network_name)
133
129
 
134
130
    def get_format_description(self):
135
131
        if self._network_name:
136
132
            try:
137
133
                real_format = controldir.network_format_registry.get(
138
 
                    self._network_name)
 
134
                        self._network_name)
139
135
            except KeyError:
140
136
                pass
141
137
            else:
162
158
        client = _SmartClient(client_medium)
163
159
        path = client.remote_path_from_transport(transport)
164
160
        try:
165
 
            response = client.call(b'BzrDirFormat.initialize', path)
166
 
        except errors.ErrorFromSmartServer as err:
 
161
            response = client.call('BzrDirFormat.initialize', path)
 
162
        except errors.ErrorFromSmartServer, err:
167
163
            _translate_error(err, path=path)
168
 
        if response[0] != b'ok':
169
 
            raise errors.SmartProtocolError(
170
 
                'unexpected response code %s' % (response,))
 
164
        if response[0] != 'ok':
 
165
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
171
166
        format = RemoteBzrDirFormat()
172
167
        self._supply_sub_formats_to(format)
173
168
        return RemoteBzrDir(transport, format)
175
170
    def parse_NoneTrueFalse(self, arg):
176
171
        if not arg:
177
172
            return None
178
 
        if arg == b'False':
 
173
        if arg == 'False':
179
174
            return False
180
 
        if arg == b'True':
 
175
        if arg == 'True':
181
176
            return True
182
177
        raise AssertionError("invalid arg %r" % arg)
183
178
 
184
179
    def _serialize_NoneTrueFalse(self, arg):
185
180
        if arg is False:
186
 
            return b'False'
 
181
            return 'False'
187
182
        if arg:
188
 
            return b'True'
189
 
        return b''
 
183
            return 'True'
 
184
        return ''
190
185
 
191
186
    def _serialize_NoneString(self, arg):
192
 
        return arg or b''
 
187
        return arg or ''
193
188
 
194
189
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
195
 
                                   create_prefix=False, force_new_repo=False, stacked_on=None,
196
 
                                   stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
197
 
                                   shared_repo=False):
 
190
        create_prefix=False, force_new_repo=False, stacked_on=None,
 
191
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
 
192
        shared_repo=False):
198
193
        try:
199
194
            # hand off the request to the smart server
200
195
            client_medium = transport.get_smart_medium()
226
221
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
227
222
            self._supply_sub_formats_to(local_dir_format)
228
223
            return local_dir_format.initialize_on_transport_ex(transport,
229
 
                                                               use_existing_dir=use_existing_dir, create_prefix=create_prefix,
230
 
                                                               force_new_repo=force_new_repo, stacked_on=stacked_on,
231
 
                                                               stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
232
 
                                                               make_working_trees=make_working_trees, shared_repo=shared_repo,
233
 
                                                               vfs_only=True)
 
224
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
 
225
                force_new_repo=force_new_repo, stacked_on=stacked_on,
 
226
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
 
227
                make_working_trees=make_working_trees, shared_repo=shared_repo,
 
228
                vfs_only=True)
234
229
        return self._initialize_on_transport_ex_rpc(client, path, transport,
235
 
                                                    use_existing_dir, create_prefix, force_new_repo, stacked_on,
236
 
                                                    stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
 
230
            use_existing_dir, create_prefix, force_new_repo, stacked_on,
 
231
            stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
237
232
 
238
233
    def _initialize_on_transport_ex_rpc(self, client, path, transport,
239
 
                                        use_existing_dir, create_prefix, force_new_repo, stacked_on,
240
 
                                        stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
 
234
        use_existing_dir, create_prefix, force_new_repo, stacked_on,
 
235
        stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
241
236
        args = []
242
237
        args.append(self._serialize_NoneTrueFalse(use_existing_dir))
243
238
        args.append(self._serialize_NoneTrueFalse(create_prefix))
246
241
        # stack_on_pwd is often/usually our transport
247
242
        if stack_on_pwd:
248
243
            try:
249
 
                stack_on_pwd = transport.relpath(stack_on_pwd).encode('utf-8')
 
244
                stack_on_pwd = transport.relpath(stack_on_pwd)
250
245
                if not stack_on_pwd:
251
 
                    stack_on_pwd = b'.'
 
246
                    stack_on_pwd = '.'
252
247
            except errors.PathNotChild:
253
248
                pass
254
249
        args.append(self._serialize_NoneString(stack_on_pwd))
258
253
        request_network_name = self._network_name or \
259
254
            _mod_bzrdir.BzrDirFormat.get_default_format().network_name()
260
255
        try:
261
 
            response = client.call(b'BzrDirFormat.initialize_ex_1.16',
262
 
                                   request_network_name, path, *args)
 
256
            response = client.call('BzrDirFormat.initialize_ex_1.16',
 
257
                request_network_name, path, *args)
263
258
        except errors.UnknownSmartMethod:
264
 
            client._medium._remember_remote_is_before((1, 16))
 
259
            client._medium._remember_remote_is_before((1,16))
265
260
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
266
261
            self._supply_sub_formats_to(local_dir_format)
267
262
            return local_dir_format.initialize_on_transport_ex(transport,
268
 
                                                               use_existing_dir=use_existing_dir, create_prefix=create_prefix,
269
 
                                                               force_new_repo=force_new_repo, stacked_on=stacked_on,
270
 
                                                               stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
271
 
                                                               make_working_trees=make_working_trees, shared_repo=shared_repo,
272
 
                                                               vfs_only=True)
273
 
        except errors.ErrorFromSmartServer as err:
274
 
            _translate_error(err, path=path.decode('utf-8'))
 
263
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
 
264
                force_new_repo=force_new_repo, stacked_on=stacked_on,
 
265
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
 
266
                make_working_trees=make_working_trees, shared_repo=shared_repo,
 
267
                vfs_only=True)
 
268
        except errors.ErrorFromSmartServer, err:
 
269
            _translate_error(err, path=path)
275
270
        repo_path = response[0]
276
271
        bzrdir_name = response[6]
277
272
        require_stacking = response[7]
282
277
        bzrdir = RemoteBzrDir(transport, format, _client=client)
283
278
        if repo_path:
284
279
            repo_format = response_tuple_to_repo_format(response[1:])
285
 
            if repo_path == b'.':
286
 
                repo_path = b''
287
 
            repo_path = repo_path.decode('utf-8')
 
280
            if repo_path == '.':
 
281
                repo_path = ''
288
282
            if repo_path:
289
283
                repo_bzrdir_format = RemoteBzrDirFormat()
290
284
                repo_bzrdir_format._network_name = response[5]
291
285
                repo_bzr = RemoteBzrDir(transport.clone(repo_path),
292
 
                                        repo_bzrdir_format)
 
286
                    repo_bzrdir_format)
293
287
            else:
294
288
                repo_bzr = bzrdir
295
289
            final_stack = response[8] or None
296
 
            if final_stack:
297
 
                final_stack = final_stack.decode('utf-8')
298
290
            final_stack_pwd = response[9] or None
299
291
            if final_stack_pwd:
300
292
                final_stack_pwd = urlutils.join(
301
 
                    transport.base, final_stack_pwd.decode('utf-8'))
 
293
                    transport.base, final_stack_pwd)
302
294
            remote_repo = RemoteRepository(repo_bzr, repo_format)
303
295
            if len(response) > 10:
304
296
                # Updated server verb that locks remotely.
308
300
                    remote_repo.dont_leave_lock_in_place()
309
301
            else:
310
302
                remote_repo.lock_write()
311
 
            policy = _mod_bzrdir.UseExistingRepository(remote_repo,
312
 
                                                       final_stack, final_stack_pwd, require_stacking)
 
303
            policy = _mod_bzrdir.UseExistingRepository(remote_repo, final_stack,
 
304
                final_stack_pwd, require_stacking)
313
305
            policy.acquire_repository()
314
306
        else:
315
307
            remote_repo = None
356
348
        return result
357
349
 
358
350
    repository_format = property(__return_repository_format,
359
 
                                 _mod_bzrdir.BzrDirMetaFormat1._set_repository_format)  # .im_func)
 
351
        _mod_bzrdir.BzrDirMetaFormat1._set_repository_format) #.im_func)
360
352
 
361
353
 
362
354
class RemoteControlStore(_mod_config.IniFileStore):
367
359
 
368
360
    def __init__(self, bzrdir):
369
361
        super(RemoteControlStore, self).__init__()
370
 
        self.controldir = bzrdir
 
362
        self.bzrdir = bzrdir
371
363
        self._real_store = None
372
364
 
373
365
    def lock_write(self, token=None):
378
370
        self._ensure_real()
379
371
        return self._real_store.unlock()
380
372
 
 
373
    @needs_write_lock
381
374
    def save(self):
382
 
        with self.lock_write():
383
 
            # We need to be able to override the undecorated implementation
384
 
            self.save_without_locking()
 
375
        # We need to be able to override the undecorated implementation
 
376
        self.save_without_locking()
385
377
 
386
378
    def save_without_locking(self):
387
379
        super(RemoteControlStore, self).save()
388
380
 
389
381
    def _ensure_real(self):
390
 
        self.controldir._ensure_real()
 
382
        self.bzrdir._ensure_real()
391
383
        if self._real_store is None:
392
 
            self._real_store = _mod_config.ControlStore(self.controldir)
 
384
            self._real_store = _mod_config.ControlStore(self.bzrdir)
393
385
 
394
386
    def external_url(self):
395
387
        return urlutils.join(self.branch.user_url, 'control.conf')
396
388
 
397
389
    def _load_content(self):
398
 
        medium = self.controldir._client._medium
399
 
        path = self.controldir._path_for_remote_call(self.controldir._client)
 
390
        medium = self.bzrdir._client._medium
 
391
        path = self.bzrdir._path_for_remote_call(self.bzrdir._client)
400
392
        try:
401
 
            response, handler = self.controldir._call_expecting_body(
402
 
                b'BzrDir.get_config_file', path)
 
393
            response, handler = self.bzrdir._call_expecting_body(
 
394
                'BzrDir.get_config_file', path)
403
395
        except errors.UnknownSmartMethod:
404
396
            self._ensure_real()
405
397
            return self._real_store._load_content()
406
 
        if len(response) and response[0] != b'ok':
 
398
        if len(response) and response[0] != 'ok':
407
399
            raise errors.UnexpectedSmartServerResponse(response)
408
400
        return handler.read_body_bytes()
409
401
 
460
452
            self._rpc_open(path)
461
453
 
462
454
    def _rpc_open_2_1(self, path):
463
 
        response = self._call(b'BzrDir.open_2.1', path)
464
 
        if response == (b'no',):
 
455
        response = self._call('BzrDir.open_2.1', path)
 
456
        if response == ('no',):
465
457
            raise errors.NotBranchError(path=self.root_transport.base)
466
 
        elif response[0] == b'yes':
467
 
            if response[1] == b'yes':
 
458
        elif response[0] == 'yes':
 
459
            if response[1] == 'yes':
468
460
                self._has_working_tree = True
469
 
            elif response[1] == b'no':
 
461
            elif response[1] == 'no':
470
462
                self._has_working_tree = False
471
463
            else:
472
464
                raise errors.UnexpectedSmartServerResponse(response)
474
466
            raise errors.UnexpectedSmartServerResponse(response)
475
467
 
476
468
    def _rpc_open(self, path):
477
 
        response = self._call(b'BzrDir.open', path)
478
 
        if response not in [(b'yes',), (b'no',)]:
 
469
        response = self._call('BzrDir.open', path)
 
470
        if response not in [('yes',), ('no',)]:
479
471
            raise errors.UnexpectedSmartServerResponse(response)
480
 
        if response == (b'no',):
 
472
        if response == ('no',):
481
473
            raise errors.NotBranchError(path=self.root_transport.base)
482
474
 
483
475
    def _ensure_real(self):
489
481
            if 'hpssvfs' in debug.debug_flags:
490
482
                import traceback
491
483
                warning('VFS BzrDir access triggered\n%s',
492
 
                        ''.join(traceback.format_stack()))
 
484
                    ''.join(traceback.format_stack()))
493
485
            self._real_bzrdir = _mod_bzrdir.BzrDir.open_from_transport(
494
 
                self.root_transport, probers=[_mod_bzr.BzrProber])
 
486
                self.root_transport, probers=[_mod_bzrdir.BzrProber])
495
487
            self._format._network_name = \
496
488
                self._real_bzrdir._format.network_name()
497
489
 
516
508
            return self._vfs_checkout_metadir()
517
509
        path = self._path_for_remote_call(self._client)
518
510
        try:
519
 
            response = self._client.call(b'BzrDir.checkout_metadir',
520
 
                                         path)
 
511
            response = self._client.call('BzrDir.checkout_metadir',
 
512
                path)
521
513
        except errors.UnknownSmartMethod:
522
514
            medium._remember_remote_is_before((2, 5))
523
515
            return self._vfs_checkout_metadir()
528
520
            format = controldir.network_format_registry.get(control_name)
529
521
        except KeyError:
530
522
            raise errors.UnknownFormatError(kind='control',
531
 
                                            format=control_name)
 
523
                format=control_name)
532
524
        if repo_name:
533
525
            try:
534
526
                repo_format = _mod_repository.network_format_registry.get(
535
527
                    repo_name)
536
528
            except KeyError:
537
529
                raise errors.UnknownFormatError(kind='repository',
538
 
                                                format=repo_name)
 
530
                    format=repo_name)
539
531
            format.repository_format = repo_format
540
532
        if branch_name:
541
533
            try:
543
535
                    branch.network_format_registry.get(branch_name))
544
536
            except KeyError:
545
537
                raise errors.UnknownFormatError(kind='branch',
546
 
                                                format=branch_name)
 
538
                    format=branch_name)
547
539
        return format
548
540
 
549
541
    def _vfs_cloning_metadir(self, require_stacking=False):
555
547
        medium = self._client._medium
556
548
        if medium._is_remote_before((1, 13)):
557
549
            return self._vfs_cloning_metadir(require_stacking=require_stacking)
558
 
        verb = b'BzrDir.cloning_metadir'
 
550
        verb = 'BzrDir.cloning_metadir'
559
551
        if require_stacking:
560
 
            stacking = b'True'
 
552
            stacking = 'True'
561
553
        else:
562
 
            stacking = b'False'
 
554
            stacking = 'False'
563
555
        path = self._path_for_remote_call(self._client)
564
556
        try:
565
557
            response = self._call(verb, path, stacking)
566
558
        except errors.UnknownSmartMethod:
567
559
            medium._remember_remote_is_before((1, 13))
568
560
            return self._vfs_cloning_metadir(require_stacking=require_stacking)
569
 
        except errors.UnknownErrorFromSmartServer as err:
570
 
            if err.error_tuple != (b'BranchReference',):
 
561
        except errors.UnknownErrorFromSmartServer, err:
 
562
            if err.error_tuple != ('BranchReference',):
571
563
                raise
572
564
            # We need to resolve the branch reference to determine the
573
565
            # cloning_metadir.  This causes unnecessary RPCs to open the
574
566
            # referenced branch (and bzrdir, etc) but only when the caller
575
567
            # didn't already resolve the branch reference.
576
568
            referenced_branch = self.open_branch()
577
 
            return referenced_branch.controldir.cloning_metadir()
 
569
            return referenced_branch.bzrdir.cloning_metadir()
578
570
        if len(response) != 3:
579
571
            raise errors.UnexpectedSmartServerResponse(response)
580
572
        control_name, repo_name, branch_info = response
584
576
        try:
585
577
            format = controldir.network_format_registry.get(control_name)
586
578
        except KeyError:
587
 
            raise errors.UnknownFormatError(
588
 
                kind='control', format=control_name)
 
579
            raise errors.UnknownFormatError(kind='control', format=control_name)
589
580
 
590
581
        if repo_name:
591
582
            try:
593
584
                    repo_name)
594
585
            except KeyError:
595
586
                raise errors.UnknownFormatError(kind='repository',
596
 
                                                format=repo_name)
597
 
        if branch_ref == b'ref':
 
587
                    format=repo_name)
 
588
        if branch_ref == 'ref':
598
589
            # XXX: we need possible_transports here to avoid reopening the
599
590
            # connection to the referenced location
600
591
            ref_bzrdir = _mod_bzrdir.BzrDir.open(branch_name)
601
592
            branch_format = ref_bzrdir.cloning_metadir().get_branch_format()
602
593
            format.set_branch_format(branch_format)
603
 
        elif branch_ref == b'branch':
 
594
        elif branch_ref == 'branch':
604
595
            if branch_name:
605
596
                try:
606
597
                    branch_format = branch.network_format_registry.get(
607
598
                        branch_name)
608
599
                except KeyError:
609
600
                    raise errors.UnknownFormatError(kind='branch',
610
 
                                                    format=branch_name)
 
601
                        format=branch_name)
611
602
                format.set_branch_format(branch_format)
612
603
        else:
613
604
            raise errors.UnexpectedSmartServerResponse(response)
626
617
        """See BzrDir.destroy_repository"""
627
618
        path = self._path_for_remote_call(self._client)
628
619
        try:
629
 
            response = self._call(b'BzrDir.destroy_repository', path)
 
620
            response = self._call('BzrDir.destroy_repository', path)
630
621
        except errors.UnknownSmartMethod:
631
622
            self._ensure_real()
632
623
            self._real_bzrdir.destroy_repository()
633
624
            return
634
 
        if response[0] != b'ok':
635
 
            raise SmartProtocolError(
636
 
                'unexpected response code %s' % (response,))
 
625
        if response[0] != 'ok':
 
626
            raise SmartProtocolError('unexpected response code %s' % (response,))
637
627
 
638
628
    def create_branch(self, name=None, repository=None,
639
629
                      append_revisions_only=None):
644
634
        # as per meta1 formats - just delegate to the format object which may
645
635
        # be parameterised.
646
636
        real_branch = self._format.get_branch_format().initialize(self,
647
 
                                                                  name=name, repository=repository,
648
 
                                                                  append_revisions_only=append_revisions_only)
 
637
            name=name, repository=repository,
 
638
            append_revisions_only=append_revisions_only)
649
639
        if not isinstance(real_branch, RemoteBranch):
650
640
            if not isinstance(repository, RemoteRepository):
651
641
                raise AssertionError(
675
665
                args = (name, )
676
666
            else:
677
667
                args = ()
678
 
            response = self._call(b'BzrDir.destroy_branch', path, *args)
 
668
            response = self._call('BzrDir.destroy_branch', path, *args)
679
669
        except errors.UnknownSmartMethod:
680
670
            self._ensure_real()
681
671
            self._real_bzrdir.destroy_branch(name=name)
682
672
            self._next_open_branch_result = None
683
673
            return
684
674
        self._next_open_branch_result = None
685
 
        if response[0] != b'ok':
686
 
            raise SmartProtocolError(
687
 
                'unexpected response code %s' % (response,))
 
675
        if response[0] != 'ok':
 
676
            raise SmartProtocolError('unexpected response code %s' % (response,))
688
677
 
689
678
    def create_workingtree(self, revision_id=None, from_branch=None,
690
 
                           accelerator_tree=None, hardlink=False):
 
679
        accelerator_tree=None, hardlink=False):
691
680
        raise errors.NotLocalUrl(self.transport.base)
692
681
 
693
682
    def find_branch_format(self, name=None):
698
687
        b = self.open_branch(name=name)
699
688
        return b._format
700
689
 
701
 
    def branch_names(self):
702
 
        path = self._path_for_remote_call(self._client)
703
 
        try:
704
 
            response, handler = self._call_expecting_body(
705
 
                b'BzrDir.get_branches', path)
706
 
        except errors.UnknownSmartMethod:
707
 
            self._ensure_real()
708
 
            return self._real_bzrdir.branch_names()
709
 
        if response[0] != b"success":
710
 
            raise errors.UnexpectedSmartServerResponse(response)
711
 
        body = bencode.bdecode(handler.read_body_bytes())
712
 
        ret = []
713
 
        for name, value in body.items():
714
 
            name = name.decode('utf-8')
715
 
            ret.append(name)
716
 
        return ret
717
 
 
718
690
    def get_branches(self, possible_transports=None, ignore_fallbacks=False):
719
691
        path = self._path_for_remote_call(self._client)
720
692
        try:
721
693
            response, handler = self._call_expecting_body(
722
 
                b'BzrDir.get_branches', path)
 
694
                'BzrDir.get_branches', path)
723
695
        except errors.UnknownSmartMethod:
724
696
            self._ensure_real()
725
697
            return self._real_bzrdir.get_branches()
726
 
        if response[0] != b"success":
 
698
        if response[0] != "success":
727
699
            raise errors.UnexpectedSmartServerResponse(response)
728
700
        body = bencode.bdecode(handler.read_body_bytes())
729
701
        ret = {}
730
 
        for name, value in body.items():
731
 
            name = name.decode('utf-8')
732
 
            ret[name] = self._open_branch(
733
 
                name, value[0].decode('ascii'), value[1],
 
702
        for (name, value) in body.iteritems():
 
703
            ret[name] = self._open_branch(name, value[0], value[1],
734
704
                possible_transports=possible_transports,
735
705
                ignore_fallbacks=ignore_fallbacks)
736
706
        return ret
752
722
            raise errors.NoColocatedBranchSupport(self)
753
723
        response = self._get_branch_reference()
754
724
        if response[0] == 'ref':
755
 
            return response[1].decode('utf-8')
 
725
            return response[1]
756
726
        else:
757
727
            return None
758
728
 
759
729
    def _get_branch_reference(self):
760
 
        """Get branch reference information
761
 
 
762
 
        :return: Tuple with (kind, location_or_format)
763
 
            if kind == 'ref', then location_or_format contains a location
764
 
            otherwise, it contains a format name
765
 
        """
766
730
        path = self._path_for_remote_call(self._client)
767
731
        medium = self._client._medium
768
732
        candidate_calls = [
769
 
            (b'BzrDir.open_branchV3', (2, 1)),
770
 
            (b'BzrDir.open_branchV2', (1, 13)),
771
 
            (b'BzrDir.open_branch', None),
 
733
            ('BzrDir.open_branchV3', (2, 1)),
 
734
            ('BzrDir.open_branchV2', (1, 13)),
 
735
            ('BzrDir.open_branch', None),
772
736
            ]
773
737
        for verb, required_version in candidate_calls:
774
738
            if required_version and medium._is_remote_before(required_version):
781
745
                medium._remember_remote_is_before(required_version)
782
746
            else:
783
747
                break
784
 
        if verb == b'BzrDir.open_branch':
785
 
            if response[0] != b'ok':
 
748
        if verb == 'BzrDir.open_branch':
 
749
            if response[0] != 'ok':
786
750
                raise errors.UnexpectedSmartServerResponse(response)
787
 
            if response[1] != b'':
 
751
            if response[1] != '':
788
752
                return ('ref', response[1])
789
753
            else:
790
 
                return ('branch', b'')
791
 
        if response[0] not in (b'ref', b'branch'):
 
754
                return ('branch', '')
 
755
        if response[0] not in ('ref', 'branch'):
792
756
            raise errors.UnexpectedSmartServerResponse(response)
793
 
        return (response[0].decode('ascii'), response[1])
 
757
        return response
794
758
 
795
759
    def _get_tree_branch(self, name=None):
796
760
        """See BzrDir._get_tree_branch()."""
801
765
        if kind == 'ref':
802
766
            # a branch reference, use the existing BranchReference logic.
803
767
            format = BranchReferenceFormat()
804
 
            ref_loc = urlutils.join(self.user_url, location_or_format.decode('utf-8'))
805
768
            return format.open(self, name=name, _found=True,
806
 
                               location=ref_loc,
807
 
                               ignore_fallbacks=ignore_fallbacks,
808
 
                               possible_transports=possible_transports)
 
769
                location=location_or_format, ignore_fallbacks=ignore_fallbacks,
 
770
                possible_transports=possible_transports)
809
771
        branch_format_name = location_or_format
810
772
        if not branch_format_name:
811
773
            branch_format_name = None
812
774
        format = RemoteBranchFormat(network_name=branch_format_name)
813
775
        return RemoteBranch(self, self.find_repository(), format=format,
814
 
                            setup_stacking=not ignore_fallbacks, name=name,
815
 
                            possible_transports=possible_transports)
 
776
            setup_stacking=not ignore_fallbacks, name=name,
 
777
            possible_transports=possible_transports)
816
778
 
817
779
    def open_branch(self, name=None, unsupported=False,
818
780
                    ignore_fallbacks=False, possible_transports=None):
821
783
        if name != "":
822
784
            raise errors.NoColocatedBranchSupport(self)
823
785
        if unsupported:
824
 
            raise NotImplementedError(
825
 
                'unsupported flag support not implemented yet.')
 
786
            raise NotImplementedError('unsupported flag support not implemented yet.')
826
787
        if self._next_open_branch_result is not None:
827
788
            # See create_branch for details.
828
789
            result = self._next_open_branch_result
830
791
            return result
831
792
        response = self._get_branch_reference()
832
793
        return self._open_branch(name, response[0], response[1],
833
 
                                 possible_transports=possible_transports,
834
 
                                 ignore_fallbacks=ignore_fallbacks)
 
794
            possible_transports=possible_transports,
 
795
            ignore_fallbacks=ignore_fallbacks)
835
796
 
836
797
    def _open_repo_v1(self, path):
837
 
        verb = b'BzrDir.find_repository'
 
798
        verb = 'BzrDir.find_repository'
838
799
        response = self._call(verb, path)
839
 
        if response[0] != b'ok':
 
800
        if response[0] != 'ok':
840
801
            raise errors.UnexpectedSmartServerResponse(response)
841
802
        # servers that only support the v1 method don't support external
842
803
        # references either.
843
804
        self._ensure_real()
844
805
        repo = self._real_bzrdir.open_repository()
845
 
        response = response + (b'no', repo._format.network_name())
 
806
        response = response + ('no', repo._format.network_name())
846
807
        return response, repo
847
808
 
848
809
    def _open_repo_v2(self, path):
849
 
        verb = b'BzrDir.find_repositoryV2'
 
810
        verb = 'BzrDir.find_repositoryV2'
850
811
        response = self._call(verb, path)
851
 
        if response[0] != b'ok':
 
812
        if response[0] != 'ok':
852
813
            raise errors.UnexpectedSmartServerResponse(response)
853
814
        self._ensure_real()
854
815
        repo = self._real_bzrdir.open_repository()
856
817
        return response, repo
857
818
 
858
819
    def _open_repo_v3(self, path):
859
 
        verb = b'BzrDir.find_repositoryV3'
 
820
        verb = 'BzrDir.find_repositoryV3'
860
821
        medium = self._client._medium
861
822
        if medium._is_remote_before((1, 13)):
862
823
            raise errors.UnknownSmartMethod(verb)
865
826
        except errors.UnknownSmartMethod:
866
827
            medium._remember_remote_is_before((1, 13))
867
828
            raise
868
 
        if response[0] != b'ok':
 
829
        if response[0] != 'ok':
869
830
            raise errors.UnexpectedSmartServerResponse(response)
870
831
        return response, None
871
832
 
873
834
        path = self._path_for_remote_call(self._client)
874
835
        response = None
875
836
        for probe in [self._open_repo_v3, self._open_repo_v2,
876
 
                      self._open_repo_v1]:
 
837
            self._open_repo_v1]:
877
838
            try:
878
839
                response, real_repo = probe(path)
879
840
                break
880
841
            except errors.UnknownSmartMethod:
881
842
                pass
882
843
        if response is None:
883
 
            raise errors.UnknownSmartMethod(b'BzrDir.find_repository{3,2,}')
884
 
        if response[0] != b'ok':
 
844
            raise errors.UnknownSmartMethod('BzrDir.find_repository{3,2,}')
 
845
        if response[0] != 'ok':
885
846
            raise errors.UnexpectedSmartServerResponse(response)
886
847
        if len(response) != 6:
887
 
            raise SmartProtocolError(
888
 
                'incorrect response length %s' % (response,))
889
 
        if response[1] == b'':
 
848
            raise SmartProtocolError('incorrect response length %s' % (response,))
 
849
        if response[1] == '':
890
850
            # repo is at this dir.
891
851
            format = response_tuple_to_repo_format(response[2:])
892
852
            # Used to support creating a real format instance when needed.
903
863
        if self._has_working_tree is None:
904
864
            path = self._path_for_remote_call(self._client)
905
865
            try:
906
 
                response = self._call(b'BzrDir.has_workingtree', path)
 
866
                response = self._call('BzrDir.has_workingtree', path)
907
867
            except errors.UnknownSmartMethod:
908
868
                self._ensure_real()
909
869
                self._has_working_tree = self._real_bzrdir.has_workingtree()
910
870
            else:
911
 
                if response[0] not in (b'yes', b'no'):
912
 
                    raise SmartProtocolError(
913
 
                        'unexpected response code %s' % (response,))
914
 
                self._has_working_tree = (response[0] == b'yes')
 
871
                if response[0] not in ('yes', 'no'):
 
872
                    raise SmartProtocolError('unexpected response code %s' % (response,))
 
873
                self._has_working_tree = (response[0] == 'yes')
915
874
        return self._has_working_tree
916
875
 
917
876
    def open_workingtree(self, recommend_upgrade=True):
922
881
 
923
882
    def _path_for_remote_call(self, client):
924
883
        """Return the path to be used for this bzrdir in a remote call."""
925
 
        remote_path = client.remote_path_from_transport(self.root_transport)
926
 
        remote_path = remote_path.decode('utf-8')
927
 
        base_url, segment_parameters = urlutils.split_segment_parameters_raw(
928
 
            remote_path)
929
 
        base_url = base_url.encode('utf-8')
930
 
        return base_url
 
884
        return urlutils.split_segment_parameters_raw(
 
885
            client.remote_path_from_transport(self.root_transport))[0]
931
886
 
932
887
    def get_branch_transport(self, branch_format, name=None):
933
888
        self._ensure_real()
956
911
        return RemoteControlStore(self)
957
912
 
958
913
 
959
 
class RemoteInventoryTree(InventoryRevisionTree):
960
 
 
961
 
    def __init__(self, repository, inv, revision_id):
962
 
        super(RemoteInventoryTree, self).__init__(repository, inv, revision_id)
963
 
 
964
 
    def archive(self, format, name, root=None, subdir=None, force_mtime=None):
965
 
        ret = self._repository._revision_archive(
966
 
            self.get_revision_id(), format, name, root, subdir,
967
 
            force_mtime=force_mtime)
968
 
        if ret is None:
969
 
            return super(RemoteInventoryTree, self).archive(
970
 
                format, name, root, subdir, force_mtime=force_mtime)
971
 
        return ret
972
 
 
973
 
    def annotate_iter(self, path,
974
 
                      default_revision=_mod_revision.CURRENT_REVISION):
975
 
        """Return an iterator of revision_id, line tuples.
976
 
 
977
 
        For working trees (and mutable trees in general), the special
978
 
        revision_id 'current:' will be used for lines that are new in this
979
 
        tree, e.g. uncommitted changes.
980
 
        :param default_revision: For lines that don't match a basis, mark them
981
 
            with this revision id. Not all implementations will make use of
982
 
            this value.
983
 
        """
984
 
        ret = self._repository._annotate_file_revision(
985
 
            self.get_revision_id(), path, file_id=None,
986
 
            default_revision=default_revision)
987
 
        if ret is None:
988
 
            return super(RemoteInventoryTree, self).annotate_iter(
989
 
                path, default_revision=default_revision)
990
 
        return ret
991
 
 
992
 
 
993
914
class RemoteRepositoryFormat(vf_repository.VersionedFileRepositoryFormat):
994
915
    """Format for repositories accessed over a _SmartClient.
995
916
 
1010
931
        to obtain data like the network name.
1011
932
    """
1012
933
 
1013
 
    _matchingcontroldir = RemoteBzrDirFormat()
 
934
    _matchingbzrdir = RemoteBzrDirFormat()
1014
935
    supports_full_versioned_files = True
1015
936
    supports_leaving_lock = True
1016
 
    supports_overriding_transport = False
1017
937
 
1018
938
    def __init__(self):
1019
939
        _mod_repository.RepositoryFormat.__init__(self)
1030
950
 
1031
951
    def __repr__(self):
1032
952
        return "%s(_network_name=%r)" % (self.__class__.__name__,
1033
 
                                         self._network_name)
 
953
            self._network_name)
1034
954
 
1035
955
    @property
1036
956
    def fast_deltas(self):
1091
1011
                self._custom_format.revision_graph_can_have_wrong_parents
1092
1012
        return self._revision_graph_can_have_wrong_parents
1093
1013
 
1094
 
    def _vfs_initialize(self, a_controldir, shared):
 
1014
    def _vfs_initialize(self, a_bzrdir, shared):
1095
1015
        """Helper for common code in initialize."""
1096
1016
        if self._custom_format:
1097
1017
            # Custom format requested
1098
 
            result = self._custom_format.initialize(
1099
 
                a_controldir, shared=shared)
 
1018
            result = self._custom_format.initialize(a_bzrdir, shared=shared)
1100
1019
        elif self._creating_bzrdir is not None:
1101
1020
            # Use the format that the repository we were created to back
1102
1021
            # has.
1103
1022
            prior_repo = self._creating_bzrdir.open_repository()
1104
1023
            prior_repo._ensure_real()
1105
1024
            result = prior_repo._real_repository._format.initialize(
1106
 
                a_controldir, shared=shared)
 
1025
                a_bzrdir, shared=shared)
1107
1026
        else:
1108
1027
            # assume that a_bzr is a RemoteBzrDir but the smart server didn't
1109
1028
            # support remote initialization.
1110
1029
            # We delegate to a real object at this point (as RemoteBzrDir
1111
1030
            # delegate to the repository format which would lead to infinite
1112
 
            # recursion if we just called a_controldir.create_repository.
1113
 
            a_controldir._ensure_real()
1114
 
            result = a_controldir._real_bzrdir.create_repository(shared=shared)
 
1031
            # recursion if we just called a_bzrdir.create_repository.
 
1032
            a_bzrdir._ensure_real()
 
1033
            result = a_bzrdir._real_bzrdir.create_repository(shared=shared)
1115
1034
        if not isinstance(result, RemoteRepository):
1116
 
            return self.open(a_controldir)
 
1035
            return self.open(a_bzrdir)
1117
1036
        else:
1118
1037
            return result
1119
1038
 
1120
 
    def initialize(self, a_controldir, shared=False):
 
1039
    def initialize(self, a_bzrdir, shared=False):
1121
1040
        # Being asked to create on a non RemoteBzrDir:
1122
 
        if not isinstance(a_controldir, RemoteBzrDir):
1123
 
            return self._vfs_initialize(a_controldir, shared)
1124
 
        medium = a_controldir._client._medium
 
1041
        if not isinstance(a_bzrdir, RemoteBzrDir):
 
1042
            return self._vfs_initialize(a_bzrdir, shared)
 
1043
        medium = a_bzrdir._client._medium
1125
1044
        if medium._is_remote_before((1, 13)):
1126
 
            return self._vfs_initialize(a_controldir, shared)
 
1045
            return self._vfs_initialize(a_bzrdir, shared)
1127
1046
        # Creating on a remote bzr dir.
1128
1047
        # 1) get the network name to use.
1129
1048
        if self._custom_format:
1131
1050
        elif self._network_name:
1132
1051
            network_name = self._network_name
1133
1052
        else:
1134
 
            # Select the current breezy default and ask for that.
1135
 
            reference_bzrdir_format = controldir.format_registry.get(
1136
 
                'default')()
 
1053
            # Select the current bzrlib default and ask for that.
 
1054
            reference_bzrdir_format = controldir.format_registry.get('default')()
1137
1055
            reference_format = reference_bzrdir_format.repository_format
1138
1056
            network_name = reference_format.network_name()
1139
1057
        # 2) try direct creation via RPC
1140
 
        path = a_controldir._path_for_remote_call(a_controldir._client)
1141
 
        verb = b'BzrDir.create_repository'
 
1058
        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
 
1059
        verb = 'BzrDir.create_repository'
1142
1060
        if shared:
1143
 
            shared_str = b'True'
 
1061
            shared_str = 'True'
1144
1062
        else:
1145
 
            shared_str = b'False'
 
1063
            shared_str = 'False'
1146
1064
        try:
1147
 
            response = a_controldir._call(verb, path, network_name, shared_str)
 
1065
            response = a_bzrdir._call(verb, path, network_name, shared_str)
1148
1066
        except errors.UnknownSmartMethod:
1149
1067
            # Fallback - use vfs methods
1150
1068
            medium._remember_remote_is_before((1, 13))
1151
 
            return self._vfs_initialize(a_controldir, shared)
 
1069
            return self._vfs_initialize(a_bzrdir, shared)
1152
1070
        else:
1153
1071
            # Turn the response into a RemoteRepository object.
1154
1072
            format = response_tuple_to_repo_format(response[1:])
1155
1073
            # Used to support creating a real format instance when needed.
1156
 
            format._creating_bzrdir = a_controldir
1157
 
            remote_repo = RemoteRepository(a_controldir, format)
 
1074
            format._creating_bzrdir = a_bzrdir
 
1075
            remote_repo = RemoteRepository(a_bzrdir, format)
1158
1076
            format._creating_repo = remote_repo
1159
1077
            return remote_repo
1160
1078
 
1161
 
    def open(self, a_controldir):
1162
 
        if not isinstance(a_controldir, RemoteBzrDir):
1163
 
            raise AssertionError('%r is not a RemoteBzrDir' % (a_controldir,))
1164
 
        return a_controldir.open_repository()
 
1079
    def open(self, a_bzrdir):
 
1080
        if not isinstance(a_bzrdir, RemoteBzrDir):
 
1081
            raise AssertionError('%r is not a RemoteBzrDir' % (a_bzrdir,))
 
1082
        return a_bzrdir.open_repository()
1165
1083
 
1166
1084
    def _ensure_real(self):
1167
1085
        if self._custom_format is None:
1170
1088
                    self._network_name)
1171
1089
            except KeyError:
1172
1090
                raise errors.UnknownFormatError(kind='repository',
1173
 
                                                format=self._network_name)
 
1091
                    format=self._network_name)
1174
1092
 
1175
1093
    @property
1176
1094
    def _fetch_order(self):
1212
1130
 
1213
1131
 
1214
1132
class RemoteRepository(_mod_repository.Repository, _RpcHelper,
1215
 
                       lock._RelockDebugMixin):
 
1133
        lock._RelockDebugMixin):
1216
1134
    """Repository accessed over rpc.
1217
1135
 
1218
1136
    For the moment most operations are performed using local transport-backed
1234
1152
            self._real_repository = real_repository
1235
1153
        else:
1236
1154
            self._real_repository = None
1237
 
        self.controldir = remote_bzrdir
 
1155
        self.bzrdir = remote_bzrdir
1238
1156
        if _client is None:
1239
1157
            self._client = remote_bzrdir._client
1240
1158
        else:
1258
1176
        self._reconcile_does_inventory_gc = False
1259
1177
        self._reconcile_fixes_text_parents = False
1260
1178
        self._reconcile_backsup_inventory = False
1261
 
        self.base = self.controldir.transport.base
 
1179
        self.base = self.bzrdir.transport.base
1262
1180
        # Additional places to query for data.
1263
1181
        self._fallback_repositories = []
1264
1182
 
1265
1183
    @property
1266
1184
    def user_transport(self):
1267
 
        return self.controldir.user_transport
 
1185
        return self.bzrdir.user_transport
1268
1186
 
1269
1187
    @property
1270
1188
    def control_transport(self):
1271
1189
        # XXX: Normally you shouldn't directly get at the remote repository
1272
1190
        # transport, but I'm not sure it's worth making this method
1273
1191
        # optional -- mbp 2010-04-21
1274
 
        return self.controldir.get_repository_transport(None)
 
1192
        return self.bzrdir.get_repository_transport(None)
1275
1193
 
1276
1194
    def __str__(self):
1277
1195
        return "%s(%s)" % (self.__class__.__name__, self.base)
1297
1215
                mutter('(suppressed) not in write group')
1298
1216
                return
1299
1217
            raise errors.BzrError("not in write group")
1300
 
        path = self.controldir._path_for_remote_call(self._client)
 
1218
        path = self.bzrdir._path_for_remote_call(self._client)
1301
1219
        try:
1302
 
            response = self._call(b'Repository.abort_write_group', path,
1303
 
                                  self._lock_token,
1304
 
                                  [token.encode('utf-8') for token in self._write_group_tokens])
1305
 
        except Exception as exc:
 
1220
            response = self._call('Repository.abort_write_group', path,
 
1221
                self._lock_token, self._write_group_tokens)
 
1222
        except Exception, exc:
1306
1223
            self._write_group = None
1307
1224
            if not suppress_errors:
1308
1225
                raise
1310
1227
            log_exception_quietly()
1311
1228
            note(gettext('bzr: ERROR (ignored): %s'), exc)
1312
1229
        else:
1313
 
            if response != (b'ok', ):
 
1230
            if response != ('ok', ):
1314
1231
                raise errors.UnexpectedSmartServerResponse(response)
1315
1232
            self._write_group_tokens = None
1316
1233
 
1337
1254
            return self._real_repository.commit_write_group()
1338
1255
        if not self.is_in_write_group():
1339
1256
            raise errors.BzrError("not in write group")
1340
 
        path = self.controldir._path_for_remote_call(self._client)
1341
 
        response = self._call(b'Repository.commit_write_group', path,
1342
 
                              self._lock_token, [token.encode('utf-8') for token in self._write_group_tokens])
1343
 
        if response != (b'ok', ):
 
1257
        path = self.bzrdir._path_for_remote_call(self._client)
 
1258
        response = self._call('Repository.commit_write_group', path,
 
1259
            self._lock_token, self._write_group_tokens)
 
1260
        if response != ('ok', ):
1344
1261
            raise errors.UnexpectedSmartServerResponse(response)
1345
1262
        self._write_group_tokens = None
1346
1263
        # Refresh data after writing to the repository.
1349
1266
    def resume_write_group(self, tokens):
1350
1267
        if self._real_repository:
1351
1268
            return self._real_repository.resume_write_group(tokens)
1352
 
        path = self.controldir._path_for_remote_call(self._client)
 
1269
        path = self.bzrdir._path_for_remote_call(self._client)
1353
1270
        try:
1354
 
            response = self._call(b'Repository.check_write_group', path,
1355
 
                                  self._lock_token, [token.encode('utf-8') for token in tokens])
 
1271
            response = self._call('Repository.check_write_group', path,
 
1272
               self._lock_token, tokens)
1356
1273
        except errors.UnknownSmartMethod:
1357
1274
            self._ensure_real()
1358
1275
            return self._real_repository.resume_write_group(tokens)
1359
 
        if response != (b'ok', ):
 
1276
        if response != ('ok', ):
1360
1277
            raise errors.UnexpectedSmartServerResponse(response)
1361
1278
        self._write_group_tokens = tokens
1362
1279
 
1379
1296
 
1380
1297
    def get_rev_id_for_revno(self, revno, known_pair):
1381
1298
        """See Repository.get_rev_id_for_revno."""
1382
 
        path = self.controldir._path_for_remote_call(self._client)
 
1299
        path = self.bzrdir._path_for_remote_call(self._client)
1383
1300
        try:
1384
1301
            if self._client._medium._is_remote_before((1, 17)):
1385
1302
                return self._get_rev_id_for_revno_vfs(revno, known_pair)
1386
1303
            response = self._call(
1387
 
                b'Repository.get_rev_id_for_revno', path, revno, known_pair)
 
1304
                'Repository.get_rev_id_for_revno', path, revno, known_pair)
1388
1305
        except errors.UnknownSmartMethod:
1389
1306
            self._client._medium._remember_remote_is_before((1, 17))
1390
1307
            return self._get_rev_id_for_revno_vfs(revno, known_pair)
1391
 
        except errors.UnknownErrorFromSmartServer as e:
1392
 
            # Older versions of Bazaar/Breezy (<< 3.0.0) would raise a
1393
 
            # ValueError instead of returning revno-outofbounds
1394
 
            if len(e.error_tuple) < 3:
1395
 
                raise
1396
 
            if e.error_tuple[:2] != (b'error', b'ValueError'):
1397
 
                raise
1398
 
            m = re.match(
1399
 
                br"requested revno \(([0-9]+)\) is later than given "
1400
 
                br"known revno \(([0-9]+)\)", e.error_tuple[2])
1401
 
            if not m:
1402
 
                raise
1403
 
            raise errors.RevnoOutOfBounds(
1404
 
                int(m.group(1)), (0, int(m.group(2))))
1405
 
        if response[0] == b'ok':
 
1308
        if response[0] == 'ok':
1406
1309
            return True, response[1]
1407
 
        elif response[0] == b'history-incomplete':
 
1310
        elif response[0] == 'history-incomplete':
1408
1311
            known_pair = response[1:3]
1409
1312
            for fallback in self._fallback_repositories:
1410
 
                found, result = fallback.get_rev_id_for_revno(
1411
 
                    revno, known_pair)
 
1313
                found, result = fallback.get_rev_id_for_revno(revno, known_pair)
1412
1314
                if found:
1413
1315
                    return True, result
1414
1316
                else:
1435
1337
            if 'hpssvfs' in debug.debug_flags:
1436
1338
                import traceback
1437
1339
                warning('VFS Repository access triggered\n%s',
1438
 
                        ''.join(traceback.format_stack()))
 
1340
                    ''.join(traceback.format_stack()))
1439
1341
            self._unstacked_provider.missing_keys.clear()
1440
 
            self.controldir._ensure_real()
 
1342
            self.bzrdir._ensure_real()
1441
1343
            self._set_real_repository(
1442
 
                self.controldir._real_bzrdir.open_repository())
 
1344
                self.bzrdir._real_bzrdir.open_repository())
1443
1345
 
1444
1346
    def _translate_error(self, err, **context):
1445
 
        self.controldir._translate_error(err, repository=self, **context)
 
1347
        self.bzrdir._translate_error(err, repository=self, **context)
1446
1348
 
1447
1349
    def find_text_key_references(self):
1448
1350
        """Find the text key references within the repository.
1469
1371
    def _get_revision_graph(self, revision_id):
1470
1372
        """Private method for using with old (< 1.2) servers to fallback."""
1471
1373
        if revision_id is None:
1472
 
            revision_id = b''
 
1374
            revision_id = ''
1473
1375
        elif _mod_revision.is_null(revision_id):
1474
1376
            return {}
1475
1377
 
1476
 
        path = self.controldir._path_for_remote_call(self._client)
 
1378
        path = self.bzrdir._path_for_remote_call(self._client)
1477
1379
        response = self._call_expecting_body(
1478
 
            b'Repository.get_revision_graph', path, revision_id)
 
1380
            'Repository.get_revision_graph', path, revision_id)
1479
1381
        response_tuple, response_handler = response
1480
 
        if response_tuple[0] != b'ok':
 
1382
        if response_tuple[0] != 'ok':
1481
1383
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1482
1384
        coded = response_handler.read_body_bytes()
1483
 
        if coded == b'':
 
1385
        if coded == '':
1484
1386
            # no revisions in this repository!
1485
1387
            return {}
1486
 
        lines = coded.split(b'\n')
 
1388
        lines = coded.split('\n')
1487
1389
        revision_graph = {}
1488
1390
        for line in lines:
1489
1391
            d = tuple(line.split())
1499
1401
        """Return a source for streaming from this repository."""
1500
1402
        return RemoteStreamSource(self, to_format)
1501
1403
 
 
1404
    @needs_read_lock
1502
1405
    def get_file_graph(self):
1503
 
        with self.lock_read():
1504
 
            return graph.Graph(self.texts)
 
1406
        return graph.Graph(self.texts)
1505
1407
 
 
1408
    @needs_read_lock
1506
1409
    def has_revision(self, revision_id):
1507
1410
        """True if this repository has a copy of the revision."""
1508
 
        # Copy of breezy.repository.Repository.has_revision
1509
 
        with self.lock_read():
1510
 
            return revision_id in self.has_revisions((revision_id,))
 
1411
        # Copy of bzrlib.repository.Repository.has_revision
 
1412
        return revision_id in self.has_revisions((revision_id,))
1511
1413
 
 
1414
    @needs_read_lock
1512
1415
    def has_revisions(self, revision_ids):
1513
1416
        """Probe to find out the presence of multiple revisions.
1514
1417
 
1515
1418
        :param revision_ids: An iterable of revision_ids.
1516
1419
        :return: A set of the revision_ids that were present.
1517
1420
        """
1518
 
        with self.lock_read():
1519
 
            # Copy of breezy.repository.Repository.has_revisions
1520
 
            parent_map = self.get_parent_map(revision_ids)
1521
 
            result = set(parent_map)
1522
 
            if _mod_revision.NULL_REVISION in revision_ids:
1523
 
                result.add(_mod_revision.NULL_REVISION)
1524
 
            return result
 
1421
        # Copy of bzrlib.repository.Repository.has_revisions
 
1422
        parent_map = self.get_parent_map(revision_ids)
 
1423
        result = set(parent_map)
 
1424
        if _mod_revision.NULL_REVISION in revision_ids:
 
1425
            result.add(_mod_revision.NULL_REVISION)
 
1426
        return result
1525
1427
 
1526
1428
    def _has_same_fallbacks(self, other_repo):
1527
1429
        """Returns true if the repositories have the same fallbacks."""
1540
1442
        # TODO: Move to RepositoryBase and unify with the regular Repository
1541
1443
        # one; unfortunately the tests rely on slightly different behaviour at
1542
1444
        # present -- mbp 20090710
1543
 
        return (self.__class__ is other.__class__
1544
 
                and self.controldir.transport.base == other.controldir.transport.base)
 
1445
        return (self.__class__ is other.__class__ and
 
1446
                self.bzrdir.transport.base == other.bzrdir.transport.base)
1545
1447
 
1546
1448
    def get_graph(self, other_repository=None):
1547
1449
        """Return the graph for this repository format"""
1548
1450
        parents_provider = self._make_parents_provider(other_repository)
1549
1451
        return graph.Graph(parents_provider)
1550
1452
 
 
1453
    @needs_read_lock
1551
1454
    def get_known_graph_ancestry(self, revision_ids):
1552
1455
        """Return the known graph for a set of revision ids and their ancestors.
1553
1456
        """
1554
 
        with self.lock_read():
1555
 
            revision_graph = dict(((key, value) for key, value in
1556
 
                                   self.get_graph().iter_ancestry(revision_ids) if value is not None))
1557
 
            revision_graph = _mod_repository._strip_NULL_ghosts(revision_graph)
1558
 
            return graph.KnownGraph(revision_graph)
 
1457
        st = static_tuple.StaticTuple
 
1458
        revision_keys = [st(r_id).intern() for r_id in revision_ids]
 
1459
        known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
 
1460
        return graph.GraphThunkIdsToKeys(known_graph)
1559
1461
 
1560
1462
    def gather_stats(self, revid=None, committers=None):
1561
1463
        """See Repository.gather_stats()."""
1562
 
        path = self.controldir._path_for_remote_call(self._client)
 
1464
        path = self.bzrdir._path_for_remote_call(self._client)
1563
1465
        # revid can be None to indicate no revisions, not just NULL_REVISION
1564
1466
        if revid is None or _mod_revision.is_null(revid):
1565
 
            fmt_revid = b''
 
1467
            fmt_revid = ''
1566
1468
        else:
1567
1469
            fmt_revid = revid
1568
1470
        if committers is None or not committers:
1569
 
            fmt_committers = b'no'
 
1471
            fmt_committers = 'no'
1570
1472
        else:
1571
 
            fmt_committers = b'yes'
 
1473
            fmt_committers = 'yes'
1572
1474
        response_tuple, response_handler = self._call_expecting_body(
1573
 
            b'Repository.gather_stats', path, fmt_revid, fmt_committers)
1574
 
        if response_tuple[0] != b'ok':
 
1475
            'Repository.gather_stats', path, fmt_revid, fmt_committers)
 
1476
        if response_tuple[0] != 'ok':
1575
1477
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1576
1478
 
1577
1479
        body = response_handler.read_body_bytes()
1578
1480
        result = {}
1579
 
        for line in body.split(b'\n'):
 
1481
        for line in body.split('\n'):
1580
1482
            if not line:
1581
1483
                continue
1582
 
            key, val_text = line.split(b':')
1583
 
            key = key.decode('ascii')
 
1484
            key, val_text = line.split(':')
1584
1485
            if key in ('revisions', 'size', 'committers'):
1585
1486
                result[key] = int(val_text)
1586
1487
            elif key in ('firstrev', 'latestrev'):
1587
 
                values = val_text.split(b' ')[1:]
1588
 
                result[key] = (float(values[0]), int(values[1]))
 
1488
                values = val_text.split(' ')[1:]
 
1489
                result[key] = (float(values[0]), long(values[1]))
1589
1490
 
1590
1491
        return result
1591
1492
 
1597
1498
 
1598
1499
    def get_physical_lock_status(self):
1599
1500
        """See Repository.get_physical_lock_status()."""
1600
 
        path = self.controldir._path_for_remote_call(self._client)
 
1501
        path = self.bzrdir._path_for_remote_call(self._client)
1601
1502
        try:
1602
 
            response = self._call(b'Repository.get_physical_lock_status', path)
 
1503
            response = self._call('Repository.get_physical_lock_status', path)
1603
1504
        except errors.UnknownSmartMethod:
1604
1505
            self._ensure_real()
1605
1506
            return self._real_repository.get_physical_lock_status()
1606
 
        if response[0] not in (b'yes', b'no'):
 
1507
        if response[0] not in ('yes', 'no'):
1607
1508
            raise errors.UnexpectedSmartServerResponse(response)
1608
 
        return (response[0] == b'yes')
 
1509
        return (response[0] == 'yes')
1609
1510
 
1610
1511
    def is_in_write_group(self):
1611
1512
        """Return True if there is an open write group.
1622
1523
 
1623
1524
    def is_shared(self):
1624
1525
        """See Repository.is_shared()."""
1625
 
        path = self.controldir._path_for_remote_call(self._client)
1626
 
        response = self._call(b'Repository.is_shared', path)
1627
 
        if response[0] not in (b'yes', b'no'):
1628
 
            raise SmartProtocolError(
1629
 
                'unexpected response code %s' % (response,))
1630
 
        return response[0] == b'yes'
 
1526
        path = self.bzrdir._path_for_remote_call(self._client)
 
1527
        response = self._call('Repository.is_shared', path)
 
1528
        if response[0] not in ('yes', 'no'):
 
1529
            raise SmartProtocolError('unexpected response code %s' % (response,))
 
1530
        return response[0] == 'yes'
1631
1531
 
1632
1532
    def is_write_locked(self):
1633
1533
        return self._lock_mode == 'w'
1640
1540
    def lock_read(self):
1641
1541
        """Lock the repository for read operations.
1642
1542
 
1643
 
        :return: A breezy.lock.LogicalLockResult.
 
1543
        :return: A bzrlib.lock.LogicalLockResult.
1644
1544
        """
1645
1545
        # wrong eventually - want a local lock cache context
1646
1546
        if not self._lock_mode:
1657
1557
        return lock.LogicalLockResult(self.unlock)
1658
1558
 
1659
1559
    def _remote_lock_write(self, token):
1660
 
        path = self.controldir._path_for_remote_call(self._client)
 
1560
        path = self.bzrdir._path_for_remote_call(self._client)
1661
1561
        if token is None:
1662
 
            token = b''
 
1562
            token = ''
1663
1563
        err_context = {'token': token}
1664
 
        response = self._call(b'Repository.lock_write', path, token,
 
1564
        response = self._call('Repository.lock_write', path, token,
1665
1565
                              **err_context)
1666
 
        if response[0] == b'ok':
 
1566
        if response[0] == 'ok':
1667
1567
            ok, token = response
1668
1568
            return token
1669
1569
        else:
1741
1641
        # 3) new servers, RemoteRepository.ensure_real is triggered before
1742
1642
        # RemoteBranch.ensure real, in this case we get a repo with no fallbacks
1743
1643
        # and need to populate it.
1744
 
        if (self._fallback_repositories
1745
 
            and len(self._real_repository._fallback_repositories)
1746
 
                != len(self._fallback_repositories)):
 
1644
        if (self._fallback_repositories and
 
1645
            len(self._real_repository._fallback_repositories) !=
 
1646
            len(self._fallback_repositories)):
1747
1647
            if len(self._real_repository._fallback_repositories):
1748
1648
                raise AssertionError(
1749
1649
                    "cannot cleanly remove existing _fallback_repositories")
1775
1675
            raise errors.NotWriteLocked(self)
1776
1676
        if self._write_group_tokens is not None:
1777
1677
            raise errors.BzrError('already in a write group')
1778
 
        path = self.controldir._path_for_remote_call(self._client)
 
1678
        path = self.bzrdir._path_for_remote_call(self._client)
1779
1679
        try:
1780
 
            response = self._call(b'Repository.start_write_group', path,
1781
 
                                  self._lock_token)
 
1680
            response = self._call('Repository.start_write_group', path,
 
1681
                self._lock_token)
1782
1682
        except (errors.UnknownSmartMethod, errors.UnsuspendableWriteGroup):
1783
1683
            self._ensure_real()
1784
1684
            return self._real_repository.start_write_group()
1785
 
        if response[0] != b'ok':
 
1685
        if response[0] != 'ok':
1786
1686
            raise errors.UnexpectedSmartServerResponse(response)
1787
 
        self._write_group_tokens = [
1788
 
            token.decode('utf-8') for token in response[1]]
 
1687
        self._write_group_tokens = response[1]
1789
1688
 
1790
1689
    def _unlock(self, token):
1791
 
        path = self.controldir._path_for_remote_call(self._client)
 
1690
        path = self.bzrdir._path_for_remote_call(self._client)
1792
1691
        if not token:
1793
1692
            # with no token the remote repository is not persistently locked.
1794
1693
            return
1795
1694
        err_context = {'token': token}
1796
 
        response = self._call(b'Repository.unlock', path, token,
 
1695
        response = self._call('Repository.unlock', path, token,
1797
1696
                              **err_context)
1798
 
        if response == (b'ok',):
 
1697
        if response == ('ok',):
1799
1698
            return
1800
1699
        else:
1801
1700
            raise errors.UnexpectedSmartServerResponse(response)
1837
1736
 
1838
1737
    def break_lock(self):
1839
1738
        # should hand off to the network
1840
 
        path = self.controldir._path_for_remote_call(self._client)
 
1739
        path = self.bzrdir._path_for_remote_call(self._client)
1841
1740
        try:
1842
 
            response = self._call(b"Repository.break_lock", path)
 
1741
            response = self._call("Repository.break_lock", path)
1843
1742
        except errors.UnknownSmartMethod:
1844
1743
            self._ensure_real()
1845
1744
            return self._real_repository.break_lock()
1846
 
        if response != (b'ok',):
 
1745
        if response != ('ok',):
1847
1746
            raise errors.UnexpectedSmartServerResponse(response)
1848
1747
 
1849
1748
    def _get_tarball(self, compression):
1852
1751
        Returns None if the server does not support sending tarballs.
1853
1752
        """
1854
1753
        import tempfile
1855
 
        path = self.controldir._path_for_remote_call(self._client)
 
1754
        path = self.bzrdir._path_for_remote_call(self._client)
1856
1755
        try:
1857
1756
            response, protocol = self._call_expecting_body(
1858
 
                b'Repository.tarball', path, compression.encode('ascii'))
 
1757
                'Repository.tarball', path, compression)
1859
1758
        except errors.UnknownSmartMethod:
1860
1759
            protocol.cancel_read_body()
1861
1760
            return None
1862
 
        if response[0] == b'ok':
 
1761
        if response[0] == 'ok':
1863
1762
            # Extract the tarball and return it
1864
1763
            t = tempfile.NamedTemporaryFile()
1865
1764
            # TODO: rpc layer should read directly into it...
1868
1767
            return t
1869
1768
        raise errors.UnexpectedSmartServerResponse(response)
1870
1769
 
 
1770
    @needs_read_lock
1871
1771
    def sprout(self, to_bzrdir, revision_id=None):
1872
1772
        """Create a descendent repository for new development.
1873
1773
 
1874
1774
        Unlike clone, this does not copy the settings of the repository.
1875
1775
        """
1876
 
        with self.lock_read():
1877
 
            dest_repo = self._create_sprouting_repo(to_bzrdir, shared=False)
1878
 
            dest_repo.fetch(self, revision_id=revision_id)
1879
 
            return dest_repo
 
1776
        dest_repo = self._create_sprouting_repo(to_bzrdir, shared=False)
 
1777
        dest_repo.fetch(self, revision_id=revision_id)
 
1778
        return dest_repo
1880
1779
 
1881
 
    def _create_sprouting_repo(self, a_controldir, shared):
1882
 
        if not isinstance(a_controldir._format, self.controldir._format.__class__):
 
1780
    def _create_sprouting_repo(self, a_bzrdir, shared):
 
1781
        if not isinstance(a_bzrdir._format, self.bzrdir._format.__class__):
1883
1782
            # use target default format.
1884
 
            dest_repo = a_controldir.create_repository()
 
1783
            dest_repo = a_bzrdir.create_repository()
1885
1784
        else:
1886
1785
            # Most control formats need the repository to be specifically
1887
1786
            # created, but on some old all-in-one formats it's not needed
1888
1787
            try:
1889
 
                dest_repo = self._format.initialize(
1890
 
                    a_controldir, shared=shared)
 
1788
                dest_repo = self._format.initialize(a_bzrdir, shared=shared)
1891
1789
            except errors.UninitializableFormat:
1892
 
                dest_repo = a_controldir.open_repository()
 
1790
                dest_repo = a_bzrdir.open_repository()
1893
1791
        return dest_repo
1894
1792
 
1895
 
    # These methods are just thin shims to the VFS object for now.
 
1793
    ### These methods are just thin shims to the VFS object for now.
1896
1794
 
 
1795
    @needs_read_lock
1897
1796
    def revision_tree(self, revision_id):
1898
 
        with self.lock_read():
1899
 
            revision_id = _mod_revision.ensure_null(revision_id)
1900
 
            if revision_id == _mod_revision.NULL_REVISION:
1901
 
                return InventoryRevisionTree(self,
1902
 
                                             Inventory(root_id=None), _mod_revision.NULL_REVISION)
1903
 
            else:
1904
 
                return list(self.revision_trees([revision_id]))[0]
 
1797
        revision_id = _mod_revision.ensure_null(revision_id)
 
1798
        if revision_id == _mod_revision.NULL_REVISION:
 
1799
            return InventoryRevisionTree(self,
 
1800
                Inventory(root_id=None), _mod_revision.NULL_REVISION)
 
1801
        else:
 
1802
            return list(self.revision_trees([revision_id]))[0]
1905
1803
 
1906
1804
    def get_serializer_format(self):
1907
 
        path = self.controldir._path_for_remote_call(self._client)
 
1805
        path = self.bzrdir._path_for_remote_call(self._client)
1908
1806
        try:
1909
 
            response = self._call(b'VersionedFileRepository.get_serializer_format',
1910
 
                                  path)
 
1807
            response = self._call('VersionedFileRepository.get_serializer_format',
 
1808
                path)
1911
1809
        except errors.UnknownSmartMethod:
1912
1810
            self._ensure_real()
1913
1811
            return self._real_repository.get_serializer_format()
1914
 
        if response[0] != b'ok':
 
1812
        if response[0] != 'ok':
1915
1813
            raise errors.UnexpectedSmartServerResponse(response)
1916
1814
        return response[1]
1917
1815
 
1933
1831
        """
1934
1832
        if self._fallback_repositories and not self._format.supports_chks:
1935
1833
            raise errors.BzrError("Cannot commit directly to a stacked branch"
1936
 
                                  " in pre-2a formats. See "
1937
 
                                  "https://bugs.launchpad.net/bzr/+bug/375013 for details.")
1938
 
        commit_builder_kls = vf_repository.VersionedFileCommitBuilder
 
1834
                " in pre-2a formats. See "
 
1835
                "https://bugs.launchpad.net/bzr/+bug/375013 for details.")
 
1836
        if self._format.rich_root_data:
 
1837
            commit_builder_kls = vf_repository.VersionedFileRootCommitBuilder
 
1838
        else:
 
1839
            commit_builder_kls = vf_repository.VersionedFileCommitBuilder
1939
1840
        result = commit_builder_kls(self, parents, config,
1940
 
                                    timestamp, timezone, committer, revprops, revision_id,
1941
 
                                    lossy)
 
1841
            timestamp, timezone, committer, revprops, revision_id,
 
1842
            lossy)
1942
1843
        self.start_write_group()
1943
1844
        return result
1944
1845
 
1966
1867
        # repository to be added may already be in the _real_repositories list.
1967
1868
        if self._real_repository is not None:
1968
1869
            fallback_locations = [repo.user_url for repo in
1969
 
                                  self._real_repository._fallback_repositories]
 
1870
                self._real_repository._fallback_repositories]
1970
1871
            if repository.user_url not in fallback_locations:
1971
1872
                self._real_repository.add_fallback_repository(repository)
1972
1873
 
1985
1886
        return self._real_repository.add_inventory(revid, inv, parents)
1986
1887
 
1987
1888
    def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1988
 
                               parents, basis_inv=None, propagate_caches=False):
 
1889
            parents, basis_inv=None, propagate_caches=False):
1989
1890
        self._ensure_real()
1990
1891
        return self._real_repository.add_inventory_by_delta(basis_revision_id,
1991
 
                                                            delta, new_revision_id, parents, basis_inv=basis_inv,
1992
 
                                                            propagate_caches=propagate_caches)
 
1892
            delta, new_revision_id, parents, basis_inv=basis_inv,
 
1893
            propagate_caches=propagate_caches)
1993
1894
 
1994
1895
    def add_revision(self, revision_id, rev, inv=None):
1995
1896
        _mod_revision.check_not_reserved_id(revision_id)
2010
1911
    def _add_revision(self, rev):
2011
1912
        if self._real_repository is not None:
2012
1913
            return self._real_repository._add_revision(rev)
2013
 
        lines = self._serializer.write_revision_to_lines(rev)
 
1914
        text = self._serializer.write_revision_to_string(rev)
2014
1915
        key = (rev.revision_id,)
2015
1916
        parents = tuple((parent,) for parent in rev.parent_ids)
2016
1917
        self._write_group_tokens, missing_keys = self._get_sink().insert_stream(
2017
 
            [('revisions', [ChunkedContentFactory(key, parents, None, lines, chunks_are_lines=True)])],
 
1918
            [('revisions', [FulltextContentFactory(key, parents, None, text)])],
2018
1919
            self._format, self._write_group_tokens)
2019
1920
 
 
1921
    @needs_read_lock
2020
1922
    def get_inventory(self, revision_id):
2021
 
        with self.lock_read():
2022
 
            return list(self.iter_inventories([revision_id]))[0]
 
1923
        return list(self.iter_inventories([revision_id]))[0]
2023
1924
 
2024
1925
    def _iter_inventories_rpc(self, revision_ids, ordering):
2025
1926
        if ordering is None:
2026
1927
            ordering = 'unordered'
2027
 
        path = self.controldir._path_for_remote_call(self._client)
2028
 
        body = b"\n".join(revision_ids)
 
1928
        path = self.bzrdir._path_for_remote_call(self._client)
 
1929
        body = "\n".join(revision_ids)
2029
1930
        response_tuple, response_handler = (
2030
1931
            self._call_with_body_bytes_expecting_body(
2031
 
                b"VersionedFileRepository.get_inventories",
2032
 
                (path, ordering.encode('ascii')), body))
2033
 
        if response_tuple[0] != b"ok":
 
1932
                "VersionedFileRepository.get_inventories",
 
1933
                (path, ordering), body))
 
1934
        if response_tuple[0] != "ok":
2034
1935
            raise errors.UnexpectedSmartServerResponse(response_tuple)
2035
1936
        deserializer = inventory_delta.InventoryDeltaDeserializer()
2036
1937
        byte_stream = response_handler.read_streamed_body()
2042
1943
        if src_format.network_name() != self._format.network_name():
2043
1944
            raise AssertionError(
2044
1945
                "Mismatched RemoteRepository and stream src %r, %r" % (
2045
 
                    src_format.network_name(), self._format.network_name()))
 
1946
                src_format.network_name(), self._format.network_name()))
2046
1947
        # ignore the src format, it's not really relevant
2047
1948
        prev_inv = Inventory(root_id=None,
2048
 
                             revision_id=_mod_revision.NULL_REVISION)
 
1949
            revision_id=_mod_revision.NULL_REVISION)
2049
1950
        # there should be just one substream, with inventory deltas
2050
 
        try:
2051
 
            substream_kind, substream = next(stream)
2052
 
        except StopIteration:
2053
 
            return
 
1951
        substream_kind, substream = stream.next()
2054
1952
        if substream_kind != "inventory-deltas":
2055
1953
            raise AssertionError(
2056
 
                "Unexpected stream %r received" % substream_kind)
 
1954
                 "Unexpected stream %r received" % substream_kind)
2057
1955
        for record in substream:
2058
1956
            (parent_id, new_id, versioned_root, tree_references, invdelta) = (
2059
 
                deserializer.parse_text_bytes(record.get_bytes_as("lines")))
 
1957
                deserializer.parse_text_bytes(record.get_bytes_as("fulltext")))
2060
1958
            if parent_id != prev_inv.revision_id:
2061
1959
                raise AssertionError("invalid base %r != %r" % (parent_id,
2062
 
                                                                prev_inv.revision_id))
 
1960
                    prev_inv.revision_id))
2063
1961
            inv = prev_inv.create_by_apply_delta(invdelta, new_id)
2064
1962
            yield inv, inv.revision_id
2065
1963
            prev_inv = inv
2081
1979
            buffering if necessary).
2082
1980
        :return: An iterator of inventories.
2083
1981
        """
2084
 
        if ((None in revision_ids) or
2085
 
                (_mod_revision.NULL_REVISION in revision_ids)):
 
1982
        if ((None in revision_ids)
 
1983
            or (_mod_revision.NULL_REVISION in revision_ids)):
2086
1984
            raise ValueError('cannot get null revision inventory')
2087
1985
        for inv, revid in self._iter_inventories(revision_ids, ordering):
2088
1986
            if inv is None:
2144
2042
            while missing:
2145
2043
                yield None, missing.pop()
2146
2044
 
 
2045
    @needs_read_lock
2147
2046
    def get_revision(self, revision_id):
2148
 
        with self.lock_read():
2149
 
            return self.get_revisions([revision_id])[0]
 
2047
        return self.get_revisions([revision_id])[0]
2150
2048
 
2151
2049
    def get_transaction(self):
2152
2050
        self._ensure_real()
2153
2051
        return self._real_repository.get_transaction()
2154
2052
 
2155
 
    def clone(self, a_controldir, revision_id=None):
2156
 
        with self.lock_read():
2157
 
            dest_repo = self._create_sprouting_repo(
2158
 
                a_controldir, shared=self.is_shared())
2159
 
            self.copy_content_into(dest_repo, revision_id)
2160
 
            return dest_repo
 
2053
    @needs_read_lock
 
2054
    def clone(self, a_bzrdir, revision_id=None):
 
2055
        dest_repo = self._create_sprouting_repo(
 
2056
            a_bzrdir, shared=self.is_shared())
 
2057
        self.copy_content_into(dest_repo, revision_id)
 
2058
        return dest_repo
2161
2059
 
2162
2060
    def make_working_trees(self):
2163
2061
        """See Repository.make_working_trees"""
2164
 
        path = self.controldir._path_for_remote_call(self._client)
 
2062
        path = self.bzrdir._path_for_remote_call(self._client)
2165
2063
        try:
2166
 
            response = self._call(b'Repository.make_working_trees', path)
 
2064
            response = self._call('Repository.make_working_trees', path)
2167
2065
        except errors.UnknownSmartMethod:
2168
2066
            self._ensure_real()
2169
2067
            return self._real_repository.make_working_trees()
2170
 
        if response[0] not in (b'yes', b'no'):
2171
 
            raise SmartProtocolError(
2172
 
                'unexpected response code %s' % (response,))
2173
 
        return response[0] == b'yes'
 
2068
        if response[0] not in ('yes', 'no'):
 
2069
            raise SmartProtocolError('unexpected response code %s' % (response,))
 
2070
        return response[0] == 'yes'
2174
2071
 
2175
2072
    def refresh_data(self):
2176
2073
        """Re-read any data needed to synchronise with disk.
2178
2075
        This method is intended to be called after another repository instance
2179
2076
        (such as one used by a smart server) has inserted data into the
2180
2077
        repository. On all repositories this will work outside of write groups.
2181
 
        Some repository formats (pack and newer for breezy native formats)
 
2078
        Some repository formats (pack and newer for bzrlib native formats)
2182
2079
        support refresh_data inside write groups. If called inside a write
2183
2080
        group on a repository that does not support refreshing in a write group
2184
2081
        IsInWriteGroupError will be raised.
2192
2089
    def revision_ids_to_search_result(self, result_set):
2193
2090
        """Convert a set of revision ids to a graph SearchResult."""
2194
2091
        result_parents = set()
2195
 
        for parents in self.get_graph().get_parent_map(result_set).values():
 
2092
        for parents in self.get_graph().get_parent_map(
 
2093
            result_set).itervalues():
2196
2094
            result_parents.update(parents)
2197
2095
        included_keys = result_set.intersection(result_parents)
2198
2096
        start_keys = result_set.difference(included_keys)
2199
2097
        exclude_keys = result_parents.difference(result_set)
2200
2098
        result = vf_search.SearchResult(start_keys, exclude_keys,
2201
 
                                        len(result_set), result_set)
 
2099
            len(result_set), result_set)
2202
2100
        return result
2203
2101
 
 
2102
    @needs_read_lock
2204
2103
    def search_missing_revision_ids(self, other,
2205
 
                                    find_ghosts=True, revision_ids=None, if_present_ids=None,
2206
 
                                    limit=None):
 
2104
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
2105
            find_ghosts=True, revision_ids=None, if_present_ids=None,
 
2106
            limit=None):
2207
2107
        """Return the revision ids that other has that this does not.
2208
2108
 
2209
2109
        These are returned in topological order.
2210
2110
 
2211
2111
        revision_id: only return revision ids included by revision_id.
2212
2112
        """
2213
 
        with self.lock_read():
2214
 
            inter_repo = _mod_repository.InterRepository.get(other, self)
2215
 
            return inter_repo.search_missing_revision_ids(
2216
 
                find_ghosts=find_ghosts, revision_ids=revision_ids,
2217
 
                if_present_ids=if_present_ids, limit=limit)
 
2113
        if symbol_versioning.deprecated_passed(revision_id):
 
2114
            symbol_versioning.warn(
 
2115
                'search_missing_revision_ids(revision_id=...) was '
 
2116
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
 
2117
                DeprecationWarning, stacklevel=2)
 
2118
            if revision_ids is not None:
 
2119
                raise AssertionError(
 
2120
                    'revision_ids is mutually exclusive with revision_id')
 
2121
            if revision_id is not None:
 
2122
                revision_ids = [revision_id]
 
2123
        inter_repo = _mod_repository.InterRepository.get(other, self)
 
2124
        return inter_repo.search_missing_revision_ids(
 
2125
            find_ghosts=find_ghosts, revision_ids=revision_ids,
 
2126
            if_present_ids=if_present_ids, limit=limit)
2218
2127
 
2219
2128
    def fetch(self, source, revision_id=None, find_ghosts=False,
2220
 
              fetch_spec=None, lossy=False):
 
2129
            fetch_spec=None):
2221
2130
        # No base implementation to use as RemoteRepository is not a subclass
2222
2131
        # of Repository; so this is a copy of Repository.fetch().
2223
2132
        if fetch_spec is not None and revision_id is not None:
2227
2136
            raise errors.InternalBzrError(
2228
2137
                "May not fetch while in a write group.")
2229
2138
        # fast path same-url fetch operations
2230
 
        if (self.has_same_location(source) and
2231
 
            fetch_spec is None and
2232
 
                self._has_same_fallbacks(source)):
 
2139
        if (self.has_same_location(source)
 
2140
            and fetch_spec is None
 
2141
            and self._has_same_fallbacks(source)):
2233
2142
            # check that last_revision is in 'from' and then return a
2234
2143
            # no-operation.
2235
 
            if (revision_id is not None
2236
 
                    and not _mod_revision.is_null(revision_id)):
 
2144
            if (revision_id is not None and
 
2145
                not _mod_revision.is_null(revision_id)):
2237
2146
                self.get_revision(revision_id)
2238
 
            return _mod_repository.FetchResult(0)
 
2147
            return 0, []
2239
2148
        # if there is no specific appropriate InterRepository, this will get
2240
2149
        # the InterRepository base class, which raises an
2241
2150
        # IncompatibleRepositories when asked to fetch.
2242
2151
        inter = _mod_repository.InterRepository.get(source, self)
2243
 
        if (fetch_spec is not None
2244
 
                and not getattr(inter, "supports_fetch_spec", False)):
 
2152
        if (fetch_spec is not None and
 
2153
            not getattr(inter, "supports_fetch_spec", False)):
2245
2154
            raise errors.UnsupportedOperation(
2246
2155
                "fetch_spec not supported for %r" % inter)
2247
2156
        return inter.fetch(revision_id=revision_id,
2248
 
                           find_ghosts=find_ghosts, fetch_spec=fetch_spec,
2249
 
                           lossy=lossy)
 
2157
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
2250
2158
 
2251
2159
    def create_bundle(self, target, base, fileobj, format=None):
2252
2160
        self._ensure_real()
2262
2170
            revisions, revision_versions_cache)
2263
2171
 
2264
2172
    def _iter_files_bytes_rpc(self, desired_files, absent):
2265
 
        path = self.controldir._path_for_remote_call(self._client)
 
2173
        path = self.bzrdir._path_for_remote_call(self._client)
2266
2174
        lines = []
2267
2175
        identifiers = []
2268
2176
        for (file_id, revid, identifier) in desired_files:
2269
 
            lines.append(b''.join([
2270
 
                file_id,
2271
 
                b'\0',
2272
 
                revid]))
 
2177
            lines.append("%s\0%s" % (
 
2178
                osutils.safe_file_id(file_id),
 
2179
                osutils.safe_revision_id(revid)))
2273
2180
            identifiers.append(identifier)
2274
2181
        (response_tuple, response_handler) = (
2275
2182
            self._call_with_body_bytes_expecting_body(
2276
 
                b"Repository.iter_files_bytes", (path, ), b"\n".join(lines)))
2277
 
        if response_tuple != (b'ok', ):
 
2183
            "Repository.iter_files_bytes", (path, ), "\n".join(lines)))
 
2184
        if response_tuple != ('ok', ):
2278
2185
            response_handler.cancel_read_body()
2279
2186
            raise errors.UnexpectedSmartServerResponse(response_tuple)
2280
2187
        byte_stream = response_handler.read_streamed_body()
2281
 
 
2282
2188
        def decompress_stream(start, byte_stream, unused):
2283
2189
            decompressor = zlib.decompressobj()
2284
2190
            yield decompressor.decompress(start)
2285
 
            while decompressor.unused_data == b"":
 
2191
            while decompressor.unused_data == "":
2286
2192
                try:
2287
 
                    data = next(byte_stream)
 
2193
                    data = byte_stream.next()
2288
2194
                except StopIteration:
2289
2195
                    break
2290
2196
                yield decompressor.decompress(data)
2291
2197
            yield decompressor.flush()
2292
2198
            unused.append(decompressor.unused_data)
2293
 
        unused = b""
 
2199
        unused = ""
2294
2200
        while True:
2295
 
            while b"\n" not in unused:
2296
 
                try:
2297
 
                    unused += next(byte_stream)
2298
 
                except StopIteration:
2299
 
                    return
2300
 
            header, rest = unused.split(b"\n", 1)
2301
 
            args = header.split(b"\0")
2302
 
            if args[0] == b"absent":
 
2201
            while not "\n" in unused:
 
2202
                unused += byte_stream.next()
 
2203
            header, rest = unused.split("\n", 1)
 
2204
            args = header.split("\0")
 
2205
            if args[0] == "absent":
2303
2206
                absent[identifiers[int(args[3])]] = (args[1], args[2])
2304
2207
                unused = rest
2305
2208
                continue
2306
 
            elif args[0] == b"ok":
 
2209
            elif args[0] == "ok":
2307
2210
                idx = int(args[1])
2308
2211
            else:
2309
2212
                raise errors.UnexpectedSmartServerResponse(args)
2310
2213
            unused_chunks = []
2311
2214
            yield (identifiers[idx],
2312
 
                   decompress_stream(rest, byte_stream, unused_chunks))
2313
 
            unused = b"".join(unused_chunks)
 
2215
                decompress_stream(rest, byte_stream, unused_chunks))
 
2216
            unused = "".join(unused_chunks)
2314
2217
 
2315
2218
    def iter_files_bytes(self, desired_files):
2316
2219
        """See Repository.iter_file_bytes.
2323
2226
            for fallback in self._fallback_repositories:
2324
2227
                if not absent:
2325
2228
                    break
2326
 
                desired_files = [(key[0], key[1], identifier)
2327
 
                                 for identifier, key in absent.items()]
 
2229
                desired_files = [(key[0], key[1], identifier) for
 
2230
                    (identifier, key) in absent.iteritems()]
2328
2231
                for (identifier, bytes_iterator) in fallback.iter_files_bytes(desired_files):
2329
2232
                    del absent[identifier]
2330
2233
                    yield identifier, bytes_iterator
2331
2234
            if absent:
2332
2235
                # There may be more missing items, but raise an exception
2333
2236
                # for just one.
2334
 
                missing_identifier = next(iter(absent))
 
2237
                missing_identifier = absent.keys()[0]
2335
2238
                missing_key = absent[missing_identifier]
2336
2239
                raise errors.RevisionNotPresent(revision_id=missing_key[1],
2337
 
                                                file_id=missing_key[0])
 
2240
                    file_id=missing_key[0])
2338
2241
        except errors.UnknownSmartMethod:
2339
2242
            self._ensure_real()
2340
2243
            for (identifier, bytes_iterator) in (
2341
 
                    self._real_repository.iter_files_bytes(desired_files)):
 
2244
                self._real_repository.iter_files_bytes(desired_files)):
2342
2245
                yield identifier, bytes_iterator
2343
2246
 
2344
2247
    def get_cached_parent_map(self, revision_ids):
2345
 
        """See breezy.CachingParentsProvider.get_cached_parent_map"""
 
2248
        """See bzrlib.CachingParentsProvider.get_cached_parent_map"""
2346
2249
        return self._unstacked_provider.get_cached_parent_map(revision_ids)
2347
2250
 
2348
2251
    def get_parent_map(self, revision_ids):
2349
 
        """See breezy.Graph.get_parent_map()."""
 
2252
        """See bzrlib.Graph.get_parent_map()."""
2350
2253
        return self._make_parents_provider().get_parent_map(revision_ids)
2351
2254
 
2352
2255
    def _get_parent_map_rpc(self, keys):
2371
2274
            # There is one other "bug" which is that ghosts in
2372
2275
            # get_revision_graph() are not returned at all. But we won't worry
2373
2276
            # about that for now.
2374
 
            for node_id, parent_ids in rg.items():
 
2277
            for node_id, parent_ids in rg.iteritems():
2375
2278
                if parent_ids == ():
2376
2279
                    rg[node_id] = (NULL_REVISION,)
2377
2280
            rg[NULL_REVISION] = ()
2382
2285
            raise ValueError('get_parent_map(None) is not valid')
2383
2286
        if NULL_REVISION in keys:
2384
2287
            keys.discard(NULL_REVISION)
2385
 
            found_parents = {NULL_REVISION: ()}
 
2288
            found_parents = {NULL_REVISION:()}
2386
2289
            if not keys:
2387
2290
                return found_parents
2388
2291
        else:
2419
2322
                keys, depth=_DEFAULT_SEARCH_DEPTH)
2420
2323
        recipe = ('manual', start_set, stop_keys, key_count)
2421
2324
        body = self._serialise_search_recipe(recipe)
2422
 
        path = self.controldir._path_for_remote_call(self._client)
 
2325
        path = self.bzrdir._path_for_remote_call(self._client)
2423
2326
        for key in keys:
2424
 
            if not isinstance(key, bytes):
 
2327
            if type(key) is not str:
2425
2328
                raise ValueError(
2426
 
                    "key %r not a bytes string" % (key,))
2427
 
        verb = b'Repository.get_parent_map'
2428
 
        args = (path, b'include-missing:') + tuple(keys)
 
2329
                    "key %r not a plain string" % (key,))
 
2330
        verb = 'Repository.get_parent_map'
 
2331
        args = (path, 'include-missing:') + tuple(keys)
2429
2332
        try:
2430
2333
            response = self._call_with_body_bytes_expecting_body(
2431
2334
                verb, args, body)
2444
2347
            # Recurse just once and we should use the fallback code.
2445
2348
            return self._get_parent_map_rpc(keys)
2446
2349
        response_tuple, response_handler = response
2447
 
        if response_tuple[0] not in [b'ok']:
 
2350
        if response_tuple[0] not in ['ok']:
2448
2351
            response_handler.cancel_read_body()
2449
2352
            raise errors.UnexpectedSmartServerResponse(response_tuple)
2450
 
        if response_tuple[0] == b'ok':
 
2353
        if response_tuple[0] == 'ok':
2451
2354
            coded = bz2.decompress(response_handler.read_body_bytes())
2452
 
            if coded == b'':
 
2355
            if coded == '':
2453
2356
                # no revisions found
2454
2357
                return {}
2455
 
            lines = coded.split(b'\n')
 
2358
            lines = coded.split('\n')
2456
2359
            revision_graph = {}
2457
2360
            for line in lines:
2458
2361
                d = tuple(line.split())
2460
2363
                    revision_graph[d[0]] = d[1:]
2461
2364
                else:
2462
2365
                    # No parents:
2463
 
                    if d[0].startswith(b'missing:'):
 
2366
                    if d[0].startswith('missing:'):
2464
2367
                        revid = d[0][8:]
2465
2368
                        self._unstacked_provider.note_missing_key(revid)
2466
2369
                    else:
2469
2372
                        revision_graph[d[0]] = (NULL_REVISION,)
2470
2373
            return revision_graph
2471
2374
 
 
2375
    @needs_read_lock
2472
2376
    def get_signature_text(self, revision_id):
2473
 
        with self.lock_read():
2474
 
            path = self.controldir._path_for_remote_call(self._client)
2475
 
            try:
2476
 
                response_tuple, response_handler = self._call_expecting_body(
2477
 
                    b'Repository.get_revision_signature_text', path, revision_id)
2478
 
            except errors.UnknownSmartMethod:
2479
 
                self._ensure_real()
2480
 
                return self._real_repository.get_signature_text(revision_id)
2481
 
            except errors.NoSuchRevision as err:
2482
 
                for fallback in self._fallback_repositories:
2483
 
                    try:
2484
 
                        return fallback.get_signature_text(revision_id)
2485
 
                    except errors.NoSuchRevision:
2486
 
                        pass
2487
 
                raise err
2488
 
            else:
2489
 
                if response_tuple[0] != b'ok':
2490
 
                    raise errors.UnexpectedSmartServerResponse(response_tuple)
2491
 
                return response_handler.read_body_bytes()
 
2377
        path = self.bzrdir._path_for_remote_call(self._client)
 
2378
        try:
 
2379
            response_tuple, response_handler = self._call_expecting_body(
 
2380
                'Repository.get_revision_signature_text', path, revision_id)
 
2381
        except errors.UnknownSmartMethod:
 
2382
            self._ensure_real()
 
2383
            return self._real_repository.get_signature_text(revision_id)
 
2384
        except errors.NoSuchRevision, err:
 
2385
            for fallback in self._fallback_repositories:
 
2386
                try:
 
2387
                    return fallback.get_signature_text(revision_id)
 
2388
                except errors.NoSuchRevision:
 
2389
                    pass
 
2390
            raise err
 
2391
        else:
 
2392
            if response_tuple[0] != 'ok':
 
2393
                raise errors.UnexpectedSmartServerResponse(response_tuple)
 
2394
            return response_handler.read_body_bytes()
2492
2395
 
 
2396
    @needs_read_lock
2493
2397
    def _get_inventory_xml(self, revision_id):
2494
 
        with self.lock_read():
2495
 
            # This call is used by older working tree formats,
2496
 
            # which stored a serialized basis inventory.
2497
 
            self._ensure_real()
2498
 
            return self._real_repository._get_inventory_xml(revision_id)
 
2398
        # This call is used by older working tree formats,
 
2399
        # which stored a serialized basis inventory.
 
2400
        self._ensure_real()
 
2401
        return self._real_repository._get_inventory_xml(revision_id)
2499
2402
 
 
2403
    @needs_write_lock
2500
2404
    def reconcile(self, other=None, thorough=False):
2501
 
        from ..reconcile import ReconcileResult
2502
 
        with self.lock_write():
2503
 
            path = self.controldir._path_for_remote_call(self._client)
2504
 
            try:
2505
 
                response, handler = self._call_expecting_body(
2506
 
                    b'Repository.reconcile', path, self._lock_token)
2507
 
            except (errors.UnknownSmartMethod, errors.TokenLockingNotSupported):
2508
 
                self._ensure_real()
2509
 
                return self._real_repository.reconcile(other=other, thorough=thorough)
2510
 
            if response != (b'ok', ):
2511
 
                raise errors.UnexpectedSmartServerResponse(response)
2512
 
            body = handler.read_body_bytes()
2513
 
            result = ReconcileResult()
2514
 
            result.garbage_inventories = None
2515
 
            result.inconsistent_parents = None
2516
 
            result.aborted = None
2517
 
            for line in body.split(b'\n'):
2518
 
                if not line:
2519
 
                    continue
2520
 
                key, val_text = line.split(b':')
2521
 
                if key == b"garbage_inventories":
2522
 
                    result.garbage_inventories = int(val_text)
2523
 
                elif key == b"inconsistent_parents":
2524
 
                    result.inconsistent_parents = int(val_text)
2525
 
                else:
2526
 
                    mutter("unknown reconcile key %r" % key)
2527
 
            return result
 
2405
        from bzrlib.reconcile import RepoReconciler
 
2406
        path = self.bzrdir._path_for_remote_call(self._client)
 
2407
        try:
 
2408
            response, handler = self._call_expecting_body(
 
2409
                'Repository.reconcile', path, self._lock_token)
 
2410
        except (errors.UnknownSmartMethod, errors.TokenLockingNotSupported):
 
2411
            self._ensure_real()
 
2412
            return self._real_repository.reconcile(other=other, thorough=thorough)
 
2413
        if response != ('ok', ):
 
2414
            raise errors.UnexpectedSmartServerResponse(response)
 
2415
        body = handler.read_body_bytes()
 
2416
        result = RepoReconciler(self)
 
2417
        for line in body.split('\n'):
 
2418
            if not line:
 
2419
                continue
 
2420
            key, val_text = line.split(':')
 
2421
            if key == "garbage_inventories":
 
2422
                result.garbage_inventories = int(val_text)
 
2423
            elif key == "inconsistent_parents":
 
2424
                result.inconsistent_parents = int(val_text)
 
2425
            else:
 
2426
                mutter("unknown reconcile key %r" % key)
 
2427
        return result
2528
2428
 
2529
2429
    def all_revision_ids(self):
2530
 
        path = self.controldir._path_for_remote_call(self._client)
 
2430
        path = self.bzrdir._path_for_remote_call(self._client)
2531
2431
        try:
2532
2432
            response_tuple, response_handler = self._call_expecting_body(
2533
 
                b"Repository.all_revision_ids", path)
 
2433
                "Repository.all_revision_ids", path)
2534
2434
        except errors.UnknownSmartMethod:
2535
2435
            self._ensure_real()
2536
2436
            return self._real_repository.all_revision_ids()
2537
 
        if response_tuple != (b"ok", ):
 
2437
        if response_tuple != ("ok", ):
2538
2438
            raise errors.UnexpectedSmartServerResponse(response_tuple)
2539
2439
        revids = set(response_handler.read_body_bytes().splitlines())
2540
2440
        for fallback in self._fallback_repositories:
2545
2445
        """Return Tree for a revision on this branch with only some files.
2546
2446
 
2547
2447
        :param revision_ids: a sequence of revision-ids;
2548
 
          a revision-id may not be None or b'null:'
 
2448
          a revision-id may not be None or 'null:'
2549
2449
        :param file_ids: if not None, the result is filtered
2550
2450
          so that only those file-ids, their parents and their
2551
2451
          children are included.
2557
2457
            filtered_inv = inv.filter(file_ids)
2558
2458
            yield InventoryRevisionTree(self, filtered_inv, filtered_inv.revision_id)
2559
2459
 
2560
 
    def get_revision_delta(self, revision_id):
2561
 
        with self.lock_read():
2562
 
            r = self.get_revision(revision_id)
2563
 
            return list(self.get_revision_deltas([r]))[0]
2564
 
 
 
2460
    @needs_read_lock
 
2461
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
 
2462
        medium = self._client._medium
 
2463
        if medium._is_remote_before((1, 2)):
 
2464
            self._ensure_real()
 
2465
            for delta in self._real_repository.get_deltas_for_revisions(
 
2466
                    revisions, specific_fileids):
 
2467
                yield delta
 
2468
            return
 
2469
        # Get the revision-ids of interest
 
2470
        required_trees = set()
 
2471
        for revision in revisions:
 
2472
            required_trees.add(revision.revision_id)
 
2473
            required_trees.update(revision.parent_ids[:1])
 
2474
 
 
2475
        # Get the matching filtered trees. Note that it's more
 
2476
        # efficient to pass filtered trees to changes_from() rather
 
2477
        # than doing the filtering afterwards. changes_from() could
 
2478
        # arguably do the filtering itself but it's path-based, not
 
2479
        # file-id based, so filtering before or afterwards is
 
2480
        # currently easier.
 
2481
        if specific_fileids is None:
 
2482
            trees = dict((t.get_revision_id(), t) for
 
2483
                t in self.revision_trees(required_trees))
 
2484
        else:
 
2485
            trees = dict((t.get_revision_id(), t) for
 
2486
                t in self._filtered_revision_trees(required_trees,
 
2487
                specific_fileids))
 
2488
 
 
2489
        # Calculate the deltas
 
2490
        for revision in revisions:
 
2491
            if not revision.parent_ids:
 
2492
                old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
 
2493
            else:
 
2494
                old_tree = trees[revision.parent_ids[0]]
 
2495
            yield trees[revision.revision_id].changes_from(old_tree)
 
2496
 
 
2497
    @needs_read_lock
 
2498
    def get_revision_delta(self, revision_id, specific_fileids=None):
 
2499
        r = self.get_revision(revision_id)
 
2500
        return list(self.get_deltas_for_revisions([r],
 
2501
            specific_fileids=specific_fileids))[0]
 
2502
 
 
2503
    @needs_read_lock
2565
2504
    def revision_trees(self, revision_ids):
2566
 
        with self.lock_read():
2567
 
            inventories = self.iter_inventories(revision_ids)
2568
 
            for inv in inventories:
2569
 
                yield RemoteInventoryTree(self, inv, inv.revision_id)
 
2505
        inventories = self.iter_inventories(revision_ids)
 
2506
        for inv in inventories:
 
2507
            yield InventoryRevisionTree(self, inv, inv.revision_id)
2570
2508
 
 
2509
    @needs_read_lock
2571
2510
    def get_revision_reconcile(self, revision_id):
2572
 
        with self.lock_read():
2573
 
            self._ensure_real()
2574
 
            return self._real_repository.get_revision_reconcile(revision_id)
 
2511
        self._ensure_real()
 
2512
        return self._real_repository.get_revision_reconcile(revision_id)
2575
2513
 
 
2514
    @needs_read_lock
2576
2515
    def check(self, revision_ids=None, callback_refs=None, check_repo=True):
2577
 
        with self.lock_read():
2578
 
            self._ensure_real()
2579
 
            return self._real_repository.check(revision_ids=revision_ids,
2580
 
                                               callback_refs=callback_refs, check_repo=check_repo)
 
2516
        self._ensure_real()
 
2517
        return self._real_repository.check(revision_ids=revision_ids,
 
2518
            callback_refs=callback_refs, check_repo=check_repo)
2581
2519
 
2582
2520
    def copy_content_into(self, destination, revision_id=None):
2583
2521
        """Make a complete copy of the content in self into destination.
2600
2538
        destination = to_bzrdir.create_repository()
2601
2539
        try:
2602
2540
            tar = tarfile.open('repository', fileobj=tar_file,
2603
 
                               mode='r|bz2')
 
2541
                mode='r|bz2')
2604
2542
            tmpdir = osutils.mkdtemp()
2605
2543
            try:
2606
 
                tar.extractall(tmpdir)
 
2544
                _extract_tar(tar, tmpdir)
2607
2545
                tmp_bzrdir = _mod_bzrdir.BzrDir.open(tmpdir)
2608
2546
                tmp_repo = tmp_bzrdir.open_repository()
2609
2547
                tmp_repo.copy_content_into(destination, revision_id)
2625
2563
        self._ensure_real()
2626
2564
        return self._real_repository.inventories
2627
2565
 
 
2566
    @needs_write_lock
2628
2567
    def pack(self, hint=None, clean_obsolete_packs=False):
2629
2568
        """Compress the data within the repository.
2630
2569
        """
2631
2570
        if hint is None:
2632
 
            body = b""
 
2571
            body = ""
2633
2572
        else:
2634
 
            body = b"".join([l.encode('ascii') + b"\n" for l in hint])
2635
 
        with self.lock_write():
2636
 
            path = self.controldir._path_for_remote_call(self._client)
2637
 
            try:
2638
 
                response, handler = self._call_with_body_bytes_expecting_body(
2639
 
                    b'Repository.pack', (path, self._lock_token,
2640
 
                                         str(clean_obsolete_packs).encode('ascii')), body)
2641
 
            except errors.UnknownSmartMethod:
2642
 
                self._ensure_real()
2643
 
                return self._real_repository.pack(hint=hint,
2644
 
                                                  clean_obsolete_packs=clean_obsolete_packs)
2645
 
            handler.cancel_read_body()
2646
 
            if response != (b'ok', ):
2647
 
                raise errors.UnexpectedSmartServerResponse(response)
 
2573
            body = "".join([l+"\n" for l in hint])
 
2574
        path = self.bzrdir._path_for_remote_call(self._client)
 
2575
        try:
 
2576
            response, handler = self._call_with_body_bytes_expecting_body(
 
2577
                'Repository.pack', (path, self._lock_token,
 
2578
                    str(clean_obsolete_packs)), body)
 
2579
        except errors.UnknownSmartMethod:
 
2580
            self._ensure_real()
 
2581
            return self._real_repository.pack(hint=hint,
 
2582
                clean_obsolete_packs=clean_obsolete_packs)
 
2583
        handler.cancel_read_body()
 
2584
        if response != ('ok', ):
 
2585
            raise errors.UnexpectedSmartServerResponse(response)
2648
2586
 
2649
2587
    @property
2650
2588
    def revisions(self):
2657
2595
 
2658
2596
    def set_make_working_trees(self, new_value):
2659
2597
        if new_value:
2660
 
            new_value_str = b"True"
 
2598
            new_value_str = "True"
2661
2599
        else:
2662
 
            new_value_str = b"False"
2663
 
        path = self.controldir._path_for_remote_call(self._client)
 
2600
            new_value_str = "False"
 
2601
        path = self.bzrdir._path_for_remote_call(self._client)
2664
2602
        try:
2665
2603
            response = self._call(
2666
 
                b'Repository.set_make_working_trees', path, new_value_str)
 
2604
                'Repository.set_make_working_trees', path, new_value_str)
2667
2605
        except errors.UnknownSmartMethod:
2668
2606
            self._ensure_real()
2669
2607
            self._real_repository.set_make_working_trees(new_value)
2670
2608
        else:
2671
 
            if response[0] != b'ok':
 
2609
            if response[0] != 'ok':
2672
2610
                raise errors.UnexpectedSmartServerResponse(response)
2673
2611
 
2674
2612
    @property
2681
2619
        self._ensure_real()
2682
2620
        return self._real_repository.signatures
2683
2621
 
 
2622
    @needs_write_lock
2684
2623
    def sign_revision(self, revision_id, gpg_strategy):
2685
 
        with self.lock_write():
2686
 
            testament = _mod_testament.Testament.from_revision(
2687
 
                self, revision_id)
2688
 
            plaintext = testament.as_short_text()
2689
 
            self.store_revision_signature(gpg_strategy, plaintext, revision_id)
 
2624
        testament = _mod_testament.Testament.from_revision(self, revision_id)
 
2625
        plaintext = testament.as_short_text()
 
2626
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
2690
2627
 
2691
2628
    @property
2692
2629
    def texts(self):
2699
2636
        return self._real_repository.texts
2700
2637
 
2701
2638
    def _iter_revisions_rpc(self, revision_ids):
2702
 
        body = b"\n".join(revision_ids)
2703
 
        path = self.controldir._path_for_remote_call(self._client)
 
2639
        body = "\n".join(revision_ids)
 
2640
        path = self.bzrdir._path_for_remote_call(self._client)
2704
2641
        response_tuple, response_handler = (
2705
2642
            self._call_with_body_bytes_expecting_body(
2706
 
                b"Repository.iter_revisions", (path, ), body))
2707
 
        if response_tuple[0] != b"ok":
 
2643
            "Repository.iter_revisions", (path, ), body))
 
2644
        if response_tuple[0] != "ok":
2708
2645
            raise errors.UnexpectedSmartServerResponse(response_tuple)
2709
 
        serializer_format = response_tuple[1].decode('ascii')
 
2646
        serializer_format = response_tuple[1]
2710
2647
        serializer = serializer_format_registry.get(serializer_format)
2711
2648
        byte_stream = response_handler.read_streamed_body()
2712
2649
        decompressor = zlib.decompressobj()
2713
2650
        chunks = []
2714
2651
        for bytes in byte_stream:
2715
2652
            chunks.append(decompressor.decompress(bytes))
2716
 
            if decompressor.unused_data != b"":
 
2653
            if decompressor.unused_data != "":
2717
2654
                chunks.append(decompressor.flush())
2718
 
                yield serializer.read_revision_from_string(b"".join(chunks))
 
2655
                yield serializer.read_revision_from_string("".join(chunks))
2719
2656
                unused = decompressor.unused_data
2720
2657
                decompressor = zlib.decompressobj()
2721
2658
                chunks = [decompressor.decompress(unused)]
2722
2659
        chunks.append(decompressor.flush())
2723
 
        text = b"".join(chunks)
2724
 
        if text != b"":
2725
 
            yield serializer.read_revision_from_string(b"".join(chunks))
 
2660
        text = "".join(chunks)
 
2661
        if text != "":
 
2662
            yield serializer.read_revision_from_string("".join(chunks))
2726
2663
 
2727
 
    def iter_revisions(self, revision_ids):
2728
 
        for rev_id in revision_ids:
2729
 
            if not rev_id or not isinstance(rev_id, bytes):
2730
 
                raise errors.InvalidRevisionId(
2731
 
                    revision_id=rev_id, branch=self)
2732
 
        with self.lock_read():
2733
 
            try:
2734
 
                missing = set(revision_ids)
2735
 
                for rev in self._iter_revisions_rpc(revision_ids):
2736
 
                    missing.remove(rev.revision_id)
2737
 
                    yield (rev.revision_id, rev)
2738
 
                for fallback in self._fallback_repositories:
2739
 
                    if not missing:
2740
 
                        break
2741
 
                    for (revid, rev) in fallback.iter_revisions(missing):
2742
 
                        if rev is not None:
2743
 
                            yield (revid, rev)
2744
 
                            missing.remove(revid)
2745
 
                for revid in missing:
2746
 
                    yield (revid, None)
2747
 
            except errors.UnknownSmartMethod:
2748
 
                self._ensure_real()
2749
 
                for entry in self._real_repository.iter_revisions(revision_ids):
2750
 
                    yield entry
 
2664
    @needs_read_lock
 
2665
    def get_revisions(self, revision_ids):
 
2666
        if revision_ids is None:
 
2667
            revision_ids = self.all_revision_ids()
 
2668
        else:
 
2669
            for rev_id in revision_ids:
 
2670
                if not rev_id or not isinstance(rev_id, basestring):
 
2671
                    raise errors.InvalidRevisionId(
 
2672
                        revision_id=rev_id, branch=self)
 
2673
        try:
 
2674
            missing = set(revision_ids)
 
2675
            revs = {}
 
2676
            for rev in self._iter_revisions_rpc(revision_ids):
 
2677
                missing.remove(rev.revision_id)
 
2678
                revs[rev.revision_id] = rev
 
2679
        except errors.UnknownSmartMethod:
 
2680
            self._ensure_real()
 
2681
            return self._real_repository.get_revisions(revision_ids)
 
2682
        for fallback in self._fallback_repositories:
 
2683
            if not missing:
 
2684
                break
 
2685
            for revid in list(missing):
 
2686
                # XXX JRV 2011-11-20: It would be nice if there was a
 
2687
                # public method on Repository that could be used to query
 
2688
                # for revision objects *without* failing completely if one
 
2689
                # was missing. There is VersionedFileRepository._iter_revisions,
 
2690
                # but unfortunately that's private and not provided by
 
2691
                # all repository implementations.
 
2692
                try:
 
2693
                    revs[revid] = fallback.get_revision(revid)
 
2694
                except errors.NoSuchRevision:
 
2695
                    pass
 
2696
                else:
 
2697
                    missing.remove(revid)
 
2698
        if missing:
 
2699
            raise errors.NoSuchRevision(self, list(missing)[0])
 
2700
        return [revs[revid] for revid in revision_ids]
2751
2701
 
2752
2702
    def supports_rich_root(self):
2753
2703
        return self._format.rich_root_data
2756
2706
    def _serializer(self):
2757
2707
        return self._format._serializer
2758
2708
 
 
2709
    @needs_write_lock
2759
2710
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
2760
 
        with self.lock_write():
2761
 
            signature = gpg_strategy.sign(plaintext, gpg.MODE_CLEAR)
2762
 
            self.add_signature_text(revision_id, signature)
 
2711
        signature = gpg_strategy.sign(plaintext)
 
2712
        self.add_signature_text(revision_id, signature)
2763
2713
 
2764
2714
    def add_signature_text(self, revision_id, signature):
2765
2715
        if self._real_repository:
2768
2718
            self._ensure_real()
2769
2719
            return self._real_repository.add_signature_text(
2770
2720
                revision_id, signature)
2771
 
        path = self.controldir._path_for_remote_call(self._client)
 
2721
        path = self.bzrdir._path_for_remote_call(self._client)
2772
2722
        response, handler = self._call_with_body_bytes_expecting_body(
2773
 
            b'Repository.add_signature_text', (path, self._lock_token,
2774
 
                                               revision_id) +
2775
 
            tuple([token.encode('utf-8')
2776
 
                   for token in self._write_group_tokens]),
2777
 
            signature)
 
2723
            'Repository.add_signature_text', (path, self._lock_token,
 
2724
                revision_id) + tuple(self._write_group_tokens), signature)
2778
2725
        handler.cancel_read_body()
2779
2726
        self.refresh_data()
2780
 
        if response[0] != b'ok':
 
2727
        if response[0] != 'ok':
2781
2728
            raise errors.UnexpectedSmartServerResponse(response)
2782
 
        self._write_group_tokens = [token.decode(
2783
 
            'utf-8') for token in response[1:]]
 
2729
        self._write_group_tokens = response[1:]
2784
2730
 
2785
2731
    def has_signature_for_revision_id(self, revision_id):
2786
 
        path = self.controldir._path_for_remote_call(self._client)
 
2732
        path = self.bzrdir._path_for_remote_call(self._client)
2787
2733
        try:
2788
 
            response = self._call(b'Repository.has_signature_for_revision_id',
2789
 
                                  path, revision_id)
 
2734
            response = self._call('Repository.has_signature_for_revision_id',
 
2735
                path, revision_id)
2790
2736
        except errors.UnknownSmartMethod:
2791
2737
            self._ensure_real()
2792
2738
            return self._real_repository.has_signature_for_revision_id(
2793
2739
                revision_id)
2794
 
        if response[0] not in (b'yes', b'no'):
2795
 
            raise SmartProtocolError(
2796
 
                'unexpected response code %s' % (response,))
2797
 
        if response[0] == b'yes':
 
2740
        if response[0] not in ('yes', 'no'):
 
2741
            raise SmartProtocolError('unexpected response code %s' % (response,))
 
2742
        if response[0] == 'yes':
2798
2743
            return True
2799
2744
        for fallback in self._fallback_repositories:
2800
2745
            if fallback.has_signature_for_revision_id(revision_id):
2801
2746
                return True
2802
2747
        return False
2803
2748
 
 
2749
    @needs_read_lock
2804
2750
    def verify_revision_signature(self, revision_id, gpg_strategy):
2805
 
        with self.lock_read():
2806
 
            if not self.has_signature_for_revision_id(revision_id):
2807
 
                return gpg.SIGNATURE_NOT_SIGNED, None
2808
 
            signature = self.get_signature_text(revision_id)
2809
 
 
2810
 
            testament = _mod_testament.Testament.from_revision(
2811
 
                self, revision_id)
2812
 
 
2813
 
            (status, key, signed_plaintext) = gpg_strategy.verify(signature)
2814
 
            if testament.as_short_text() != signed_plaintext:
2815
 
                return gpg.SIGNATURE_NOT_VALID, None
2816
 
            return (status, key)
 
2751
        if not self.has_signature_for_revision_id(revision_id):
 
2752
            return gpg.SIGNATURE_NOT_SIGNED, None
 
2753
        signature = self.get_signature_text(revision_id)
 
2754
 
 
2755
        testament = _mod_testament.Testament.from_revision(self, revision_id)
 
2756
        plaintext = testament.as_short_text()
 
2757
 
 
2758
        return gpg_strategy.verify(signature, plaintext)
2817
2759
 
2818
2760
    def item_keys_introduced_by(self, revision_ids, _files_pb=None):
2819
2761
        self._ensure_real()
2820
2762
        return self._real_repository.item_keys_introduced_by(revision_ids,
2821
 
                                                             _files_pb=_files_pb)
 
2763
            _files_pb=_files_pb)
2822
2764
 
2823
2765
    def _find_inconsistent_revision_parents(self, revisions_iterator=None):
2824
2766
        self._ensure_real()
2842
2784
        :param recipe: A search recipe (start, stop, count).
2843
2785
        :return: Serialised bytes.
2844
2786
        """
2845
 
        start_keys = b' '.join(recipe[1])
2846
 
        stop_keys = b' '.join(recipe[2])
2847
 
        count = str(recipe[3]).encode('ascii')
2848
 
        return b'\n'.join((start_keys, stop_keys, count))
 
2787
        start_keys = ' '.join(recipe[1])
 
2788
        stop_keys = ' '.join(recipe[2])
 
2789
        count = str(recipe[3])
 
2790
        return '\n'.join((start_keys, stop_keys, count))
2849
2791
 
2850
2792
    def _serialise_search_result(self, search_result):
2851
2793
        parts = search_result.get_network_struct()
2852
 
        return b'\n'.join(parts)
 
2794
        return '\n'.join(parts)
2853
2795
 
2854
2796
    def autopack(self):
2855
 
        path = self.controldir._path_for_remote_call(self._client)
 
2797
        path = self.bzrdir._path_for_remote_call(self._client)
2856
2798
        try:
2857
 
            response = self._call(b'PackRepository.autopack', path)
 
2799
            response = self._call('PackRepository.autopack', path)
2858
2800
        except errors.UnknownSmartMethod:
2859
2801
            self._ensure_real()
2860
2802
            self._real_repository._pack_collection.autopack()
2861
2803
            return
2862
2804
        self.refresh_data()
2863
 
        if response[0] != b'ok':
2864
 
            raise errors.UnexpectedSmartServerResponse(response)
2865
 
 
2866
 
    def _revision_archive(self, revision_id, format, name, root, subdir,
2867
 
                          force_mtime=None):
2868
 
        path = self.controldir._path_for_remote_call(self._client)
2869
 
        format = format or ''
2870
 
        root = root or ''
2871
 
        subdir = subdir or ''
2872
 
        force_mtime = int(force_mtime) if force_mtime is not None else None
2873
 
        try:
2874
 
            response, protocol = self._call_expecting_body(
2875
 
                b'Repository.revision_archive', path,
2876
 
                revision_id,
2877
 
                format.encode('ascii'),
2878
 
                os.path.basename(name).encode('utf-8'),
2879
 
                root.encode('utf-8'),
2880
 
                subdir.encode('utf-8'),
2881
 
                force_mtime)
2882
 
        except errors.UnknownSmartMethod:
2883
 
            return None
2884
 
        if response[0] == b'ok':
2885
 
            return iter([protocol.read_body_bytes()])
2886
 
        raise errors.UnexpectedSmartServerResponse(response)
2887
 
 
2888
 
    def _annotate_file_revision(self, revid, tree_path, file_id, default_revision):
2889
 
        path = self.controldir._path_for_remote_call(self._client)
2890
 
        tree_path = tree_path.encode('utf-8')
2891
 
        file_id = file_id or b''
2892
 
        default_revision = default_revision or b''
2893
 
        try:
2894
 
            response, handler = self._call_expecting_body(
2895
 
                b'Repository.annotate_file_revision', path,
2896
 
                revid, tree_path, file_id, default_revision)
2897
 
        except errors.UnknownSmartMethod:
2898
 
            return None
2899
 
        if response[0] != b'ok':
2900
 
            raise errors.UnexpectedSmartServerResponse(response)
2901
 
        return map(tuple, bencode.bdecode(handler.read_body_bytes()))
 
2805
        if response[0] != 'ok':
 
2806
            raise errors.UnexpectedSmartServerResponse(response)
2902
2807
 
2903
2808
 
2904
2809
class RemoteStreamSink(vf_repository.StreamSink):
2911
2816
            self.target_repo.autopack()
2912
2817
        return result
2913
2818
 
2914
 
    def insert_missing_keys(self, source, missing_keys):
2915
 
        if (isinstance(source, RemoteStreamSource)
2916
 
                and source.from_repository._client._medium == self.target_repo._client._medium):
2917
 
            # Streaming from and to the same medium is tricky, since we don't support
2918
 
            # more than one concurrent request. For now, just force VFS.
2919
 
            stream = source._get_real_stream_for_missing_keys(missing_keys)
2920
 
        else:
2921
 
            stream = source.get_stream_for_missing_keys(missing_keys)
2922
 
        return self.insert_stream_without_locking(stream,
2923
 
                                                  self.target_repo._format)
2924
 
 
2925
2819
    def insert_stream(self, stream, src_format, resume_tokens):
2926
2820
        target = self.target_repo
2927
2821
        target._unstacked_provider.missing_keys.clear()
2928
 
        candidate_calls = [(b'Repository.insert_stream_1.19', (1, 19))]
 
2822
        candidate_calls = [('Repository.insert_stream_1.19', (1, 19))]
2929
2823
        if target._lock_token:
2930
 
            candidate_calls.append(
2931
 
                (b'Repository.insert_stream_locked', (1, 14)))
2932
 
            lock_args = (target._lock_token or b'',)
 
2824
            candidate_calls.append(('Repository.insert_stream_locked', (1, 14)))
 
2825
            lock_args = (target._lock_token or '',)
2933
2826
        else:
2934
 
            candidate_calls.append((b'Repository.insert_stream', (1, 13)))
 
2827
            candidate_calls.append(('Repository.insert_stream', (1, 13)))
2935
2828
            lock_args = ()
2936
2829
        client = target._client
2937
2830
        medium = client._medium
2938
 
        path = target.controldir._path_for_remote_call(client)
 
2831
        path = target.bzrdir._path_for_remote_call(client)
2939
2832
        # Probe for the verb to use with an empty stream before sending the
2940
2833
        # real stream to it.  We do this both to avoid the risk of sending a
2941
2834
        # large request that is then rejected, and because we don't want to
2952
2845
            byte_stream = smart_repo._stream_to_byte_stream([], src_format)
2953
2846
            try:
2954
2847
                response = client.call_with_body_stream(
2955
 
                    (verb, path, b'') + lock_args, byte_stream)
 
2848
                    (verb, path, '') + lock_args, byte_stream)
2956
2849
            except errors.UnknownSmartMethod:
2957
2850
                medium._remember_remote_is_before(required_version)
2958
2851
            else:
2971
2864
            stream = self._stop_stream_if_inventory_delta(stream)
2972
2865
        byte_stream = smart_repo._stream_to_byte_stream(
2973
2866
            stream, src_format)
2974
 
        resume_tokens = b' '.join([token.encode('utf-8')
2975
 
                                   for token in resume_tokens])
 
2867
        resume_tokens = ' '.join(resume_tokens)
2976
2868
        response = client.call_with_body_stream(
2977
2869
            (verb, path, resume_tokens) + lock_args, byte_stream)
2978
 
        if response[0][0] not in (b'ok', b'missing-basis'):
 
2870
        if response[0][0] not in ('ok', 'missing-basis'):
2979
2871
            raise errors.UnexpectedSmartServerResponse(response)
2980
2872
        if self._last_substream is not None:
2981
2873
            # The stream included an inventory-delta record, but the remote
2983
2875
            # rest of the stream via VFS.
2984
2876
            self.target_repo.refresh_data()
2985
2877
            return self._resume_stream_with_vfs(response, src_format)
2986
 
        if response[0][0] == b'missing-basis':
 
2878
        if response[0][0] == 'missing-basis':
2987
2879
            tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
2988
 
            resume_tokens = [token.decode('utf-8') for token in tokens]
2989
 
            return resume_tokens, set((entry[0].decode('utf-8'), ) + entry[1:] for entry in missing_keys)
 
2880
            resume_tokens = tokens
 
2881
            return resume_tokens, set(missing_keys)
2990
2882
        else:
2991
2883
            self.target_repo.refresh_data()
2992
2884
            return [], set()
2995
2887
        """Resume sending a stream via VFS, first resending the record and
2996
2888
        substream that couldn't be sent via an insert_stream verb.
2997
2889
        """
2998
 
        if response[0][0] == b'missing-basis':
 
2890
        if response[0][0] == 'missing-basis':
2999
2891
            tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
3000
 
            tokens = [token.decode('utf-8') for token in tokens]
3001
2892
            # Ignore missing_keys, we haven't finished inserting yet
3002
2893
        else:
3003
2894
            tokens = []
3004
 
 
3005
2895
        def resume_substream():
3006
2896
            # Yield the substream that was interrupted.
3007
2897
            for record in self._last_substream:
3008
2898
                yield record
3009
2899
            self._last_substream = None
3010
 
 
3011
2900
        def resume_stream():
3012
2901
            # Finish sending the interrupted substream
3013
2902
            yield ('inventory-deltas', resume_substream())
3039
2928
    """Stream data from a remote server."""
3040
2929
 
3041
2930
    def get_stream(self, search):
3042
 
        if (self.from_repository._fallback_repositories
3043
 
                and self.to_format._fetch_order == 'topological'):
 
2931
        if (self.from_repository._fallback_repositories and
 
2932
            self.to_format._fetch_order == 'topological'):
3044
2933
            return self._real_stream(self.from_repository, search)
3045
2934
        sources = []
3046
2935
        seen = set()
3054
2943
            sources.append(repo)
3055
2944
        return self.missing_parents_chain(search, sources)
3056
2945
 
3057
 
    def _get_real_stream_for_missing_keys(self, missing_keys):
 
2946
    def get_stream_for_missing_keys(self, missing_keys):
3058
2947
        self.from_repository._ensure_real()
3059
2948
        real_repo = self.from_repository._real_repository
3060
2949
        real_source = real_repo._get_source(self.to_format)
3061
2950
        return real_source.get_stream_for_missing_keys(missing_keys)
3062
2951
 
3063
 
    def get_stream_for_missing_keys(self, missing_keys):
3064
 
        if not isinstance(self.from_repository, RemoteRepository):
3065
 
            return self._get_real_stream_for_missing_keys(missing_keys)
3066
 
        client = self.from_repository._client
3067
 
        medium = client._medium
3068
 
        if medium._is_remote_before((3, 0)):
3069
 
            return self._get_real_stream_for_missing_keys(missing_keys)
3070
 
        path = self.from_repository.controldir._path_for_remote_call(client)
3071
 
        args = (path, self.to_format.network_name())
3072
 
        search_bytes = b'\n'.join(
3073
 
            [b'%s\t%s' % (key[0].encode('utf-8'), key[1]) for key in missing_keys])
3074
 
        try:
3075
 
            response, handler = self.from_repository._call_with_body_bytes_expecting_body(
3076
 
                b'Repository.get_stream_for_missing_keys', args, search_bytes)
3077
 
        except (errors.UnknownSmartMethod, errors.UnknownFormatError):
3078
 
            return self._get_real_stream_for_missing_keys(missing_keys)
3079
 
        if response[0] != b'ok':
3080
 
            raise errors.UnexpectedSmartServerResponse(response)
3081
 
        byte_stream = handler.read_streamed_body()
3082
 
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
3083
 
                                                               self._record_counter)
3084
 
        if src_format.network_name() != self.from_repository._format.network_name():
3085
 
            raise AssertionError(
3086
 
                "Mismatched RemoteRepository and stream src %r, %r" % (
3087
 
                    src_format.network_name(), repo._format.network_name()))
3088
 
        return stream
3089
 
 
3090
2952
    def _real_stream(self, repo, search):
3091
2953
        """Get a stream for search from repo.
3092
2954
 
3122
2984
            return self._real_stream(repo, search)
3123
2985
        client = repo._client
3124
2986
        medium = client._medium
3125
 
        path = repo.controldir._path_for_remote_call(client)
 
2987
        path = repo.bzrdir._path_for_remote_call(client)
3126
2988
        search_bytes = repo._serialise_search_result(search)
3127
2989
        args = (path, self.to_format.network_name())
3128
2990
        candidate_verbs = [
3129
 
            (b'Repository.get_stream_1.19', (1, 19)),
3130
 
            (b'Repository.get_stream', (1, 13))]
 
2991
            ('Repository.get_stream_1.19', (1, 19)),
 
2992
            ('Repository.get_stream', (1, 13))]
3131
2993
 
3132
2994
        found_verb = False
3133
2995
        for verb, version in candidate_verbs:
3138
3000
                    verb, args, search_bytes)
3139
3001
            except errors.UnknownSmartMethod:
3140
3002
                medium._remember_remote_is_before(version)
3141
 
            except errors.UnknownErrorFromSmartServer as e:
 
3003
            except errors.UnknownErrorFromSmartServer, e:
3142
3004
                if isinstance(search, vf_search.EverythingResult):
3143
3005
                    error_verb = e.error_from_smart_server.error_verb
3144
 
                    if error_verb == b'BadSearch':
 
3006
                    if error_verb == 'BadSearch':
3145
3007
                        # Pre-2.4 servers don't support this sort of search.
3146
3008
                        # XXX: perhaps falling back to VFS on BadSearch is a
3147
3009
                        # good idea in general?  It might provide a little bit
3155
3017
                break
3156
3018
        if not found_verb:
3157
3019
            return self._real_stream(repo, search)
3158
 
        if response_tuple[0] != b'ok':
 
3020
        if response_tuple[0] != 'ok':
3159
3021
            raise errors.UnexpectedSmartServerResponse(response_tuple)
3160
3022
        byte_stream = response_handler.read_streamed_body()
3161
3023
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
3162
 
                                                               self._record_counter)
 
3024
            self._record_counter)
3163
3025
        if src_format.network_name() != repo._format.network_name():
3164
3026
            raise AssertionError(
3165
3027
                "Mismatched RemoteRepository and stream src %r, %r" % (
3166
 
                    src_format.network_name(), repo._format.network_name()))
 
3028
                src_format.network_name(), repo._format.network_name()))
3167
3029
        return stream
3168
3030
 
3169
3031
    def missing_parents_chain(self, search, sources):
3209
3071
    """
3210
3072
 
3211
3073
    def __init__(self, bzrdir, _client):
3212
 
        self.controldir = bzrdir
 
3074
        self.bzrdir = bzrdir
3213
3075
        self._client = _client
3214
3076
        self._need_find_modes = True
3215
3077
        LockableFiles.__init__(
3226
3088
 
3227
3089
    def __init__(self, network_name=None):
3228
3090
        super(RemoteBranchFormat, self).__init__()
3229
 
        self._matchingcontroldir = RemoteBzrDirFormat()
3230
 
        self._matchingcontroldir.set_branch_format(self)
 
3091
        self._matchingbzrdir = RemoteBzrDirFormat()
 
3092
        self._matchingbzrdir.set_branch_format(self)
3231
3093
        self._custom_format = None
3232
3094
        self._network_name = network_name
3233
3095
 
3234
3096
    def __eq__(self, other):
3235
 
        return (isinstance(other, RemoteBranchFormat)
3236
 
                and self.__dict__ == other.__dict__)
 
3097
        return (isinstance(other, RemoteBranchFormat) and
 
3098
            self.__dict__ == other.__dict__)
3237
3099
 
3238
3100
    def _ensure_real(self):
3239
3101
        if self._custom_format is None:
3242
3104
                    self._network_name)
3243
3105
            except KeyError:
3244
3106
                raise errors.UnknownFormatError(kind='branch',
3245
 
                                                format=self._network_name)
 
3107
                    format=self._network_name)
3246
3108
 
3247
3109
    def get_format_description(self):
3248
3110
        self._ensure_real()
3251
3113
    def network_name(self):
3252
3114
        return self._network_name
3253
3115
 
3254
 
    def open(self, a_controldir, name=None, ignore_fallbacks=False):
3255
 
        return a_controldir.open_branch(name=name,
3256
 
                                        ignore_fallbacks=ignore_fallbacks)
 
3116
    def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
 
3117
        return a_bzrdir.open_branch(name=name, 
 
3118
            ignore_fallbacks=ignore_fallbacks)
3257
3119
 
3258
 
    def _vfs_initialize(self, a_controldir, name, append_revisions_only,
 
3120
    def _vfs_initialize(self, a_bzrdir, name, append_revisions_only,
3259
3121
                        repository=None):
3260
3122
        # Initialisation when using a local bzrdir object, or a non-vfs init
3261
3123
        # method is not available on the server.
3262
3124
        # self._custom_format is always set - the start of initialize ensures
3263
3125
        # that.
3264
 
        if isinstance(a_controldir, RemoteBzrDir):
3265
 
            a_controldir._ensure_real()
3266
 
            result = self._custom_format.initialize(a_controldir._real_bzrdir,
3267
 
                                                    name=name, append_revisions_only=append_revisions_only,
3268
 
                                                    repository=repository)
 
3126
        if isinstance(a_bzrdir, RemoteBzrDir):
 
3127
            a_bzrdir._ensure_real()
 
3128
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
 
3129
                name=name, append_revisions_only=append_revisions_only,
 
3130
                repository=repository)
3269
3131
        else:
3270
3132
            # We assume the bzrdir is parameterised; it may not be.
3271
 
            result = self._custom_format.initialize(a_controldir, name=name,
3272
 
                                                    append_revisions_only=append_revisions_only,
3273
 
                                                    repository=repository)
3274
 
        if (isinstance(a_controldir, RemoteBzrDir)
3275
 
                and not isinstance(result, RemoteBranch)):
3276
 
            result = RemoteBranch(a_controldir, a_controldir.find_repository(), result,
 
3133
            result = self._custom_format.initialize(a_bzrdir, name=name,
 
3134
                append_revisions_only=append_revisions_only,
 
3135
                repository=repository)
 
3136
        if (isinstance(a_bzrdir, RemoteBzrDir) and
 
3137
            not isinstance(result, RemoteBranch)):
 
3138
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
3277
3139
                                  name=name)
3278
3140
        return result
3279
3141
 
3280
 
    def initialize(self, a_controldir, name=None, repository=None,
 
3142
    def initialize(self, a_bzrdir, name=None, repository=None,
3281
3143
                   append_revisions_only=None):
3282
3144
        if name is None:
3283
 
            name = a_controldir._get_selected_branch()
 
3145
            name = a_bzrdir._get_selected_branch()
3284
3146
        # 1) get the network name to use.
3285
3147
        if self._custom_format:
3286
3148
            network_name = self._custom_format.network_name()
3287
3149
        else:
3288
 
            # Select the current breezy default and ask for that.
3289
 
            reference_bzrdir_format = controldir.format_registry.get(
3290
 
                'default')()
 
3150
            # Select the current bzrlib default and ask for that.
 
3151
            reference_bzrdir_format = controldir.format_registry.get('default')()
3291
3152
            reference_format = reference_bzrdir_format.get_branch_format()
3292
3153
            self._custom_format = reference_format
3293
3154
            network_name = reference_format.network_name()
3294
3155
        # Being asked to create on a non RemoteBzrDir:
3295
 
        if not isinstance(a_controldir, RemoteBzrDir):
3296
 
            return self._vfs_initialize(a_controldir, name=name,
3297
 
                                        append_revisions_only=append_revisions_only,
3298
 
                                        repository=repository)
3299
 
        medium = a_controldir._client._medium
 
3156
        if not isinstance(a_bzrdir, RemoteBzrDir):
 
3157
            return self._vfs_initialize(a_bzrdir, name=name,
 
3158
                append_revisions_only=append_revisions_only,
 
3159
                repository=repository)
 
3160
        medium = a_bzrdir._client._medium
3300
3161
        if medium._is_remote_before((1, 13)):
3301
 
            return self._vfs_initialize(a_controldir, name=name,
3302
 
                                        append_revisions_only=append_revisions_only,
3303
 
                                        repository=repository)
 
3162
            return self._vfs_initialize(a_bzrdir, name=name,
 
3163
                append_revisions_only=append_revisions_only,
 
3164
                repository=repository)
3304
3165
        # Creating on a remote bzr dir.
3305
3166
        # 2) try direct creation via RPC
3306
 
        path = a_controldir._path_for_remote_call(a_controldir._client)
 
3167
        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
3307
3168
        if name != "":
3308
3169
            # XXX JRV20100304: Support creating colocated branches
3309
3170
            raise errors.NoColocatedBranchSupport(self)
3310
 
        verb = b'BzrDir.create_branch'
 
3171
        verb = 'BzrDir.create_branch'
3311
3172
        try:
3312
 
            response = a_controldir._call(verb, path, network_name)
 
3173
            response = a_bzrdir._call(verb, path, network_name)
3313
3174
        except errors.UnknownSmartMethod:
3314
3175
            # Fallback - use vfs methods
3315
3176
            medium._remember_remote_is_before((1, 13))
3316
 
            return self._vfs_initialize(a_controldir, name=name,
3317
 
                                        append_revisions_only=append_revisions_only,
3318
 
                                        repository=repository)
3319
 
        if response[0] != b'ok':
 
3177
            return self._vfs_initialize(a_bzrdir, name=name,
 
3178
                    append_revisions_only=append_revisions_only,
 
3179
                    repository=repository)
 
3180
        if response[0] != 'ok':
3320
3181
            raise errors.UnexpectedSmartServerResponse(response)
3321
3182
        # Turn the response into a RemoteRepository object.
3322
3183
        format = RemoteBranchFormat(network_name=response[1])
3323
3184
        repo_format = response_tuple_to_repo_format(response[3:])
3324
 
        repo_path = response[2].decode('utf-8')
 
3185
        repo_path = response[2]
3325
3186
        if repository is not None:
3326
 
            remote_repo_url = urlutils.join(a_controldir.user_url, repo_path)
 
3187
            remote_repo_url = urlutils.join(a_bzrdir.user_url, repo_path)
3327
3188
            url_diff = urlutils.relative_url(repository.user_url,
3328
 
                                             remote_repo_url)
 
3189
                    remote_repo_url)
3329
3190
            if url_diff != '.':
3330
3191
                raise AssertionError(
3331
3192
                    'repository.user_url %r does not match URL from server '
3332
3193
                    'response (%r + %r)'
3333
 
                    % (repository.user_url, a_controldir.user_url, repo_path))
 
3194
                    % (repository.user_url, a_bzrdir.user_url, repo_path))
3334
3195
            remote_repo = repository
3335
3196
        else:
3336
3197
            if repo_path == '':
3337
 
                repo_bzrdir = a_controldir
 
3198
                repo_bzrdir = a_bzrdir
3338
3199
            else:
3339
3200
                repo_bzrdir = RemoteBzrDir(
3340
 
                    a_controldir.root_transport.clone(
3341
 
                        repo_path), a_controldir._format,
3342
 
                    a_controldir._client)
 
3201
                    a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
 
3202
                    a_bzrdir._client)
3343
3203
            remote_repo = RemoteRepository(repo_bzrdir, repo_format)
3344
 
        remote_branch = RemoteBranch(a_controldir, remote_repo,
3345
 
                                     format=format, setup_stacking=False, name=name)
 
3204
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
 
3205
            format=format, setup_stacking=False, name=name)
3346
3206
        if append_revisions_only:
3347
3207
            remote_branch.set_append_revisions_only(append_revisions_only)
3348
3208
        # XXX: We know this is a new branch, so it must have revno 0, revid
3369
3229
        self._ensure_real()
3370
3230
        return self._custom_format.supports_set_append_revisions_only()
3371
3231
 
3372
 
    @property
3373
 
    def supports_reference_locations(self):
3374
 
        self._ensure_real()
3375
 
        return self._custom_format.supports_reference_locations
3376
 
 
3377
 
    def stores_revno(self):
3378
 
        return True
3379
 
 
3380
3232
    def _use_default_local_heads_to_fetch(self):
3381
3233
        # If the branch format is a metadir format *and* its heads_to_fetch
3382
3234
        # implementation is not overridden vs the base class, we can use the
3384
3236
        # usually cheaper in terms of net round trips, as the last-revision and
3385
3237
        # tags info fetched is cached and would be fetched anyway.
3386
3238
        self._ensure_real()
3387
 
        if isinstance(self._custom_format, bzrbranch.BranchFormatMetadir):
 
3239
        if isinstance(self._custom_format, branch.BranchFormatMetadir):
3388
3240
            branch_class = self._custom_format._branch_class()
3389
 
            heads_to_fetch_impl = branch_class.heads_to_fetch
3390
 
            if heads_to_fetch_impl is branch.Branch.heads_to_fetch:
 
3241
            heads_to_fetch_impl = branch_class.heads_to_fetch.im_func
 
3242
            if heads_to_fetch_impl is branch.Branch.heads_to_fetch.im_func:
3391
3243
                return True
3392
3244
        return False
3393
3245
 
3411
3263
        path = self.branch._remote_path()
3412
3264
        try:
3413
3265
            response, handler = self.branch._call_expecting_body(
3414
 
                b'Branch.get_config_file', path)
 
3266
                'Branch.get_config_file', path)
3415
3267
        except errors.UnknownSmartMethod:
3416
3268
            self._ensure_real()
3417
3269
            return self._real_store._load_content()
3418
 
        if len(response) and response[0] != b'ok':
 
3270
        if len(response) and response[0] != 'ok':
3419
3271
            raise errors.UnexpectedSmartServerResponse(response)
3420
3272
        return handler.read_body_bytes()
3421
3273
 
3423
3275
        path = self.branch._remote_path()
3424
3276
        try:
3425
3277
            response, handler = self.branch._call_with_body_bytes_expecting_body(
3426
 
                b'Branch.put_config_file', (path,
3427
 
                                            self.branch._lock_token, self.branch._repo_lock_token),
 
3278
                'Branch.put_config_file', (path,
 
3279
                    self.branch._lock_token, self.branch._repo_lock_token),
3428
3280
                content)
3429
3281
        except errors.UnknownSmartMethod:
3430
3282
            self._ensure_real()
3431
3283
            return self._real_store._save_content(content)
3432
3284
        handler.cancel_read_body()
3433
 
        if response != (b'ok', ):
 
3285
        if response != ('ok', ):
3434
3286
            raise errors.UnexpectedSmartServerResponse(response)
3435
3287
 
3436
3288
    def _ensure_real(self):
3446
3298
    """
3447
3299
 
3448
3300
    def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
3449
 
                 _client=None, format=None, setup_stacking=True, name=None,
3450
 
                 possible_transports=None):
 
3301
        _client=None, format=None, setup_stacking=True, name=None,
 
3302
        possible_transports=None):
3451
3303
        """Create a RemoteBranch instance.
3452
3304
 
3453
3305
        :param real_branch: An optional local implementation of the branch
3464
3316
        # We intentionally don't call the parent class's __init__, because it
3465
3317
        # will try to assign to self.tags, which is a property in this subclass.
3466
3318
        # And the parent's __init__ doesn't do much anyway.
3467
 
        self.controldir = remote_bzrdir
 
3319
        self.bzrdir = remote_bzrdir
3468
3320
        self.name = name
3469
3321
        if _client is not None:
3470
3322
            self._client = _client
3483
3335
            self._real_branch.repository = self.repository
3484
3336
        else:
3485
3337
            self._real_branch = None
3486
 
        # Fill out expected attributes of branch for breezy API users.
 
3338
        # Fill out expected attributes of branch for bzrlib API users.
3487
3339
        self._clear_cached_state()
3488
3340
        # TODO: deprecate self.base in favor of user_url
3489
 
        self.base = self.controldir.user_url
 
3341
        self.base = self.bzrdir.user_url
3490
3342
        self._name = name
3491
3343
        self._control_files = None
3492
3344
        self._lock_mode = None
3527
3379
        # the vfs branch.
3528
3380
        try:
3529
3381
            fallback_url = self.get_stacked_on_url()
3530
 
        except (errors.NotStacked, branch.UnstackableBranchFormat,
3531
 
                errors.UnstackableRepositoryFormat) as e:
 
3382
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
3383
            errors.UnstackableRepositoryFormat), e:
3532
3384
            return
3533
3385
        self._is_stacked = True
3534
3386
        if possible_transports is None:
3535
3387
            possible_transports = []
3536
3388
        else:
3537
3389
            possible_transports = list(possible_transports)
3538
 
        possible_transports.append(self.controldir.root_transport)
 
3390
        possible_transports.append(self.bzrdir.root_transport)
3539
3391
        self._activate_fallback_location(fallback_url,
3540
 
                                         possible_transports=possible_transports)
 
3392
            possible_transports=possible_transports)
3541
3393
 
3542
3394
    def _get_config(self):
3543
3395
        return RemoteBranchConfig(self)
3544
3396
 
3545
3397
    def _get_config_store(self):
3546
3398
        if self.conf_store is None:
3547
 
            self.conf_store = RemoteBranchStore(self)
 
3399
            self.conf_store =  RemoteBranchStore(self)
3548
3400
        return self.conf_store
3549
3401
 
3550
3402
    def store_uncommitted(self, creator):
3575
3427
        if self._real_branch is None:
3576
3428
            if not vfs.vfs_enabled():
3577
3429
                raise AssertionError('smart server vfs must be enabled '
3578
 
                                     'to use vfs implementation')
3579
 
            self.controldir._ensure_real()
3580
 
            self._real_branch = self.controldir._real_bzrdir.open_branch(
 
3430
                    'to use vfs implementation')
 
3431
            self.bzrdir._ensure_real()
 
3432
            self._real_branch = self.bzrdir._real_bzrdir.open_branch(
3581
3433
                ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
3582
3434
            # The remote branch and the real branch shares the same store. If
3583
3435
            # we don't, there will always be cases where one of the stores
3603
3455
 
3604
3456
    def _clear_cached_state(self):
3605
3457
        super(RemoteBranch, self)._clear_cached_state()
3606
 
        self._tags_bytes = None
3607
3458
        if self._real_branch is not None:
3608
3459
            self._real_branch._clear_cached_state()
3609
3460
 
3625
3476
        # because it triggers an _ensure_real that we otherwise might not need.
3626
3477
        if self._control_files is None:
3627
3478
            self._control_files = RemoteBranchLockableFiles(
3628
 
                self.controldir, self._client)
 
3479
                self.bzrdir, self._client)
3629
3480
        return self._control_files
3630
3481
 
3631
3482
    def get_physical_lock_status(self):
3632
3483
        """See Branch.get_physical_lock_status()."""
3633
3484
        try:
3634
 
            response = self._client.call(b'Branch.get_physical_lock_status',
3635
 
                                         self._remote_path())
 
3485
            response = self._client.call('Branch.get_physical_lock_status',
 
3486
                self._remote_path())
3636
3487
        except errors.UnknownSmartMethod:
3637
3488
            self._ensure_real()
3638
3489
            return self._real_branch.get_physical_lock_status()
3639
 
        if response[0] not in (b'yes', b'no'):
 
3490
        if response[0] not in ('yes', 'no'):
3640
3491
            raise errors.UnexpectedSmartServerResponse(response)
3641
 
        return (response[0] == b'yes')
 
3492
        return (response[0] == 'yes')
3642
3493
 
3643
3494
    def get_stacked_on_url(self):
3644
3495
        """Get the URL this branch is stacked against.
3652
3503
        try:
3653
3504
            # there may not be a repository yet, so we can't use
3654
3505
            # self._translate_error, so we can't use self._call either.
3655
 
            response = self._client.call(b'Branch.get_stacked_on_url',
3656
 
                                         self._remote_path())
3657
 
        except errors.ErrorFromSmartServer as err:
 
3506
            response = self._client.call('Branch.get_stacked_on_url',
 
3507
                self._remote_path())
 
3508
        except errors.ErrorFromSmartServer, err:
3658
3509
            # there may not be a repository yet, so we can't call through
3659
3510
            # its _translate_error
3660
3511
            _translate_error(err, branch=self)
3661
 
        except errors.UnknownSmartMethod as err:
 
3512
        except errors.UnknownSmartMethod, err:
3662
3513
            self._ensure_real()
3663
3514
            return self._real_branch.get_stacked_on_url()
3664
 
        if response[0] != b'ok':
 
3515
        if response[0] != 'ok':
3665
3516
            raise errors.UnexpectedSmartServerResponse(response)
3666
 
        return response[1].decode('utf-8')
 
3517
        return response[1]
3667
3518
 
3668
3519
    def set_stacked_on_url(self, url):
3669
3520
        branch.Branch.set_stacked_on_url(self, url)
3670
3521
        # We need the stacked_on_url to be visible both locally (to not query
3671
3522
        # it repeatedly) and remotely (so smart verbs can get it server side)
3672
3523
        # Without the following line,
3673
 
        # breezy.tests.per_branch.test_create_clone.TestCreateClone
 
3524
        # bzrlib.tests.per_branch.test_create_clone.TestCreateClone
3674
3525
        # .test_create_clone_on_transport_stacked_hooks_get_stacked_branch
3675
3526
        # fails for remote branches -- vila 2012-01-04
3676
3527
        self.conf_store.save_changes()
3683
3534
        self._ensure_real()
3684
3535
        return self._real_branch._get_tags_bytes()
3685
3536
 
 
3537
    @needs_read_lock
3686
3538
    def _get_tags_bytes(self):
3687
 
        with self.lock_read():
3688
 
            if self._tags_bytes is None:
3689
 
                self._tags_bytes = self._get_tags_bytes_via_hpss()
3690
 
            return self._tags_bytes
 
3539
        if self._tags_bytes is None:
 
3540
            self._tags_bytes = self._get_tags_bytes_via_hpss()
 
3541
        return self._tags_bytes
3691
3542
 
3692
3543
    def _get_tags_bytes_via_hpss(self):
3693
3544
        medium = self._client._medium
3694
3545
        if medium._is_remote_before((1, 13)):
3695
3546
            return self._vfs_get_tags_bytes()
3696
3547
        try:
3697
 
            response = self._call(
3698
 
                b'Branch.get_tags_bytes', self._remote_path())
 
3548
            response = self._call('Branch.get_tags_bytes', self._remote_path())
3699
3549
        except errors.UnknownSmartMethod:
3700
3550
            medium._remember_remote_is_before((1, 13))
3701
3551
            return self._vfs_get_tags_bytes()
3716
3566
            args = (
3717
3567
                self._remote_path(), self._lock_token, self._repo_lock_token)
3718
3568
            response = self._call_with_body_bytes(
3719
 
                b'Branch.set_tags_bytes', args, bytes)
 
3569
                'Branch.set_tags_bytes', args, bytes)
3720
3570
        except errors.UnknownSmartMethod:
3721
3571
            medium._remember_remote_is_before((1, 18))
3722
3572
            self._vfs_set_tags_bytes(bytes)
3724
3574
    def lock_read(self):
3725
3575
        """Lock the branch for read operations.
3726
3576
 
3727
 
        :return: A breezy.lock.LogicalLockResult.
 
3577
        :return: A bzrlib.lock.LogicalLockResult.
3728
3578
        """
3729
3579
        self.repository.lock_read()
3730
3580
        if not self._lock_mode:
3739
3589
 
3740
3590
    def _remote_lock_write(self, token):
3741
3591
        if token is None:
3742
 
            branch_token = repo_token = b''
 
3592
            branch_token = repo_token = ''
3743
3593
        else:
3744
3594
            branch_token = token
3745
3595
            repo_token = self.repository.lock_write().repository_token
3747
3597
        err_context = {'token': token}
3748
3598
        try:
3749
3599
            response = self._call(
3750
 
                b'Branch.lock_write', self._remote_path(), branch_token,
3751
 
                repo_token or b'', **err_context)
3752
 
        except errors.LockContention as e:
 
3600
                'Branch.lock_write', self._remote_path(), branch_token,
 
3601
                repo_token or '', **err_context)
 
3602
        except errors.LockContention, e:
3753
3603
            # The LockContention from the server doesn't have any
3754
3604
            # information about the lock_url. We re-raise LockContention
3755
3605
            # with valid lock_url.
3756
3606
            raise errors.LockContention('(remote lock)',
3757
 
                                        self.repository.base.split('.bzr/')[0])
3758
 
        if response[0] != b'ok':
 
3607
                self.repository.base.split('.bzr/')[0])
 
3608
        if response[0] != 'ok':
3759
3609
            raise errors.UnexpectedSmartServerResponse(response)
3760
3610
        ok, branch_token, repo_token = response
3761
3611
        return branch_token, repo_token
3767
3617
            remote_tokens = self._remote_lock_write(token)
3768
3618
            self._lock_token, self._repo_lock_token = remote_tokens
3769
3619
            if not self._lock_token:
3770
 
                raise SmartProtocolError(
3771
 
                    'Remote server did not return a token!')
 
3620
                raise SmartProtocolError('Remote server did not return a token!')
3772
3621
            # Tell the self.repository object that it is locked.
3773
3622
            self.repository.lock_write(
3774
3623
                self._repo_lock_token, _skip_rpc=True)
3798
3647
    def _unlock(self, branch_token, repo_token):
3799
3648
        err_context = {'token': str((branch_token, repo_token))}
3800
3649
        response = self._call(
3801
 
            b'Branch.unlock', self._remote_path(), branch_token,
3802
 
            repo_token or b'', **err_context)
3803
 
        if response == (b'ok',):
 
3650
            'Branch.unlock', self._remote_path(), branch_token,
 
3651
            repo_token or '', **err_context)
 
3652
        if response == ('ok',):
3804
3653
            return
3805
3654
        raise errors.UnexpectedSmartServerResponse(response)
3806
3655
 
3815
3664
                mode = self._lock_mode
3816
3665
                self._lock_mode = None
3817
3666
                if self._real_branch is not None:
3818
 
                    if (not self._leave_lock and mode == 'w'
3819
 
                            and self._repo_lock_token):
 
3667
                    if (not self._leave_lock and mode == 'w' and
 
3668
                        self._repo_lock_token):
3820
3669
                        # If this RemoteBranch will remove the physical lock
3821
3670
                        # for the repository, make sure the _real_branch
3822
3671
                        # doesn't do it first.  (Because the _real_branch's
3841
3690
    def break_lock(self):
3842
3691
        try:
3843
3692
            response = self._call(
3844
 
                b'Branch.break_lock', self._remote_path())
 
3693
                'Branch.break_lock', self._remote_path())
3845
3694
        except errors.UnknownSmartMethod:
3846
3695
            self._ensure_real()
3847
3696
            return self._real_branch.break_lock()
3848
 
        if response != (b'ok',):
 
3697
        if response != ('ok',):
3849
3698
            raise errors.UnexpectedSmartServerResponse(response)
3850
3699
 
3851
3700
    def leave_lock_in_place(self):
3858
3707
            raise NotImplementedError(self.dont_leave_lock_in_place)
3859
3708
        self._leave_lock = False
3860
3709
 
 
3710
    @needs_read_lock
3861
3711
    def get_rev_id(self, revno, history=None):
3862
3712
        if revno == 0:
3863
3713
            return _mod_revision.NULL_REVISION
3864
 
        with self.lock_read():
3865
 
            last_revision_info = self.last_revision_info()
3866
 
            if revno < 0:
3867
 
                raise errors.RevnoOutOfBounds(
3868
 
                    revno, (0, last_revision_info[0]))
3869
 
            ok, result = self.repository.get_rev_id_for_revno(
3870
 
                revno, last_revision_info)
3871
 
            if ok:
3872
 
                return result
3873
 
            missing_parent = result[1]
3874
 
            # Either the revision named by the server is missing, or its parent
3875
 
            # is.  Call get_parent_map to determine which, so that we report a
3876
 
            # useful error.
3877
 
            parent_map = self.repository.get_parent_map([missing_parent])
3878
 
            if missing_parent in parent_map:
3879
 
                missing_parent = parent_map[missing_parent]
3880
 
            raise errors.NoSuchRevision(self, missing_parent)
 
3714
        last_revision_info = self.last_revision_info()
 
3715
        ok, result = self.repository.get_rev_id_for_revno(
 
3716
            revno, last_revision_info)
 
3717
        if ok:
 
3718
            return result
 
3719
        missing_parent = result[1]
 
3720
        # Either the revision named by the server is missing, or its parent
 
3721
        # is.  Call get_parent_map to determine which, so that we report a
 
3722
        # useful error.
 
3723
        parent_map = self.repository.get_parent_map([missing_parent])
 
3724
        if missing_parent in parent_map:
 
3725
            missing_parent = parent_map[missing_parent]
 
3726
        raise errors.RevisionNotPresent(missing_parent, self.repository)
3881
3727
 
3882
3728
    def _read_last_revision_info(self):
3883
 
        response = self._call(
3884
 
            b'Branch.last_revision_info', self._remote_path())
3885
 
        if response[0] != b'ok':
3886
 
            raise SmartProtocolError(
3887
 
                'unexpected response code %s' % (response,))
 
3729
        response = self._call('Branch.last_revision_info', self._remote_path())
 
3730
        if response[0] != 'ok':
 
3731
            raise SmartProtocolError('unexpected response code %s' % (response,))
3888
3732
        revno = int(response[1])
3889
3733
        last_revision = response[2]
3890
3734
        return (revno, last_revision)
3895
3739
            self._ensure_real()
3896
3740
            return self._real_branch._gen_revision_history()
3897
3741
        response_tuple, response_handler = self._call_expecting_body(
3898
 
            b'Branch.revision_history', self._remote_path())
3899
 
        if response_tuple[0] != b'ok':
 
3742
            'Branch.revision_history', self._remote_path())
 
3743
        if response_tuple[0] != 'ok':
3900
3744
            raise errors.UnexpectedSmartServerResponse(response_tuple)
3901
 
        result = response_handler.read_body_bytes().split(b'\x00')
 
3745
        result = response_handler.read_body_bytes().split('\x00')
3902
3746
        if result == ['']:
3903
3747
            return []
3904
3748
        return result
3905
3749
 
3906
3750
    def _remote_path(self):
3907
 
        return self.controldir._path_for_remote_call(self._client)
 
3751
        return self.bzrdir._path_for_remote_call(self._client)
3908
3752
 
3909
3753
    def _set_last_revision_descendant(self, revision_id, other_branch,
3910
 
                                      allow_diverged=False, allow_overwrite_descendant=False):
 
3754
            allow_diverged=False, allow_overwrite_descendant=False):
3911
3755
        # This performs additional work to meet the hook contract; while its
3912
3756
        # undesirable, we have to synthesise the revno to call the hook, and
3913
3757
        # not calling the hook is worse as it means changes can't be prevented.
3918
3762
        history = self._lefthand_history(revision_id)
3919
3763
        self._run_pre_change_branch_tip_hooks(len(history), revision_id)
3920
3764
        err_context = {'other_branch': other_branch}
3921
 
        response = self._call(b'Branch.set_last_revision_ex',
3922
 
                              self._remote_path(), self._lock_token, self._repo_lock_token,
3923
 
                              revision_id, int(allow_diverged), int(
3924
 
                                  allow_overwrite_descendant),
3925
 
                              **err_context)
 
3765
        response = self._call('Branch.set_last_revision_ex',
 
3766
            self._remote_path(), self._lock_token, self._repo_lock_token,
 
3767
            revision_id, int(allow_diverged), int(allow_overwrite_descendant),
 
3768
            **err_context)
3926
3769
        self._clear_cached_state()
3927
 
        if len(response) != 3 and response[0] != b'ok':
 
3770
        if len(response) != 3 and response[0] != 'ok':
3928
3771
            raise errors.UnexpectedSmartServerResponse(response)
3929
3772
        new_revno, new_revision_id = response[1:]
3930
3773
        self._last_revision_info_cache = new_revno, new_revision_id
3944
3787
        history = self._lefthand_history(revision_id)
3945
3788
        self._run_pre_change_branch_tip_hooks(len(history), revision_id)
3946
3789
        self._clear_cached_state()
3947
 
        response = self._call(b'Branch.set_last_revision',
3948
 
                              self._remote_path(), self._lock_token, self._repo_lock_token,
3949
 
                              revision_id)
3950
 
        if response != (b'ok',):
 
3790
        response = self._call('Branch.set_last_revision',
 
3791
            self._remote_path(), self._lock_token, self._repo_lock_token,
 
3792
            revision_id)
 
3793
        if response != ('ok',):
3951
3794
            raise errors.UnexpectedSmartServerResponse(response)
3952
3795
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
3953
3796
 
3956
3799
        if medium._is_remote_before((1, 13)):
3957
3800
            return self._vfs_get_parent_location()
3958
3801
        try:
3959
 
            response = self._call(b'Branch.get_parent', self._remote_path())
 
3802
            response = self._call('Branch.get_parent', self._remote_path())
3960
3803
        except errors.UnknownSmartMethod:
3961
3804
            medium._remember_remote_is_before((1, 13))
3962
3805
            return self._vfs_get_parent_location()
3963
3806
        if len(response) != 1:
3964
3807
            raise errors.UnexpectedSmartServerResponse(response)
3965
3808
        parent_location = response[0]
3966
 
        if parent_location == b'':
 
3809
        if parent_location == '':
3967
3810
            return None
3968
 
        return parent_location.decode('utf-8')
 
3811
        return parent_location
3969
3812
 
3970
3813
    def _vfs_get_parent_location(self):
3971
3814
        self._ensure_real()
3976
3819
        if medium._is_remote_before((1, 15)):
3977
3820
            return self._vfs_set_parent_location(url)
3978
3821
        try:
3979
 
            call_url = url or u''
3980
 
            if isinstance(call_url, str):
3981
 
                call_url = call_url.encode('utf-8')
3982
 
            response = self._call(b'Branch.set_parent_location',
3983
 
                                  self._remote_path(), self._lock_token, self._repo_lock_token,
3984
 
                                  call_url)
 
3822
            call_url = url or ''
 
3823
            if type(call_url) is not str:
 
3824
                raise AssertionError('url must be a str or None (%s)' % url)
 
3825
            response = self._call('Branch.set_parent_location',
 
3826
                self._remote_path(), self._lock_token, self._repo_lock_token,
 
3827
                call_url)
3985
3828
        except errors.UnknownSmartMethod:
3986
3829
            medium._remember_remote_is_before((1, 15))
3987
3830
            return self._vfs_set_parent_location(url)
3992
3835
        self._ensure_real()
3993
3836
        return self._real_branch._set_parent_location(url)
3994
3837
 
 
3838
    @needs_write_lock
3995
3839
    def pull(self, source, overwrite=False, stop_revision=None,
3996
3840
             **kwargs):
3997
 
        with self.lock_write():
3998
 
            self._clear_cached_state_of_remote_branch_only()
3999
 
            self._ensure_real()
4000
 
            return self._real_branch.pull(
4001
 
                source, overwrite=overwrite, stop_revision=stop_revision,
4002
 
                _override_hook_target=self, **kwargs)
 
3841
        self._clear_cached_state_of_remote_branch_only()
 
3842
        self._ensure_real()
 
3843
        return self._real_branch.pull(
 
3844
            source, overwrite=overwrite, stop_revision=stop_revision,
 
3845
            _override_hook_target=self, **kwargs)
4003
3846
 
4004
 
    def push(self, target, overwrite=False, stop_revision=None, lossy=False, tag_selector=None):
4005
 
        with self.lock_read():
4006
 
            self._ensure_real()
4007
 
            return self._real_branch.push(
4008
 
                target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
4009
 
                _override_hook_source_branch=self, tag_selector=tag_selector)
 
3847
    @needs_read_lock
 
3848
    def push(self, target, overwrite=False, stop_revision=None, lossy=False):
 
3849
        self._ensure_real()
 
3850
        return self._real_branch.push(
 
3851
            target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
 
3852
            _override_hook_source_branch=self)
4010
3853
 
4011
3854
    def peek_lock_mode(self):
4012
3855
        return self._lock_mode
4014
3857
    def is_locked(self):
4015
3858
        return self._lock_count >= 1
4016
3859
 
 
3860
    @needs_read_lock
4017
3861
    def revision_id_to_dotted_revno(self, revision_id):
4018
3862
        """Given a revision id, return its dotted revno.
4019
3863
 
4020
3864
        :return: a tuple like (1,) or (400,1,3).
4021
3865
        """
4022
 
        with self.lock_read():
4023
 
            try:
4024
 
                response = self._call(b'Branch.revision_id_to_revno',
4025
 
                                      self._remote_path(), revision_id)
4026
 
            except errors.UnknownSmartMethod:
4027
 
                self._ensure_real()
4028
 
                return self._real_branch.revision_id_to_dotted_revno(revision_id)
4029
 
            except errors.UnknownErrorFromSmartServer as e:
4030
 
                # Deal with older versions of bzr/brz that didn't explicitly
4031
 
                # wrap GhostRevisionsHaveNoRevno.
4032
 
                if e.error_tuple[1] == b'GhostRevisionsHaveNoRevno':
4033
 
                    (revid, ghost_revid) = re.findall(b"{([^}]+)}", e.error_tuple[2])
4034
 
                    raise errors.GhostRevisionsHaveNoRevno(
4035
 
                        revid, ghost_revid)
4036
 
                raise
4037
 
            if response[0] == b'ok':
4038
 
                return tuple([int(x) for x in response[1:]])
4039
 
            else:
4040
 
                raise errors.UnexpectedSmartServerResponse(response)
 
3866
        try:
 
3867
            response = self._call('Branch.revision_id_to_revno',
 
3868
                self._remote_path(), revision_id)
 
3869
        except errors.UnknownSmartMethod:
 
3870
            self._ensure_real()
 
3871
            return self._real_branch.revision_id_to_dotted_revno(revision_id)
 
3872
        if response[0] == 'ok':
 
3873
            return tuple([int(x) for x in response[1:]])
 
3874
        else:
 
3875
            raise errors.UnexpectedSmartServerResponse(response)
4041
3876
 
 
3877
    @needs_read_lock
4042
3878
    def revision_id_to_revno(self, revision_id):
4043
3879
        """Given a revision id on the branch mainline, return its revno.
4044
3880
 
4045
3881
        :return: an integer
4046
3882
        """
4047
 
        with self.lock_read():
4048
 
            try:
4049
 
                response = self._call(b'Branch.revision_id_to_revno',
4050
 
                                      self._remote_path(), revision_id)
4051
 
            except errors.UnknownSmartMethod:
4052
 
                self._ensure_real()
4053
 
                return self._real_branch.revision_id_to_revno(revision_id)
4054
 
            if response[0] == b'ok':
4055
 
                if len(response) == 2:
4056
 
                    return int(response[1])
4057
 
                raise NoSuchRevision(self, revision_id)
4058
 
            else:
4059
 
                raise errors.UnexpectedSmartServerResponse(response)
 
3883
        try:
 
3884
            response = self._call('Branch.revision_id_to_revno',
 
3885
                self._remote_path(), revision_id)
 
3886
        except errors.UnknownSmartMethod:
 
3887
            self._ensure_real()
 
3888
            return self._real_branch.revision_id_to_revno(revision_id)
 
3889
        if response[0] == 'ok':
 
3890
            if len(response) == 2:
 
3891
                return int(response[1])
 
3892
            raise NoSuchRevision(self, revision_id)
 
3893
        else:
 
3894
            raise errors.UnexpectedSmartServerResponse(response)
4060
3895
 
 
3896
    @needs_write_lock
4061
3897
    def set_last_revision_info(self, revno, revision_id):
4062
 
        with self.lock_write():
4063
 
            # XXX: These should be returned by the set_last_revision_info verb
4064
 
            old_revno, old_revid = self.last_revision_info()
4065
 
            self._run_pre_change_branch_tip_hooks(revno, revision_id)
4066
 
            if not revision_id or not isinstance(revision_id, bytes):
4067
 
                raise errors.InvalidRevisionId(
4068
 
                    revision_id=revision_id, branch=self)
4069
 
            try:
4070
 
                response = self._call(b'Branch.set_last_revision_info',
4071
 
                                      self._remote_path(), self._lock_token, self._repo_lock_token,
4072
 
                                      str(revno).encode('ascii'), revision_id)
4073
 
            except errors.UnknownSmartMethod:
4074
 
                self._ensure_real()
4075
 
                self._clear_cached_state_of_remote_branch_only()
4076
 
                self._real_branch.set_last_revision_info(revno, revision_id)
4077
 
                self._last_revision_info_cache = revno, revision_id
4078
 
                return
4079
 
            if response == (b'ok',):
4080
 
                self._clear_cached_state()
4081
 
                self._last_revision_info_cache = revno, revision_id
4082
 
                self._run_post_change_branch_tip_hooks(old_revno, old_revid)
4083
 
                # Update the _real_branch's cache too.
4084
 
                if self._real_branch is not None:
4085
 
                    cache = self._last_revision_info_cache
4086
 
                    self._real_branch._last_revision_info_cache = cache
4087
 
            else:
4088
 
                raise errors.UnexpectedSmartServerResponse(response)
 
3898
        # XXX: These should be returned by the set_last_revision_info verb
 
3899
        old_revno, old_revid = self.last_revision_info()
 
3900
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
 
3901
        if not revision_id or not isinstance(revision_id, basestring):
 
3902
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
 
3903
        try:
 
3904
            response = self._call('Branch.set_last_revision_info',
 
3905
                self._remote_path(), self._lock_token, self._repo_lock_token,
 
3906
                str(revno), revision_id)
 
3907
        except errors.UnknownSmartMethod:
 
3908
            self._ensure_real()
 
3909
            self._clear_cached_state_of_remote_branch_only()
 
3910
            self._real_branch.set_last_revision_info(revno, revision_id)
 
3911
            self._last_revision_info_cache = revno, revision_id
 
3912
            return
 
3913
        if response == ('ok',):
 
3914
            self._clear_cached_state()
 
3915
            self._last_revision_info_cache = revno, revision_id
 
3916
            self._run_post_change_branch_tip_hooks(old_revno, old_revid)
 
3917
            # Update the _real_branch's cache too.
 
3918
            if self._real_branch is not None:
 
3919
                cache = self._last_revision_info_cache
 
3920
                self._real_branch._last_revision_info_cache = cache
 
3921
        else:
 
3922
            raise errors.UnexpectedSmartServerResponse(response)
4089
3923
 
 
3924
    @needs_write_lock
4090
3925
    def generate_revision_history(self, revision_id, last_rev=None,
4091
3926
                                  other_branch=None):
4092
 
        with self.lock_write():
4093
 
            medium = self._client._medium
4094
 
            if not medium._is_remote_before((1, 6)):
4095
 
                # Use a smart method for 1.6 and above servers
4096
 
                try:
4097
 
                    self._set_last_revision_descendant(revision_id, other_branch,
4098
 
                                                       allow_diverged=True, allow_overwrite_descendant=True)
4099
 
                    return
4100
 
                except errors.UnknownSmartMethod:
4101
 
                    medium._remember_remote_is_before((1, 6))
4102
 
            self._clear_cached_state_of_remote_branch_only()
4103
 
            graph = self.repository.get_graph()
4104
 
            (last_revno, last_revid) = self.last_revision_info()
4105
 
            known_revision_ids = [
4106
 
                (last_revid, last_revno),
4107
 
                (_mod_revision.NULL_REVISION, 0),
4108
 
                ]
4109
 
            if last_rev is not None:
4110
 
                if not graph.is_ancestor(last_rev, revision_id):
4111
 
                    # our previous tip is not merged into stop_revision
4112
 
                    raise errors.DivergedBranches(self, other_branch)
4113
 
            revno = graph.find_distance_to_null(
4114
 
                revision_id, known_revision_ids)
4115
 
            self.set_last_revision_info(revno, revision_id)
 
3927
        medium = self._client._medium
 
3928
        if not medium._is_remote_before((1, 6)):
 
3929
            # Use a smart method for 1.6 and above servers
 
3930
            try:
 
3931
                self._set_last_revision_descendant(revision_id, other_branch,
 
3932
                    allow_diverged=True, allow_overwrite_descendant=True)
 
3933
                return
 
3934
            except errors.UnknownSmartMethod:
 
3935
                medium._remember_remote_is_before((1, 6))
 
3936
        self._clear_cached_state_of_remote_branch_only()
 
3937
        graph = self.repository.get_graph()
 
3938
        (last_revno, last_revid) = self.last_revision_info()
 
3939
        known_revision_ids = [
 
3940
            (last_revid, last_revno),
 
3941
            (_mod_revision.NULL_REVISION, 0),
 
3942
            ]
 
3943
        if last_rev is not None:
 
3944
            if not graph.is_ancestor(last_rev, revision_id):
 
3945
                # our previous tip is not merged into stop_revision
 
3946
                raise errors.DivergedBranches(self, other_branch)
 
3947
        revno = graph.find_distance_to_null(revision_id, known_revision_ids)
 
3948
        self.set_last_revision_info(revno, revision_id)
4116
3949
 
4117
3950
    def set_push_location(self, location):
4118
3951
        self._set_config_location('push_location', location)
4134
3967
            return self._vfs_heads_to_fetch()
4135
3968
 
4136
3969
    def _rpc_heads_to_fetch(self):
4137
 
        response = self._call(b'Branch.heads_to_fetch', self._remote_path())
 
3970
        response = self._call('Branch.heads_to_fetch', self._remote_path())
4138
3971
        if len(response) != 2:
4139
3972
            raise errors.UnexpectedSmartServerResponse(response)
4140
3973
        must_fetch, if_present_fetch = response
4144
3977
        self._ensure_real()
4145
3978
        return self._real_branch.heads_to_fetch()
4146
3979
 
4147
 
    def reconcile(self, thorough=True):
4148
 
        """Make sure the data stored in this branch is consistent."""
4149
 
        from .reconcile import BranchReconciler
4150
 
        with self.lock_write():
4151
 
            reconciler = BranchReconciler(self, thorough=thorough)
4152
 
            return reconciler.reconcile()
4153
 
 
4154
 
    def get_reference_info(self, file_id):
4155
 
        """Get the tree_path and branch_location for a tree reference."""
4156
 
        if not self._format.supports_reference_locations:
4157
 
            raise errors.UnsupportedOperation(self.get_reference_info, self)
4158
 
        return self._get_all_reference_info().get(file_id, (None, None))
4159
 
 
4160
 
    def set_reference_info(self, file_id, branch_location, tree_path=None):
4161
 
        """Set the branch location to use for a tree reference."""
4162
 
        if not self._format.supports_reference_locations:
4163
 
            raise errors.UnsupportedOperation(self.set_reference_info, self)
4164
 
        self._ensure_real()
4165
 
        self._real_branch.set_reference_info(
4166
 
            file_id, branch_location, tree_path)
4167
 
 
4168
 
    def _set_all_reference_info(self, reference_info):
4169
 
        if not self._format.supports_reference_locations:
4170
 
            raise errors.UnsupportedOperation(self.set_reference_info, self)
4171
 
        self._ensure_real()
4172
 
        self._real_branch._set_all_reference_info(reference_info)
4173
 
 
4174
 
    def _get_all_reference_info(self):
4175
 
        if not self._format.supports_reference_locations:
4176
 
            return {}
4177
 
        try:
4178
 
            response, handler = self._call_expecting_body(
4179
 
                b'Branch.get_all_reference_info', self._remote_path())
4180
 
        except errors.UnknownSmartMethod:
4181
 
            self._ensure_real()
4182
 
            return self._real_branch._get_all_reference_info()
4183
 
        if len(response) and response[0] != b'ok':
4184
 
            raise errors.UnexpectedSmartServerResponse(response)
4185
 
        ret = {}
4186
 
        for (f, u, p) in bencode.bdecode(handler.read_body_bytes()):
4187
 
            ret[f] = (u.decode('utf-8'), p.decode('utf-8') if p else None)
4188
 
        return ret
4189
 
 
4190
 
    def reference_parent(self, file_id, path, possible_transports=None):
4191
 
        """Return the parent branch for a tree-reference.
4192
 
 
4193
 
        :param path: The path of the nested tree in the tree
4194
 
        :return: A branch associated with the nested tree
4195
 
        """
4196
 
        branch_location = self.get_reference_info(file_id)[0]
4197
 
        if branch_location is None:
4198
 
            try:
4199
 
                return branch.Branch.open_from_transport(
4200
 
                    self.controldir.root_transport.clone(path),
4201
 
                    possible_transports=possible_transports)
4202
 
            except errors.NotBranchError:
4203
 
                return None
4204
 
        return branch.Branch.open(
4205
 
            urlutils.join(
4206
 
                urlutils.strip_segment_parameters(self.user_url), branch_location),
4207
 
            possible_transports=possible_transports)
4208
 
 
4209
3980
 
4210
3981
class RemoteConfig(object):
4211
3982
    """A Config that reads and writes from smart verbs.
4212
3983
 
4213
3984
    It is a low-level object that considers config data to be name/value pairs
4214
3985
    that may be associated with a section. Assigning meaning to the these
4215
 
    values is done at higher levels like breezy.config.TreeConfig.
 
3986
    values is done at higher levels like bzrlib.config.TreeConfig.
4216
3987
    """
4217
3988
 
4218
3989
    def get_option(self, name, section=None, default=None):
4244
4015
        return value
4245
4016
 
4246
4017
    def _response_to_configobj(self, response):
4247
 
        if len(response[0]) and response[0][0] != b'ok':
 
4018
        if len(response[0]) and response[0][0] != 'ok':
4248
4019
            raise errors.UnexpectedSmartServerResponse(response)
4249
4020
        lines = response[1].read_body_bytes().splitlines()
4250
4021
        conf = _mod_config.ConfigObj(lines, encoding='utf-8')
4262
4033
    def _get_configobj(self):
4263
4034
        path = self._branch._remote_path()
4264
4035
        response = self._branch._client.call_expecting_body(
4265
 
            b'Branch.get_config_file', path)
 
4036
            'Branch.get_config_file', path)
4266
4037
        return self._response_to_configobj(response)
4267
4038
 
4268
4039
    def set_option(self, value, name, section=None):
4283
4054
            return self._set_config_option(value, name, section)
4284
4055
 
4285
4056
    def _set_config_option(self, value, name, section):
4286
 
        if isinstance(value, (bool, int)):
4287
 
            value = str(value)
4288
 
        elif isinstance(value, str):
4289
 
            pass
4290
 
        else:
4291
 
            raise TypeError(value)
4292
4057
        try:
4293
4058
            path = self._branch._remote_path()
4294
 
            response = self._branch._client.call(b'Branch.set_config_option',
4295
 
                                                 path, self._branch._lock_token, self._branch._repo_lock_token,
4296
 
                                                 value.encode('utf-8'), name.encode('utf-8'),
4297
 
                                                 (section or '').encode('utf-8'))
 
4059
            response = self._branch._client.call('Branch.set_config_option',
 
4060
                path, self._branch._lock_token, self._branch._repo_lock_token,
 
4061
                value.encode('utf8'), name, section or '')
4298
4062
        except errors.UnknownSmartMethod:
4299
4063
            medium = self._branch._client._medium
4300
4064
            medium._remember_remote_is_before((1, 14))
4305
4069
    def _serialize_option_dict(self, option_dict):
4306
4070
        utf8_dict = {}
4307
4071
        for key, value in option_dict.items():
4308
 
            if isinstance(key, str):
 
4072
            if isinstance(key, unicode):
4309
4073
                key = key.encode('utf8')
4310
 
            if isinstance(value, str):
 
4074
            if isinstance(value, unicode):
4311
4075
                value = value.encode('utf8')
4312
4076
            utf8_dict[key] = value
4313
4077
        return bencode.bencode(utf8_dict)
4317
4081
            path = self._branch._remote_path()
4318
4082
            serialised_dict = self._serialize_option_dict(value)
4319
4083
            response = self._branch._client.call(
4320
 
                b'Branch.set_config_option_dict',
 
4084
                'Branch.set_config_option_dict',
4321
4085
                path, self._branch._lock_token, self._branch._repo_lock_token,
4322
 
                serialised_dict, name.encode('utf-8'), (section or '').encode('utf-8'))
 
4086
                serialised_dict, name, section or '')
4323
4087
        except errors.UnknownSmartMethod:
4324
4088
            medium = self._branch._client._medium
4325
4089
            medium._remember_remote_is_before((2, 2))
4344
4108
 
4345
4109
    def _get_configobj(self):
4346
4110
        medium = self._bzrdir._client._medium
4347
 
        verb = b'BzrDir.get_config_file'
 
4111
        verb = 'BzrDir.get_config_file'
4348
4112
        if medium._is_remote_before((1, 15)):
4349
4113
            raise errors.UnknownSmartMethod(verb)
4350
4114
        path = self._bzrdir._path_for_remote_call(self._bzrdir._client)
4371
4135
        return self._bzrdir._real_bzrdir
4372
4136
 
4373
4137
 
 
4138
def _extract_tar(tar, to_dir):
 
4139
    """Extract all the contents of a tarfile object.
 
4140
 
 
4141
    A replacement for extractall, which is not present in python2.4
 
4142
    """
 
4143
    for tarinfo in tar:
 
4144
        tar.extract(tarinfo, to_dir)
 
4145
 
 
4146
 
4374
4147
error_translators = registry.Registry()
4375
4148
no_context_error_translators = registry.Registry()
4376
4149
 
4392
4165
    def find(name):
4393
4166
        try:
4394
4167
            return context[name]
4395
 
        except KeyError:
4396
 
            mutter('Missing key \'%s\' in context %r', name, context)
 
4168
        except KeyError, key_err:
 
4169
            mutter('Missing key %r in context %r', key_err.args[0], context)
4397
4170
            raise err
4398
 
 
4399
4171
    def get_path():
4400
4172
        """Get the path from the context if present, otherwise use first error
4401
4173
        arg.
4402
4174
        """
4403
4175
        try:
4404
4176
            return context['path']
4405
 
        except KeyError:
 
4177
        except KeyError, key_err:
4406
4178
            try:
4407
 
                return err.error_args[0].decode('utf-8')
4408
 
            except IndexError:
4409
 
                mutter('Missing key \'path\' in context %r', context)
 
4179
                return err.error_args[0]
 
4180
            except IndexError, idx_err:
 
4181
                mutter(
 
4182
                    'Missing key %r in context %r', key_err.args[0], context)
4410
4183
                raise err
4411
 
    if not isinstance(err.error_verb, bytes):
4412
 
        raise TypeError(err.error_verb)
 
4184
 
4413
4185
    try:
4414
4186
        translator = error_translators.get(err.error_verb)
4415
4187
    except KeyError:
4424
4196
        raise translator(err)
4425
4197
 
4426
4198
 
4427
 
error_translators.register(b'NoSuchRevision',
4428
 
                           lambda err, find, get_path: NoSuchRevision(
4429
 
                               find('branch'), err.error_args[0]))
4430
 
error_translators.register(b'nosuchrevision',
4431
 
                           lambda err, find, get_path: NoSuchRevision(
4432
 
                               find('repository'), err.error_args[0]))
4433
 
error_translators.register(
4434
 
    b'revno-outofbounds',
4435
 
    lambda err, find, get_path: errors.RevnoOutOfBounds(
4436
 
        err.error_args[0], (err.error_args[1], err.error_args[2])))
4437
 
 
 
4199
error_translators.register('NoSuchRevision',
 
4200
    lambda err, find, get_path: NoSuchRevision(
 
4201
        find('branch'), err.error_args[0]))
 
4202
error_translators.register('nosuchrevision',
 
4203
    lambda err, find, get_path: NoSuchRevision(
 
4204
        find('repository'), err.error_args[0]))
4438
4205
 
4439
4206
def _translate_nobranch_error(err, find, get_path):
4440
4207
    if len(err.error_args) >= 1:
4441
 
        extra = err.error_args[0].decode('utf-8')
 
4208
        extra = err.error_args[0]
4442
4209
    else:
4443
4210
        extra = None
4444
4211
    return errors.NotBranchError(path=find('bzrdir').root_transport.base,
4445
 
                                 detail=extra)
4446
 
 
4447
 
 
4448
 
error_translators.register(b'nobranch', _translate_nobranch_error)
4449
 
error_translators.register(b'norepository',
4450
 
                           lambda err, find, get_path: errors.NoRepositoryPresent(
4451
 
                               find('bzrdir')))
4452
 
error_translators.register(b'UnlockableTransport',
4453
 
                           lambda err, find, get_path: errors.UnlockableTransport(
4454
 
                               find('bzrdir').root_transport))
4455
 
error_translators.register(b'TokenMismatch',
4456
 
                           lambda err, find, get_path: errors.TokenMismatch(
4457
 
                               find('token'), '(remote token)'))
4458
 
error_translators.register(b'Diverged',
4459
 
                           lambda err, find, get_path: errors.DivergedBranches(
4460
 
                               find('branch'), find('other_branch')))
4461
 
error_translators.register(b'NotStacked',
4462
 
                           lambda err, find, get_path: errors.NotStacked(branch=find('branch')))
4463
 
 
 
4212
        detail=extra)
 
4213
 
 
4214
error_translators.register('nobranch', _translate_nobranch_error)
 
4215
error_translators.register('norepository',
 
4216
    lambda err, find, get_path: errors.NoRepositoryPresent(
 
4217
        find('bzrdir')))
 
4218
error_translators.register('UnlockableTransport',
 
4219
    lambda err, find, get_path: errors.UnlockableTransport(
 
4220
        find('bzrdir').root_transport))
 
4221
error_translators.register('TokenMismatch',
 
4222
    lambda err, find, get_path: errors.TokenMismatch(
 
4223
        find('token'), '(remote token)'))
 
4224
error_translators.register('Diverged',
 
4225
    lambda err, find, get_path: errors.DivergedBranches(
 
4226
        find('branch'), find('other_branch')))
 
4227
error_translators.register('NotStacked',
 
4228
    lambda err, find, get_path: errors.NotStacked(branch=find('branch')))
4464
4229
 
4465
4230
def _translate_PermissionDenied(err, find, get_path):
4466
4231
    path = get_path()
4467
4232
    if len(err.error_args) >= 2:
4468
 
        extra = err.error_args[1].decode('utf-8')
 
4233
        extra = err.error_args[1]
4469
4234
    else:
4470
4235
        extra = None
4471
4236
    return errors.PermissionDenied(path, extra=extra)
4472
4237
 
4473
 
 
4474
 
error_translators.register(b'PermissionDenied', _translate_PermissionDenied)
4475
 
error_translators.register(b'ReadError',
4476
 
                           lambda err, find, get_path: errors.ReadError(get_path()))
4477
 
error_translators.register(b'NoSuchFile',
4478
 
                           lambda err, find, get_path: errors.NoSuchFile(get_path()))
4479
 
error_translators.register(b'TokenLockingNotSupported',
4480
 
                           lambda err, find, get_path: errors.TokenLockingNotSupported(
4481
 
                               find('repository')))
4482
 
error_translators.register(b'UnsuspendableWriteGroup',
4483
 
                           lambda err, find, get_path: errors.UnsuspendableWriteGroup(
4484
 
                               repository=find('repository')))
4485
 
error_translators.register(b'UnresumableWriteGroup',
4486
 
                           lambda err, find, get_path: errors.UnresumableWriteGroup(
4487
 
                               repository=find('repository'), write_groups=err.error_args[0],
4488
 
                               reason=err.error_args[1]))
4489
 
error_translators.register(b'AlreadyControlDir',
4490
 
                           lambda err, find, get_path: errors.AlreadyControlDirError(get_path()))
4491
 
 
4492
 
no_context_error_translators.register(b'GhostRevisionsHaveNoRevno',
4493
 
                                      lambda err: errors.GhostRevisionsHaveNoRevno(*err.error_args))
4494
 
no_context_error_translators.register(b'IncompatibleRepositories',
4495
 
                                      lambda err: errors.IncompatibleRepositories(
4496
 
                                          err.error_args[0].decode('utf-8'), err.error_args[1].decode('utf-8'), err.error_args[2].decode('utf-8')))
4497
 
no_context_error_translators.register(b'LockContention',
4498
 
                                      lambda err: errors.LockContention('(remote lock)'))
4499
 
no_context_error_translators.register(b'LockFailed',
4500
 
                                      lambda err: errors.LockFailed(err.error_args[0].decode('utf-8'), err.error_args[1].decode('utf-8')))
4501
 
no_context_error_translators.register(b'TipChangeRejected',
4502
 
                                      lambda err: errors.TipChangeRejected(err.error_args[0].decode('utf8')))
4503
 
no_context_error_translators.register(b'UnstackableBranchFormat',
4504
 
                                      lambda err: branch.UnstackableBranchFormat(*err.error_args))
4505
 
no_context_error_translators.register(b'UnstackableRepositoryFormat',
4506
 
                                      lambda err: errors.UnstackableRepositoryFormat(*err.error_args))
4507
 
no_context_error_translators.register(b'FileExists',
4508
 
                                      lambda err: errors.FileExists(err.error_args[0].decode('utf-8')))
4509
 
no_context_error_translators.register(b'DirectoryNotEmpty',
4510
 
                                      lambda err: errors.DirectoryNotEmpty(err.error_args[0].decode('utf-8')))
4511
 
no_context_error_translators.register(b'UnknownFormat',
4512
 
                                      lambda err: errors.UnknownFormatError(
4513
 
                                          err.error_args[0].decode('ascii'), err.error_args[0].decode('ascii')))
4514
 
no_context_error_translators.register(b'InvalidURL',
4515
 
                                      lambda err: urlutils.InvalidURL(
4516
 
                                          err.error_args[0].decode('utf-8'), err.error_args[1].decode('ascii')))
4517
 
 
 
4238
error_translators.register('PermissionDenied', _translate_PermissionDenied)
 
4239
error_translators.register('ReadError',
 
4240
    lambda err, find, get_path: errors.ReadError(get_path()))
 
4241
error_translators.register('NoSuchFile',
 
4242
    lambda err, find, get_path: errors.NoSuchFile(get_path()))
 
4243
error_translators.register('TokenLockingNotSupported',
 
4244
    lambda err, find, get_path: errors.TokenLockingNotSupported(
 
4245
        find('repository')))
 
4246
error_translators.register('UnsuspendableWriteGroup',
 
4247
    lambda err, find, get_path: errors.UnsuspendableWriteGroup(
 
4248
        repository=find('repository')))
 
4249
error_translators.register('UnresumableWriteGroup',
 
4250
    lambda err, find, get_path: errors.UnresumableWriteGroup(
 
4251
        repository=find('repository'), write_groups=err.error_args[0],
 
4252
        reason=err.error_args[1]))
 
4253
no_context_error_translators.register('IncompatibleRepositories',
 
4254
    lambda err: errors.IncompatibleRepositories(
 
4255
        err.error_args[0], err.error_args[1], err.error_args[2]))
 
4256
no_context_error_translators.register('LockContention',
 
4257
    lambda err: errors.LockContention('(remote lock)'))
 
4258
no_context_error_translators.register('LockFailed',
 
4259
    lambda err: errors.LockFailed(err.error_args[0], err.error_args[1]))
 
4260
no_context_error_translators.register('TipChangeRejected',
 
4261
    lambda err: errors.TipChangeRejected(err.error_args[0].decode('utf8')))
 
4262
no_context_error_translators.register('UnstackableBranchFormat',
 
4263
    lambda err: errors.UnstackableBranchFormat(*err.error_args))
 
4264
no_context_error_translators.register('UnstackableRepositoryFormat',
 
4265
    lambda err: errors.UnstackableRepositoryFormat(*err.error_args))
 
4266
no_context_error_translators.register('FileExists',
 
4267
    lambda err: errors.FileExists(err.error_args[0]))
 
4268
no_context_error_translators.register('DirectoryNotEmpty',
 
4269
    lambda err: errors.DirectoryNotEmpty(err.error_args[0]))
4518
4270
 
4519
4271
def _translate_short_readv_error(err):
4520
4272
    args = err.error_args
4521
 
    return errors.ShortReadvError(
4522
 
        args[0].decode('utf-8'),
4523
 
        int(args[1].decode('ascii')), int(args[2].decode('ascii')),
4524
 
        int(args[3].decode('ascii')))
4525
 
 
4526
 
 
4527
 
no_context_error_translators.register(b'ShortReadvError',
4528
 
                                      _translate_short_readv_error)
4529
 
 
 
4273
    return errors.ShortReadvError(args[0], int(args[1]), int(args[2]),
 
4274
        int(args[3]))
 
4275
 
 
4276
no_context_error_translators.register('ShortReadvError',
 
4277
    _translate_short_readv_error)
4530
4278
 
4531
4279
def _translate_unicode_error(err):
4532
 
    encoding = err.error_args[0].decode('ascii')
4533
 
    val = err.error_args[1].decode('utf-8')
4534
 
    start = int(err.error_args[2].decode('ascii'))
4535
 
    end = int(err.error_args[3].decode('ascii'))
4536
 
    reason = err.error_args[4].decode('utf-8')
4537
 
    if val.startswith('u:'):
4538
 
        val = val[2:].decode('utf-8')
4539
 
    elif val.startswith('s:'):
4540
 
        val = val[2:].decode('base64')
4541
 
    if err.error_verb == 'UnicodeDecodeError':
4542
 
        raise UnicodeDecodeError(encoding, val, start, end, reason)
4543
 
    elif err.error_verb == 'UnicodeEncodeError':
4544
 
        raise UnicodeEncodeError(encoding, val, start, end, reason)
4545
 
 
4546
 
 
4547
 
no_context_error_translators.register(b'UnicodeEncodeError',
4548
 
                                      _translate_unicode_error)
4549
 
no_context_error_translators.register(b'UnicodeDecodeError',
4550
 
                                      _translate_unicode_error)
4551
 
no_context_error_translators.register(b'ReadOnlyError',
4552
 
                                      lambda err: errors.TransportNotPossible('readonly transport'))
4553
 
no_context_error_translators.register(b'MemoryError',
4554
 
                                      lambda err: errors.BzrError("remote server out of memory\n"
4555
 
                                                                  "Retry non-remotely, or contact the server admin for details."))
4556
 
no_context_error_translators.register(b'RevisionNotPresent',
4557
 
                                      lambda err: errors.RevisionNotPresent(err.error_args[0].decode('utf-8'), err.error_args[1].decode('utf-8')))
4558
 
 
4559
 
no_context_error_translators.register(b'BzrCheckError',
4560
 
                                      lambda err: errors.BzrCheckError(msg=err.error_args[0].decode('utf-8')))
 
4280
        encoding = str(err.error_args[0]) # encoding must always be a string
 
4281
        val = err.error_args[1]
 
4282
        start = int(err.error_args[2])
 
4283
        end = int(err.error_args[3])
 
4284
        reason = str(err.error_args[4]) # reason must always be a string
 
4285
        if val.startswith('u:'):
 
4286
            val = val[2:].decode('utf-8')
 
4287
        elif val.startswith('s:'):
 
4288
            val = val[2:].decode('base64')
 
4289
        if err.error_verb == 'UnicodeDecodeError':
 
4290
            raise UnicodeDecodeError(encoding, val, start, end, reason)
 
4291
        elif err.error_verb == 'UnicodeEncodeError':
 
4292
            raise UnicodeEncodeError(encoding, val, start, end, reason)
 
4293
 
 
4294
no_context_error_translators.register('UnicodeEncodeError',
 
4295
    _translate_unicode_error)
 
4296
no_context_error_translators.register('UnicodeDecodeError',
 
4297
    _translate_unicode_error)
 
4298
no_context_error_translators.register('ReadOnlyError',
 
4299
    lambda err: errors.TransportNotPossible('readonly transport'))
 
4300
no_context_error_translators.register('MemoryError',
 
4301
    lambda err: errors.BzrError("remote server out of memory\n"
 
4302
        "Retry non-remotely, or contact the server admin for details."))
 
4303
no_context_error_translators.register('RevisionNotPresent',
 
4304
    lambda err: errors.RevisionNotPresent(err.error_args[0], err.error_args[1]))
 
4305
 
 
4306
no_context_error_translators.register('BzrCheckError',
 
4307
    lambda err: errors.BzrCheckError(msg=err.error_args[0]))
 
4308