1091
1018
self._custom_format.revision_graph_can_have_wrong_parents
1092
1019
return self._revision_graph_can_have_wrong_parents
1094
def _vfs_initialize(self, a_controldir, shared):
1021
def _vfs_initialize(self, a_bzrdir, shared):
1095
1022
"""Helper for common code in initialize."""
1096
1023
if self._custom_format:
1097
1024
# Custom format requested
1098
result = self._custom_format.initialize(
1099
a_controldir, shared=shared)
1025
result = self._custom_format.initialize(a_bzrdir, shared=shared)
1100
1026
elif self._creating_bzrdir is not None:
1101
1027
# Use the format that the repository we were created to back
1103
1029
prior_repo = self._creating_bzrdir.open_repository()
1104
1030
prior_repo._ensure_real()
1105
1031
result = prior_repo._real_repository._format.initialize(
1106
a_controldir, shared=shared)
1032
a_bzrdir, shared=shared)
1108
1034
# assume that a_bzr is a RemoteBzrDir but the smart server didn't
1109
1035
# support remote initialization.
1110
1036
# We delegate to a real object at this point (as RemoteBzrDir
1111
1037
# 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)
1038
# recursion if we just called a_bzrdir.create_repository.
1039
a_bzrdir._ensure_real()
1040
result = a_bzrdir._real_bzrdir.create_repository(shared=shared)
1115
1041
if not isinstance(result, RemoteRepository):
1116
return self.open(a_controldir)
1042
return self.open(a_bzrdir)
1120
def initialize(self, a_controldir, shared=False):
1046
def initialize(self, a_bzrdir, shared=False):
1121
1047
# 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
1048
if not isinstance(a_bzrdir, RemoteBzrDir):
1049
return self._vfs_initialize(a_bzrdir, shared)
1050
medium = a_bzrdir._client._medium
1125
1051
if medium._is_remote_before((1, 13)):
1126
return self._vfs_initialize(a_controldir, shared)
1052
return self._vfs_initialize(a_bzrdir, shared)
1127
1053
# Creating on a remote bzr dir.
1128
1054
# 1) get the network name to use.
1129
1055
if self._custom_format:
1540
1449
# TODO: Move to RepositoryBase and unify with the regular Repository
1541
1450
# one; unfortunately the tests rely on slightly different behaviour at
1542
1451
# present -- mbp 20090710
1543
return (self.__class__ is other.__class__
1544
and self.controldir.transport.base == other.controldir.transport.base)
1452
return (self.__class__ is other.__class__ and
1453
self.bzrdir.transport.base == other.bzrdir.transport.base)
1546
1455
def get_graph(self, other_repository=None):
1547
1456
"""Return the graph for this repository format"""
1548
1457
parents_provider = self._make_parents_provider(other_repository)
1549
1458
return graph.Graph(parents_provider)
1551
1461
def get_known_graph_ancestry(self, revision_ids):
1552
1462
"""Return the known graph for a set of revision ids and their ancestors.
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)
1464
st = static_tuple.StaticTuple
1465
revision_keys = [st(r_id).intern() for r_id in revision_ids]
1466
known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
1467
return graph.GraphThunkIdsToKeys(known_graph)
1560
1469
def gather_stats(self, revid=None, committers=None):
1561
1470
"""See Repository.gather_stats()."""
1562
path = self.controldir._path_for_remote_call(self._client)
1471
path = self.bzrdir._path_for_remote_call(self._client)
1563
1472
# revid can be None to indicate no revisions, not just NULL_REVISION
1564
1473
if revid is None or _mod_revision.is_null(revid):
1567
1476
fmt_revid = revid
1568
1477
if committers is None or not committers:
1569
fmt_committers = b'no'
1478
fmt_committers = 'no'
1571
fmt_committers = b'yes'
1480
fmt_committers = 'yes'
1572
1481
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':
1482
'Repository.gather_stats', path, fmt_revid, fmt_committers)
1483
if response_tuple[0] != 'ok':
1575
1484
raise errors.UnexpectedSmartServerResponse(response_tuple)
1577
1486
body = response_handler.read_body_bytes()
1579
for line in body.split(b'\n'):
1488
for line in body.split('\n'):
1582
key, val_text = line.split(b':')
1583
key = key.decode('ascii')
1491
key, val_text = line.split(':')
1584
1492
if key in ('revisions', 'size', 'committers'):
1585
1493
result[key] = int(val_text)
1586
1494
elif key in ('firstrev', 'latestrev'):
1587
values = val_text.split(b' ')[1:]
1495
values = val_text.split(' ')[1:]
1588
1496
result[key] = (float(values[0]), int(values[1]))
1869
1775
raise errors.UnexpectedSmartServerResponse(response)
1871
1778
def sprout(self, to_bzrdir, revision_id=None):
1872
1779
"""Create a descendent repository for new development.
1874
1781
Unlike clone, this does not copy the settings of the repository.
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)
1783
dest_repo = self._create_sprouting_repo(to_bzrdir, shared=False)
1784
dest_repo.fetch(self, revision_id=revision_id)
1881
def _create_sprouting_repo(self, a_controldir, shared):
1882
if not isinstance(a_controldir._format, self.controldir._format.__class__):
1787
def _create_sprouting_repo(self, a_bzrdir, shared):
1788
if not isinstance(a_bzrdir._format, self.bzrdir._format.__class__):
1883
1789
# use target default format.
1884
dest_repo = a_controldir.create_repository()
1790
dest_repo = a_bzrdir.create_repository()
1886
1792
# Most control formats need the repository to be specifically
1887
1793
# created, but on some old all-in-one formats it's not needed
1889
dest_repo = self._format.initialize(
1890
a_controldir, shared=shared)
1795
dest_repo = self._format.initialize(a_bzrdir, shared=shared)
1891
1796
except errors.UninitializableFormat:
1892
dest_repo = a_controldir.open_repository()
1797
dest_repo = a_bzrdir.open_repository()
1893
1798
return dest_repo
1895
# These methods are just thin shims to the VFS object for now.
1800
### These methods are just thin shims to the VFS object for now.
1897
1803
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)
1904
return list(self.revision_trees([revision_id]))[0]
1804
revision_id = _mod_revision.ensure_null(revision_id)
1805
if revision_id == _mod_revision.NULL_REVISION:
1806
return InventoryRevisionTree(self,
1807
Inventory(root_id=None), _mod_revision.NULL_REVISION)
1809
return list(self.revision_trees([revision_id]))[0]
1906
1811
def get_serializer_format(self):
1907
path = self.controldir._path_for_remote_call(self._client)
1812
path = self.bzrdir._path_for_remote_call(self._client)
1909
response = self._call(b'VersionedFileRepository.get_serializer_format',
1814
response = self._call('VersionedFileRepository.get_serializer_format',
1911
1816
except errors.UnknownSmartMethod:
1912
1817
self._ensure_real()
1913
1818
return self._real_repository.get_serializer_format()
1914
if response[0] != b'ok':
1819
if response[0] != 'ok':
1915
1820
raise errors.UnexpectedSmartServerResponse(response)
1916
1821
return response[1]
2469
2367
revision_graph[d[0]] = (NULL_REVISION,)
2470
2368
return revision_graph
2472
2371
def get_signature_text(self, revision_id):
2473
with self.lock_read():
2474
path = self.controldir._path_for_remote_call(self._client)
2476
response_tuple, response_handler = self._call_expecting_body(
2477
b'Repository.get_revision_signature_text', path, revision_id)
2478
except errors.UnknownSmartMethod:
2480
return self._real_repository.get_signature_text(revision_id)
2481
except errors.NoSuchRevision as err:
2482
for fallback in self._fallback_repositories:
2484
return fallback.get_signature_text(revision_id)
2485
except errors.NoSuchRevision:
2489
if response_tuple[0] != b'ok':
2490
raise errors.UnexpectedSmartServerResponse(response_tuple)
2491
return response_handler.read_body_bytes()
2372
path = self.bzrdir._path_for_remote_call(self._client)
2374
response_tuple, response_handler = self._call_expecting_body(
2375
'Repository.get_revision_signature_text', path, revision_id)
2376
except errors.UnknownSmartMethod:
2378
return self._real_repository.get_signature_text(revision_id)
2379
except errors.NoSuchRevision as err:
2380
for fallback in self._fallback_repositories:
2382
return fallback.get_signature_text(revision_id)
2383
except errors.NoSuchRevision:
2387
if response_tuple[0] != 'ok':
2388
raise errors.UnexpectedSmartServerResponse(response_tuple)
2389
return response_handler.read_body_bytes()
2493
2392
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.
2498
return self._real_repository._get_inventory_xml(revision_id)
2393
# This call is used by older working tree formats,
2394
# which stored a serialized basis inventory.
2396
return self._real_repository._get_inventory_xml(revision_id)
2500
2399
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)
2505
response, handler = self._call_expecting_body(
2506
b'Repository.reconcile', path, self._lock_token)
2507
except (errors.UnknownSmartMethod, errors.TokenLockingNotSupported):
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'):
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)
2526
mutter("unknown reconcile key %r" % key)
2400
from .reconcile import RepoReconciler
2401
path = self.bzrdir._path_for_remote_call(self._client)
2403
response, handler = self._call_expecting_body(
2404
'Repository.reconcile', path, self._lock_token)
2405
except (errors.UnknownSmartMethod, errors.TokenLockingNotSupported):
2407
return self._real_repository.reconcile(other=other, thorough=thorough)
2408
if response != ('ok', ):
2409
raise errors.UnexpectedSmartServerResponse(response)
2410
body = handler.read_body_bytes()
2411
result = RepoReconciler(self)
2412
for line in body.split('\n'):
2415
key, val_text = line.split(':')
2416
if key == "garbage_inventories":
2417
result.garbage_inventories = int(val_text)
2418
elif key == "inconsistent_parents":
2419
result.inconsistent_parents = int(val_text)
2421
mutter("unknown reconcile key %r" % key)
2529
2424
def all_revision_ids(self):
2530
path = self.controldir._path_for_remote_call(self._client)
2425
path = self.bzrdir._path_for_remote_call(self._client)
2532
2427
response_tuple, response_handler = self._call_expecting_body(
2533
b"Repository.all_revision_ids", path)
2428
"Repository.all_revision_ids", path)
2534
2429
except errors.UnknownSmartMethod:
2535
2430
self._ensure_real()
2536
2431
return self._real_repository.all_revision_ids()
2537
if response_tuple != (b"ok", ):
2432
if response_tuple != ("ok", ):
2538
2433
raise errors.UnexpectedSmartServerResponse(response_tuple)
2539
2434
revids = set(response_handler.read_body_bytes().splitlines())
2540
2435
for fallback in self._fallback_repositories:
2557
2452
filtered_inv = inv.filter(file_ids)
2558
2453
yield InventoryRevisionTree(self, filtered_inv, filtered_inv.revision_id)
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]
2456
def get_deltas_for_revisions(self, revisions, specific_fileids=None):
2457
medium = self._client._medium
2458
if medium._is_remote_before((1, 2)):
2460
for delta in self._real_repository.get_deltas_for_revisions(
2461
revisions, specific_fileids):
2464
# Get the revision-ids of interest
2465
required_trees = set()
2466
for revision in revisions:
2467
required_trees.add(revision.revision_id)
2468
required_trees.update(revision.parent_ids[:1])
2470
# Get the matching filtered trees. Note that it's more
2471
# efficient to pass filtered trees to changes_from() rather
2472
# than doing the filtering afterwards. changes_from() could
2473
# arguably do the filtering itself but it's path-based, not
2474
# file-id based, so filtering before or afterwards is
2476
if specific_fileids is None:
2477
trees = dict((t.get_revision_id(), t) for
2478
t in self.revision_trees(required_trees))
2480
trees = dict((t.get_revision_id(), t) for
2481
t in self._filtered_revision_trees(required_trees,
2484
# Calculate the deltas
2485
for revision in revisions:
2486
if not revision.parent_ids:
2487
old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
2489
old_tree = trees[revision.parent_ids[0]]
2490
yield trees[revision.revision_id].changes_from(old_tree)
2493
def get_revision_delta(self, revision_id, specific_fileids=None):
2494
r = self.get_revision(revision_id)
2495
return list(self.get_deltas_for_revisions([r],
2496
specific_fileids=specific_fileids))[0]
2565
2499
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)
2500
inventories = self.iter_inventories(revision_ids)
2501
for inv in inventories:
2502
yield InventoryRevisionTree(self, inv, inv.revision_id)
2571
2505
def get_revision_reconcile(self, revision_id):
2572
with self.lock_read():
2574
return self._real_repository.get_revision_reconcile(revision_id)
2507
return self._real_repository.get_revision_reconcile(revision_id)
2576
2510
def check(self, revision_ids=None, callback_refs=None, check_repo=True):
2577
with self.lock_read():
2579
return self._real_repository.check(revision_ids=revision_ids,
2580
callback_refs=callback_refs, check_repo=check_repo)
2512
return self._real_repository.check(revision_ids=revision_ids,
2513
callback_refs=callback_refs, check_repo=check_repo)
2582
2515
def copy_content_into(self, destination, revision_id=None):
2583
2516
"""Make a complete copy of the content in self into destination.
2699
2631
return self._real_repository.texts
2701
2633
def _iter_revisions_rpc(self, revision_ids):
2702
body = b"\n".join(revision_ids)
2703
path = self.controldir._path_for_remote_call(self._client)
2634
body = "\n".join(revision_ids)
2635
path = self.bzrdir._path_for_remote_call(self._client)
2704
2636
response_tuple, response_handler = (
2705
2637
self._call_with_body_bytes_expecting_body(
2706
b"Repository.iter_revisions", (path, ), body))
2707
if response_tuple[0] != b"ok":
2638
"Repository.iter_revisions", (path, ), body))
2639
if response_tuple[0] != "ok":
2708
2640
raise errors.UnexpectedSmartServerResponse(response_tuple)
2709
serializer_format = response_tuple[1].decode('ascii')
2641
serializer_format = response_tuple[1]
2710
2642
serializer = serializer_format_registry.get(serializer_format)
2711
2643
byte_stream = response_handler.read_streamed_body()
2712
2644
decompressor = zlib.decompressobj()
2714
2646
for bytes in byte_stream:
2715
2647
chunks.append(decompressor.decompress(bytes))
2716
if decompressor.unused_data != b"":
2648
if decompressor.unused_data != "":
2717
2649
chunks.append(decompressor.flush())
2718
yield serializer.read_revision_from_string(b"".join(chunks))
2650
yield serializer.read_revision_from_string("".join(chunks))
2719
2651
unused = decompressor.unused_data
2720
2652
decompressor = zlib.decompressobj()
2721
2653
chunks = [decompressor.decompress(unused)]
2722
2654
chunks.append(decompressor.flush())
2723
text = b"".join(chunks)
2725
yield serializer.read_revision_from_string(b"".join(chunks))
2655
text = "".join(chunks)
2657
yield serializer.read_revision_from_string("".join(chunks))
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():
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:
2741
for (revid, rev) in fallback.iter_revisions(missing):
2744
missing.remove(revid)
2745
for revid in missing:
2747
except errors.UnknownSmartMethod:
2749
for entry in self._real_repository.iter_revisions(revision_ids):
2660
def get_revisions(self, revision_ids):
2661
if revision_ids is None:
2662
revision_ids = self.all_revision_ids()
2664
for rev_id in revision_ids:
2665
if not rev_id or not isinstance(rev_id, basestring):
2666
raise errors.InvalidRevisionId(
2667
revision_id=rev_id, branch=self)
2669
missing = set(revision_ids)
2671
for rev in self._iter_revisions_rpc(revision_ids):
2672
missing.remove(rev.revision_id)
2673
revs[rev.revision_id] = rev
2674
except errors.UnknownSmartMethod:
2676
return self._real_repository.get_revisions(revision_ids)
2677
for fallback in self._fallback_repositories:
2680
for revid in list(missing):
2681
# XXX JRV 2011-11-20: It would be nice if there was a
2682
# public method on Repository that could be used to query
2683
# for revision objects *without* failing completely if one
2684
# was missing. There is VersionedFileRepository._iter_revisions,
2685
# but unfortunately that's private and not provided by
2686
# all repository implementations.
2688
revs[revid] = fallback.get_revision(revid)
2689
except errors.NoSuchRevision:
2692
missing.remove(revid)
2694
raise errors.NoSuchRevision(self, list(missing)[0])
2695
return [revs[revid] for revid in revision_ids]
2752
2697
def supports_rich_root(self):
2753
2698
return self._format.rich_root_data
2768
2713
self._ensure_real()
2769
2714
return self._real_repository.add_signature_text(
2770
2715
revision_id, signature)
2771
path = self.controldir._path_for_remote_call(self._client)
2716
path = self.bzrdir._path_for_remote_call(self._client)
2772
2717
response, handler = self._call_with_body_bytes_expecting_body(
2773
b'Repository.add_signature_text', (path, self._lock_token,
2775
tuple([token.encode('utf-8')
2776
for token in self._write_group_tokens]),
2718
'Repository.add_signature_text', (path, self._lock_token,
2719
revision_id) + tuple(self._write_group_tokens), signature)
2778
2720
handler.cancel_read_body()
2779
2721
self.refresh_data()
2780
if response[0] != b'ok':
2722
if response[0] != 'ok':
2781
2723
raise errors.UnexpectedSmartServerResponse(response)
2782
self._write_group_tokens = [token.decode(
2783
'utf-8') for token in response[1:]]
2724
self._write_group_tokens = response[1:]
2785
2726
def has_signature_for_revision_id(self, revision_id):
2786
path = self.controldir._path_for_remote_call(self._client)
2727
path = self.bzrdir._path_for_remote_call(self._client)
2788
response = self._call(b'Repository.has_signature_for_revision_id',
2729
response = self._call('Repository.has_signature_for_revision_id',
2790
2731
except errors.UnknownSmartMethod:
2791
2732
self._ensure_real()
2792
2733
return self._real_repository.has_signature_for_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':
2735
if response[0] not in ('yes', 'no'):
2736
raise SmartProtocolError('unexpected response code %s' % (response,))
2737
if response[0] == 'yes':
2799
2739
for fallback in self._fallback_repositories:
2800
2740
if fallback.has_signature_for_revision_id(revision_id):
2804
2745
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)
2810
testament = _mod_testament.Testament.from_revision(
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)
2746
if not self.has_signature_for_revision_id(revision_id):
2747
return gpg.SIGNATURE_NOT_SIGNED, None
2748
signature = self.get_signature_text(revision_id)
2750
testament = _mod_testament.Testament.from_revision(self, revision_id)
2751
plaintext = testament.as_short_text()
2753
return gpg_strategy.verify(signature, plaintext)
2818
2755
def item_keys_introduced_by(self, revision_ids, _files_pb=None):
2819
2756
self._ensure_real()
2820
2757
return self._real_repository.item_keys_introduced_by(revision_ids,
2821
_files_pb=_files_pb)
2758
_files_pb=_files_pb)
2823
2760
def _find_inconsistent_revision_parents(self, revisions_iterator=None):
2824
2761
self._ensure_real()
2842
2779
:param recipe: A search recipe (start, stop, count).
2843
2780
:return: Serialised bytes.
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))
2782
start_keys = ' '.join(recipe[1])
2783
stop_keys = ' '.join(recipe[2])
2784
count = str(recipe[3])
2785
return '\n'.join((start_keys, stop_keys, count))
2850
2787
def _serialise_search_result(self, search_result):
2851
2788
parts = search_result.get_network_struct()
2852
return b'\n'.join(parts)
2789
return '\n'.join(parts)
2854
2791
def autopack(self):
2855
path = self.controldir._path_for_remote_call(self._client)
2792
path = self.bzrdir._path_for_remote_call(self._client)
2857
response = self._call(b'PackRepository.autopack', path)
2794
response = self._call('PackRepository.autopack', path)
2858
2795
except errors.UnknownSmartMethod:
2859
2796
self._ensure_real()
2860
2797
self._real_repository._pack_collection.autopack()
2862
2799
self.refresh_data()
2863
if response[0] != b'ok':
2864
raise errors.UnexpectedSmartServerResponse(response)
2866
def _revision_archive(self, revision_id, format, name, root, subdir,
2868
path = self.controldir._path_for_remote_call(self._client)
2869
format = format or ''
2871
subdir = subdir or ''
2872
force_mtime = int(force_mtime) if force_mtime is not None else None
2874
response, protocol = self._call_expecting_body(
2875
b'Repository.revision_archive', path,
2877
format.encode('ascii'),
2878
os.path.basename(name).encode('utf-8'),
2879
root.encode('utf-8'),
2880
subdir.encode('utf-8'),
2882
except errors.UnknownSmartMethod:
2884
if response[0] == b'ok':
2885
return iter([protocol.read_body_bytes()])
2886
raise errors.UnexpectedSmartServerResponse(response)
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''
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:
2899
if response[0] != b'ok':
2900
raise errors.UnexpectedSmartServerResponse(response)
2901
return map(tuple, bencode.bdecode(handler.read_body_bytes()))
2800
if response[0] != 'ok':
2801
raise errors.UnexpectedSmartServerResponse(response)
2904
2804
class RemoteStreamSink(vf_repository.StreamSink):
3251
3108
def network_name(self):
3252
3109
return self._network_name
3254
def open(self, a_controldir, name=None, ignore_fallbacks=False):
3255
return a_controldir.open_branch(name=name,
3256
ignore_fallbacks=ignore_fallbacks)
3111
def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
3112
return a_bzrdir.open_branch(name=name,
3113
ignore_fallbacks=ignore_fallbacks)
3258
def _vfs_initialize(self, a_controldir, name, append_revisions_only,
3115
def _vfs_initialize(self, a_bzrdir, name, append_revisions_only,
3259
3116
repository=None):
3260
3117
# Initialisation when using a local bzrdir object, or a non-vfs init
3261
3118
# method is not available on the server.
3262
3119
# self._custom_format is always set - the start of initialize ensures
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)
3121
if isinstance(a_bzrdir, RemoteBzrDir):
3122
a_bzrdir._ensure_real()
3123
result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
3124
name=name, append_revisions_only=append_revisions_only,
3125
repository=repository)
3270
3127
# 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,
3128
result = self._custom_format.initialize(a_bzrdir, name=name,
3129
append_revisions_only=append_revisions_only,
3130
repository=repository)
3131
if (isinstance(a_bzrdir, RemoteBzrDir) and
3132
not isinstance(result, RemoteBranch)):
3133
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
3280
def initialize(self, a_controldir, name=None, repository=None,
3137
def initialize(self, a_bzrdir, name=None, repository=None,
3281
3138
append_revisions_only=None):
3282
3139
if name is None:
3283
name = a_controldir._get_selected_branch()
3140
name = a_bzrdir._get_selected_branch()
3284
3141
# 1) get the network name to use.
3285
3142
if self._custom_format:
3286
3143
network_name = self._custom_format.network_name()
3288
3145
# Select the current breezy default and ask for that.
3289
reference_bzrdir_format = controldir.format_registry.get(
3146
reference_bzrdir_format = controldir.format_registry.get('default')()
3291
3147
reference_format = reference_bzrdir_format.get_branch_format()
3292
3148
self._custom_format = reference_format
3293
3149
network_name = reference_format.network_name()
3294
3150
# 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
3151
if not isinstance(a_bzrdir, RemoteBzrDir):
3152
return self._vfs_initialize(a_bzrdir, name=name,
3153
append_revisions_only=append_revisions_only,
3154
repository=repository)
3155
medium = a_bzrdir._client._medium
3300
3156
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)
3157
return self._vfs_initialize(a_bzrdir, name=name,
3158
append_revisions_only=append_revisions_only,
3159
repository=repository)
3304
3160
# Creating on a remote bzr dir.
3305
3161
# 2) try direct creation via RPC
3306
path = a_controldir._path_for_remote_call(a_controldir._client)
3162
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
3308
3164
# XXX JRV20100304: Support creating colocated branches
3309
3165
raise errors.NoColocatedBranchSupport(self)
3310
verb = b'BzrDir.create_branch'
3166
verb = 'BzrDir.create_branch'
3312
response = a_controldir._call(verb, path, network_name)
3168
response = a_bzrdir._call(verb, path, network_name)
3313
3169
except errors.UnknownSmartMethod:
3314
3170
# Fallback - use vfs methods
3315
3171
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':
3172
return self._vfs_initialize(a_bzrdir, name=name,
3173
append_revisions_only=append_revisions_only,
3174
repository=repository)
3175
if response[0] != 'ok':
3320
3176
raise errors.UnexpectedSmartServerResponse(response)
3321
3177
# Turn the response into a RemoteRepository object.
3322
3178
format = RemoteBranchFormat(network_name=response[1])
3323
3179
repo_format = response_tuple_to_repo_format(response[3:])
3324
repo_path = response[2].decode('utf-8')
3180
repo_path = response[2]
3325
3181
if repository is not None:
3326
remote_repo_url = urlutils.join(a_controldir.user_url, repo_path)
3182
remote_repo_url = urlutils.join(a_bzrdir.user_url, repo_path)
3327
3183
url_diff = urlutils.relative_url(repository.user_url,
3329
3185
if url_diff != '.':
3330
3186
raise AssertionError(
3331
3187
'repository.user_url %r does not match URL from server '
3332
3188
'response (%r + %r)'
3333
% (repository.user_url, a_controldir.user_url, repo_path))
3189
% (repository.user_url, a_bzrdir.user_url, repo_path))
3334
3190
remote_repo = repository
3336
3192
if repo_path == '':
3337
repo_bzrdir = a_controldir
3193
repo_bzrdir = a_bzrdir
3339
3195
repo_bzrdir = RemoteBzrDir(
3340
a_controldir.root_transport.clone(
3341
repo_path), a_controldir._format,
3342
a_controldir._client)
3196
a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
3343
3198
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
3344
remote_branch = RemoteBranch(a_controldir, remote_repo,
3345
format=format, setup_stacking=False, name=name)
3199
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
3200
format=format, setup_stacking=False, name=name)
3346
3201
if append_revisions_only:
3347
3202
remote_branch.set_append_revisions_only(append_revisions_only)
3348
3203
# XXX: We know this is a new branch, so it must have revno 0, revid
4014
3852
def is_locked(self):
4015
3853
return self._lock_count >= 1
4017
3856
def revision_id_to_dotted_revno(self, revision_id):
4018
3857
"""Given a revision id, return its dotted revno.
4020
3859
:return: a tuple like (1,) or (400,1,3).
4022
with self.lock_read():
4024
response = self._call(b'Branch.revision_id_to_revno',
4025
self._remote_path(), revision_id)
4026
except errors.UnknownSmartMethod:
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(
4037
if response[0] == b'ok':
4038
return tuple([int(x) for x in response[1:]])
4040
raise errors.UnexpectedSmartServerResponse(response)
3862
response = self._call('Branch.revision_id_to_revno',
3863
self._remote_path(), revision_id)
3864
except errors.UnknownSmartMethod:
3866
return self._real_branch.revision_id_to_dotted_revno(revision_id)
3867
if response[0] == 'ok':
3868
return tuple([int(x) for x in response[1:]])
3870
raise errors.UnexpectedSmartServerResponse(response)
4042
3873
def revision_id_to_revno(self, revision_id):
4043
3874
"""Given a revision id on the branch mainline, return its revno.
4045
3876
:return: an integer
4047
with self.lock_read():
4049
response = self._call(b'Branch.revision_id_to_revno',
4050
self._remote_path(), revision_id)
4051
except errors.UnknownSmartMethod:
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)
4059
raise errors.UnexpectedSmartServerResponse(response)
3879
response = self._call('Branch.revision_id_to_revno',
3880
self._remote_path(), revision_id)
3881
except errors.UnknownSmartMethod:
3883
return self._real_branch.revision_id_to_revno(revision_id)
3884
if response[0] == 'ok':
3885
if len(response) == 2:
3886
return int(response[1])
3887
raise NoSuchRevision(self, revision_id)
3889
raise errors.UnexpectedSmartServerResponse(response)
4061
3892
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)
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:
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
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
4088
raise errors.UnexpectedSmartServerResponse(response)
3893
# XXX: These should be returned by the set_last_revision_info verb
3894
old_revno, old_revid = self.last_revision_info()
3895
self._run_pre_change_branch_tip_hooks(revno, revision_id)
3896
if not revision_id or not isinstance(revision_id, basestring):
3897
raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
3899
response = self._call('Branch.set_last_revision_info',
3900
self._remote_path(), self._lock_token, self._repo_lock_token,
3901
str(revno), revision_id)
3902
except errors.UnknownSmartMethod:
3904
self._clear_cached_state_of_remote_branch_only()
3905
self._real_branch.set_last_revision_info(revno, revision_id)
3906
self._last_revision_info_cache = revno, revision_id
3908
if response == ('ok',):
3909
self._clear_cached_state()
3910
self._last_revision_info_cache = revno, revision_id
3911
self._run_post_change_branch_tip_hooks(old_revno, old_revid)
3912
# Update the _real_branch's cache too.
3913
if self._real_branch is not None:
3914
cache = self._last_revision_info_cache
3915
self._real_branch._last_revision_info_cache = cache
3917
raise errors.UnexpectedSmartServerResponse(response)
4090
3920
def generate_revision_history(self, revision_id, last_rev=None,
4091
3921
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
4097
self._set_last_revision_descendant(revision_id, other_branch,
4098
allow_diverged=True, allow_overwrite_descendant=True)
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),
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)
3922
medium = self._client._medium
3923
if not medium._is_remote_before((1, 6)):
3924
# Use a smart method for 1.6 and above servers
3926
self._set_last_revision_descendant(revision_id, other_branch,
3927
allow_diverged=True, allow_overwrite_descendant=True)
3929
except errors.UnknownSmartMethod:
3930
medium._remember_remote_is_before((1, 6))
3931
self._clear_cached_state_of_remote_branch_only()
3932
graph = self.repository.get_graph()
3933
(last_revno, last_revid) = self.last_revision_info()
3934
known_revision_ids = [
3935
(last_revid, last_revno),
3936
(_mod_revision.NULL_REVISION, 0),
3938
if last_rev is not None:
3939
if not graph.is_ancestor(last_rev, revision_id):
3940
# our previous tip is not merged into stop_revision
3941
raise errors.DivergedBranches(self, other_branch)
3942
revno = graph.find_distance_to_null(revision_id, known_revision_ids)
3943
self.set_last_revision_info(revno, revision_id)
4117
3945
def set_push_location(self, location):
4118
3946
self._set_config_location('push_location', location)
4144
3972
self._ensure_real()
4145
3973
return self._real_branch.heads_to_fetch()
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()
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))
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)
4165
self._real_branch.set_reference_info(
4166
file_id, branch_location, tree_path)
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)
4172
self._real_branch._set_all_reference_info(reference_info)
4174
def _get_all_reference_info(self):
4175
if not self._format.supports_reference_locations:
4178
response, handler = self._call_expecting_body(
4179
b'Branch.get_all_reference_info', self._remote_path())
4180
except errors.UnknownSmartMethod:
4182
return self._real_branch._get_all_reference_info()
4183
if len(response) and response[0] != b'ok':
4184
raise errors.UnexpectedSmartServerResponse(response)
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)
4190
def reference_parent(self, file_id, path, possible_transports=None):
4191
"""Return the parent branch for a tree-reference.
4193
:param path: The path of the nested tree in the tree
4194
:return: A branch associated with the nested tree
4196
branch_location = self.get_reference_info(file_id)[0]
4197
if branch_location is None:
4199
return branch.Branch.open_from_transport(
4200
self.controldir.root_transport.clone(path),
4201
possible_transports=possible_transports)
4202
except errors.NotBranchError:
4204
return branch.Branch.open(
4206
urlutils.strip_segment_parameters(self.user_url), branch_location),
4207
possible_transports=possible_transports)
4210
3976
class RemoteConfig(object):
4211
3977
"""A Config that reads and writes from smart verbs.
4424
4191
raise translator(err)
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])))
4194
error_translators.register('NoSuchRevision',
4195
lambda err, find, get_path: NoSuchRevision(
4196
find('branch'), err.error_args[0]))
4197
error_translators.register('nosuchrevision',
4198
lambda err, find, get_path: NoSuchRevision(
4199
find('repository'), err.error_args[0]))
4439
4201
def _translate_nobranch_error(err, find, get_path):
4440
4202
if len(err.error_args) >= 1:
4441
extra = err.error_args[0].decode('utf-8')
4203
extra = err.error_args[0]
4444
4206
return errors.NotBranchError(path=find('bzrdir').root_transport.base,
4448
error_translators.register(b'nobranch', _translate_nobranch_error)
4449
error_translators.register(b'norepository',
4450
lambda err, find, get_path: errors.NoRepositoryPresent(
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')))
4209
error_translators.register('nobranch', _translate_nobranch_error)
4210
error_translators.register('norepository',
4211
lambda err, find, get_path: errors.NoRepositoryPresent(
4213
error_translators.register('UnlockableTransport',
4214
lambda err, find, get_path: errors.UnlockableTransport(
4215
find('bzrdir').root_transport))
4216
error_translators.register('TokenMismatch',
4217
lambda err, find, get_path: errors.TokenMismatch(
4218
find('token'), '(remote token)'))
4219
error_translators.register('Diverged',
4220
lambda err, find, get_path: errors.DivergedBranches(
4221
find('branch'), find('other_branch')))
4222
error_translators.register('NotStacked',
4223
lambda err, find, get_path: errors.NotStacked(branch=find('branch')))
4465
4225
def _translate_PermissionDenied(err, find, get_path):
4466
4226
path = get_path()
4467
4227
if len(err.error_args) >= 2:
4468
extra = err.error_args[1].decode('utf-8')
4228
extra = err.error_args[1]
4471
4231
return errors.PermissionDenied(path, extra=extra)
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()))
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')))
4233
error_translators.register('PermissionDenied', _translate_PermissionDenied)
4234
error_translators.register('ReadError',
4235
lambda err, find, get_path: errors.ReadError(get_path()))
4236
error_translators.register('NoSuchFile',
4237
lambda err, find, get_path: errors.NoSuchFile(get_path()))
4238
error_translators.register('TokenLockingNotSupported',
4239
lambda err, find, get_path: errors.TokenLockingNotSupported(
4240
find('repository')))
4241
error_translators.register('UnsuspendableWriteGroup',
4242
lambda err, find, get_path: errors.UnsuspendableWriteGroup(
4243
repository=find('repository')))
4244
error_translators.register('UnresumableWriteGroup',
4245
lambda err, find, get_path: errors.UnresumableWriteGroup(
4246
repository=find('repository'), write_groups=err.error_args[0],
4247
reason=err.error_args[1]))
4248
no_context_error_translators.register('IncompatibleRepositories',
4249
lambda err: errors.IncompatibleRepositories(
4250
err.error_args[0], err.error_args[1], err.error_args[2]))
4251
no_context_error_translators.register('LockContention',
4252
lambda err: errors.LockContention('(remote lock)'))
4253
no_context_error_translators.register('LockFailed',
4254
lambda err: errors.LockFailed(err.error_args[0], err.error_args[1]))
4255
no_context_error_translators.register('TipChangeRejected',
4256
lambda err: errors.TipChangeRejected(err.error_args[0].decode('utf8')))
4257
no_context_error_translators.register('UnstackableBranchFormat',
4258
lambda err: errors.UnstackableBranchFormat(*err.error_args))
4259
no_context_error_translators.register('UnstackableRepositoryFormat',
4260
lambda err: errors.UnstackableRepositoryFormat(*err.error_args))
4261
no_context_error_translators.register('FileExists',
4262
lambda err: errors.FileExists(err.error_args[0]))
4263
no_context_error_translators.register('DirectoryNotEmpty',
4264
lambda err: errors.DirectoryNotEmpty(err.error_args[0]))
4519
4266
def _translate_short_readv_error(err):
4520
4267
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')))
4527
no_context_error_translators.register(b'ShortReadvError',
4528
_translate_short_readv_error)
4268
return errors.ShortReadvError(args[0], int(args[1]), int(args[2]),
4271
no_context_error_translators.register('ShortReadvError',
4272
_translate_short_readv_error)
4531
4274
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)
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')))
4559
no_context_error_translators.register(b'BzrCheckError',
4560
lambda err: errors.BzrCheckError(msg=err.error_args[0].decode('utf-8')))
4275
encoding = str(err.error_args[0]) # encoding must always be a string
4276
val = err.error_args[1]
4277
start = int(err.error_args[2])
4278
end = int(err.error_args[3])
4279
reason = str(err.error_args[4]) # reason must always be a string
4280
if val.startswith('u:'):
4281
val = val[2:].decode('utf-8')
4282
elif val.startswith('s:'):
4283
val = val[2:].decode('base64')
4284
if err.error_verb == 'UnicodeDecodeError':
4285
raise UnicodeDecodeError(encoding, val, start, end, reason)
4286
elif err.error_verb == 'UnicodeEncodeError':
4287
raise UnicodeEncodeError(encoding, val, start, end, reason)
4289
no_context_error_translators.register('UnicodeEncodeError',
4290
_translate_unicode_error)
4291
no_context_error_translators.register('UnicodeDecodeError',
4292
_translate_unicode_error)
4293
no_context_error_translators.register('ReadOnlyError',
4294
lambda err: errors.TransportNotPossible('readonly transport'))
4295
no_context_error_translators.register('MemoryError',
4296
lambda err: errors.BzrError("remote server out of memory\n"
4297
"Retry non-remotely, or contact the server admin for details."))
4298
no_context_error_translators.register('RevisionNotPresent',
4299
lambda err: errors.RevisionNotPresent(err.error_args[0], err.error_args[1]))
4301
no_context_error_translators.register('BzrCheckError',
4302
lambda err: errors.BzrCheckError(msg=err.error_args[0]))