162
135
def open_repository(self):
163
136
path = self._path_for_remote_call(self._client)
164
verb = 'BzrDir.find_repositoryV2'
167
response = self._client.call(verb, path)
168
except errors.UnknownSmartMethod:
169
verb = 'BzrDir.find_repository'
170
response = self._client.call(verb, path)
171
except errors.ErrorFromSmartServer, err:
172
self._translate_error(err)
173
if response[0] != 'ok':
174
raise errors.UnexpectedSmartServerResponse(response)
175
if verb == 'BzrDir.find_repository':
176
# servers that don't support the V2 method don't support external
178
response = response + ('no', )
179
if not (len(response) == 5):
180
raise SmartProtocolError('incorrect response length %s' % (response,))
137
response = self._client.call('BzrDir.find_repository', path)
138
assert response[0] in ('ok', 'norepository'), \
139
'unexpected response code %s' % (response,)
140
if response[0] == 'norepository':
141
raise errors.NoRepositoryPresent(self)
142
assert len(response) == 4, 'incorrect response length %s' % (response,)
181
143
if response[1] == '':
182
144
format = RemoteRepositoryFormat()
183
145
format.rich_root_data = (response[2] == 'yes')
184
146
format.supports_tree_reference = (response[3] == 'yes')
185
# No wire format to check this yet.
186
format.supports_external_lookups = (response[4] == 'yes')
187
# Used to support creating a real format instance when needed.
188
format._creating_bzrdir = self
189
147
return RemoteRepository(self, format)
191
149
raise errors.NoRepositoryPresent(self)
238
191
Instances of this repository are represented by RemoteRepository
241
The RemoteRepositoryFormat is parameterized during construction
194
The RemoteRepositoryFormat is parameterised during construction
242
195
to reflect the capabilities of the real, remote format. Specifically
243
196
the attributes rich_root_data and supports_tree_reference are set
244
197
on a per instance basis, and are not set (and should not be) at
248
_matchingbzrdir = RemoteBzrDirFormat()
201
_matchingbzrdir = RemoteBzrDirFormat
250
203
def initialize(self, a_bzrdir, shared=False):
251
if not isinstance(a_bzrdir, RemoteBzrDir):
252
prior_repo = self._creating_bzrdir.open_repository()
253
prior_repo._ensure_real()
254
return prior_repo._real_repository._format.initialize(
255
a_bzrdir, shared=shared)
204
assert isinstance(a_bzrdir, RemoteBzrDir), \
205
'%r is not a RemoteBzrDir' % (a_bzrdir,)
256
206
return a_bzrdir.create_repository(shared=shared)
258
208
def open(self, a_bzrdir):
259
if not isinstance(a_bzrdir, RemoteBzrDir):
260
raise AssertionError('%r is not a RemoteBzrDir' % (a_bzrdir,))
209
assert isinstance(a_bzrdir, RemoteBzrDir)
261
210
return a_bzrdir.open_repository()
263
212
def get_format_description(self):
361
298
#self._real_repository = self.bzrdir._real_bzrdir.open_repository()
362
299
self._set_real_repository(self.bzrdir._real_bzrdir.open_repository())
364
def _translate_error(self, err, **context):
365
self.bzrdir._translate_error(err, repository=self, **context)
367
def find_text_key_references(self):
368
"""Find the text key references within the repository.
370
:return: a dictionary mapping (file_id, revision_id) tuples to altered file-ids to an iterable of
371
revision_ids. Each altered file-ids has the exact revision_ids that
372
altered it listed explicitly.
373
:return: A dictionary mapping text keys ((fileid, revision_id) tuples)
374
to whether they were referred to by the inventory of the
375
revision_id that they contain. The inventory texts from all present
376
revision ids are assessed to generate this report.
379
return self._real_repository.find_text_key_references()
381
def _generate_text_key_index(self):
382
"""Generate a new text key index for the repository.
384
This is an expensive function that will take considerable time to run.
386
:return: A dict mapping (file_id, revision_id) tuples to a list of
387
parents, also (file_id, revision_id) tuples.
390
return self._real_repository._generate_text_key_index()
392
@symbol_versioning.deprecated_method(symbol_versioning.one_four)
393
301
def get_revision_graph(self, revision_id=None):
394
302
"""See Repository.get_revision_graph()."""
395
return self._get_revision_graph(revision_id)
397
def _get_revision_graph(self, revision_id):
398
"""Private method for using with old (< 1.2) servers to fallback."""
399
303
if revision_id is None:
401
elif revision.is_null(revision_id):
305
elif revision_id == NULL_REVISION:
404
308
path = self.bzrdir._path_for_remote_call(self._client)
406
response = self._client.call_expecting_body(
407
'Repository.get_revision_graph', path, revision_id)
408
except errors.ErrorFromSmartServer, err:
409
self._translate_error(err)
410
response_tuple, response_handler = response
411
if response_tuple[0] != 'ok':
412
raise errors.UnexpectedSmartServerResponse(response_tuple)
413
coded = response_handler.read_body_bytes()
415
# no revisions in this repository!
417
lines = coded.split('\n')
420
d = tuple(line.split())
421
revision_graph[d[0]] = d[1:]
423
return revision_graph
309
assert type(revision_id) is str
310
response = self._client.call_expecting_body(
311
'Repository.get_revision_graph', path, revision_id)
312
if response[0][0] not in ['ok', 'nosuchrevision']:
313
raise errors.UnexpectedSmartServerResponse(response[0])
314
if response[0][0] == 'ok':
315
coded = response[1].read_body_bytes()
317
# no revisions in this repository!
319
lines = coded.split('\n')
322
d = tuple(line.split())
323
revision_graph[d[0]] = d[1:]
325
return revision_graph
327
response_body = response[1].read_body_bytes()
328
assert response_body == ''
329
raise NoSuchRevision(self, revision_id)
425
331
def has_revision(self, revision_id):
426
332
"""See Repository.has_revision()."""
427
if revision_id == NULL_REVISION:
333
if revision_id is None:
428
334
# The null revision is always present.
430
336
path = self.bzrdir._path_for_remote_call(self._client)
431
response = self._client.call(
432
'Repository.has_revision', path, revision_id)
433
if response[0] not in ('yes', 'no'):
434
raise errors.UnexpectedSmartServerResponse(response)
337
response = self._client.call('Repository.has_revision', path, revision_id)
338
assert response[0] in ('yes', 'no'), 'unexpected response code %s' % (response,)
435
339
return response[0] == 'yes'
437
def has_revisions(self, revision_ids):
438
"""See Repository.has_revisions()."""
440
for revision_id in revision_ids:
441
if self.has_revision(revision_id):
442
result.add(revision_id)
445
341
def has_same_location(self, other):
446
342
return (self.__class__ == other.__class__ and
447
343
self.bzrdir.transport.base == other.bzrdir.transport.base)
449
345
def get_graph(self, other_repository=None):
450
346
"""Return the graph for this repository format"""
451
parents_provider = self
452
if (other_repository is not None and
453
other_repository.bzrdir.transport.base !=
454
self.bzrdir.transport.base):
455
parents_provider = graph._StackedParentsProvider(
456
[parents_provider, other_repository._make_parents_provider()])
457
return graph.Graph(parents_provider)
347
return self._real_repository.get_graph(other_repository)
459
349
def gather_stats(self, revid=None, committers=None):
460
350
"""See Repository.gather_stats()."""
461
351
path = self.bzrdir._path_for_remote_call(self._client)
462
# revid can be None to indicate no revisions, not just NULL_REVISION
463
if revid is None or revision.is_null(revid):
352
if revid in (None, NULL_REVISION):
466
355
fmt_revid = revid
613
478
def _unlock(self, token):
614
479
path = self.bzrdir._path_for_remote_call(self._client)
616
# with no token the remote repository is not persistently locked.
619
response = self._client.call('Repository.unlock', path, token)
620
except errors.ErrorFromSmartServer, err:
621
self._translate_error(err, token=token)
480
response = self._client.call('Repository.unlock', path, token)
622
481
if response == ('ok',):
483
elif response[0] == 'TokenMismatch':
484
raise errors.TokenMismatch(token, '(remote token)')
625
486
raise errors.UnexpectedSmartServerResponse(response)
627
488
def unlock(self):
489
if self._lock_count == 1 and self._lock_mode == 'w':
490
# don't unlock if inside a write group.
491
if self.is_in_write_group():
492
raise errors.BzrError(
493
'Must end write groups before releasing write locks.')
628
494
self._lock_count -= 1
629
if self._lock_count > 0:
631
self._parents_map = None
632
if 'hpss' in debug.debug_flags:
633
self._requested_parents = None
634
old_mode = self._lock_mode
635
self._lock_mode = None
637
# The real repository is responsible at present for raising an
638
# exception if it's in an unfinished write group. However, it
639
# normally will *not* actually remove the lock from disk - that's
640
# done by the server on receiving the Repository.unlock call.
641
# This is just to let the _real_repository stay up to date.
495
if not self._lock_count:
496
mode = self._lock_mode
497
self._lock_mode = None
642
498
if self._real_repository is not None:
643
499
self._real_repository.unlock()
645
# The rpc-level lock should be released even if there was a
646
# problem releasing the vfs-based lock.
648
501
# Only write-locked repositories need to make a remote method
649
502
# call to perfom the unlock.
650
old_token = self._lock_token
651
self._lock_token = None
652
if not self._leave_lock:
653
self._unlock(old_token)
504
assert self._lock_token, 'Locked, but no token!'
505
token = self._lock_token
506
self._lock_token = None
507
if not self._leave_lock:
655
510
def break_lock(self):
656
511
# should hand off to the network
752
605
return self._real_repository.clone(a_bzrdir, revision_id=revision_id)
754
607
def make_working_trees(self):
755
"""See Repository.make_working_trees"""
757
return self._real_repository.make_working_trees()
759
def revision_ids_to_search_result(self, result_set):
760
"""Convert a set of revision ids to a graph SearchResult."""
761
result_parents = set()
762
for parents in self.get_graph().get_parent_map(
763
result_set).itervalues():
764
result_parents.update(parents)
765
included_keys = result_set.intersection(result_parents)
766
start_keys = result_set.difference(included_keys)
767
exclude_keys = result_parents.difference(result_set)
768
result = graph.SearchResult(start_keys, exclude_keys,
769
len(result_set), result_set)
773
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
774
"""Return the revision ids that other has that this does not.
776
These are returned in topological order.
778
revision_id: only return revision ids included by revision_id.
780
return repository.InterRepository.get(
781
other, self).search_missing_revision_ids(revision_id, find_ghosts)
608
"""RemoteRepositories never create working trees by default."""
783
611
def fetch(self, source, revision_id=None, pb=None):
784
612
if self.has_same_location(source):
785
613
# check that last_revision is in 'from' and then return a
787
615
if (revision_id is not None and
788
not revision.is_null(revision_id)):
616
not _mod_revision.is_null(revision_id)):
789
617
self.get_revision(revision_id)
791
619
self._ensure_real()
796
624
self._ensure_real()
797
625
self._real_repository.create_bundle(target, base, fileobj, format)
628
def control_weaves(self):
630
return self._real_repository.control_weaves
800
633
def get_ancestry(self, revision_id, topo_sorted=True):
801
634
self._ensure_real()
802
635
return self._real_repository.get_ancestry(revision_id, topo_sorted)
638
def get_inventory_weave(self):
640
return self._real_repository.get_inventory_weave()
804
642
def fileids_altered_by_revision_ids(self, revision_ids):
805
643
self._ensure_real()
806
644
return self._real_repository.fileids_altered_by_revision_ids(revision_ids)
808
def _get_versioned_file_checker(self, revisions, revision_versions_cache):
810
return self._real_repository._get_versioned_file_checker(
811
revisions, revision_versions_cache)
813
646
def iter_files_bytes(self, desired_files):
814
647
"""See Repository.iter_file_bytes.
816
649
self._ensure_real()
817
650
return self._real_repository.iter_files_bytes(desired_files)
820
def _fetch_order(self):
821
"""Decorate the real repository for now.
823
In the long term getting this back from the remote repository as part
824
of open would be more efficient.
827
return self._real_repository._fetch_order
830
def _fetch_uses_deltas(self):
831
"""Decorate the real repository for now.
833
In the long term getting this back from the remote repository as part
834
of open would be more efficient.
837
return self._real_repository._fetch_uses_deltas
840
def _fetch_reconcile(self):
841
"""Decorate the real repository for now.
843
In the long term getting this back from the remote repository as part
844
of open would be more efficient.
847
return self._real_repository._fetch_reconcile
849
def get_parent_map(self, keys):
850
"""See bzrlib.Graph.get_parent_map()."""
851
# Hack to build up the caching logic.
852
ancestry = self._parents_map
854
# Repository is not locked, so there's no cache.
855
missing_revisions = set(keys)
858
missing_revisions = set(key for key in keys if key not in ancestry)
859
if missing_revisions:
860
parent_map = self._get_parent_map(missing_revisions)
861
if 'hpss' in debug.debug_flags:
862
mutter('retransmitted revisions: %d of %d',
863
len(set(ancestry).intersection(parent_map)),
865
ancestry.update(parent_map)
866
present_keys = [k for k in keys if k in ancestry]
867
if 'hpss' in debug.debug_flags:
868
if self._requested_parents is not None and len(ancestry) != 0:
869
self._requested_parents.update(present_keys)
870
mutter('Current RemoteRepository graph hit rate: %d%%',
871
100.0 * len(self._requested_parents) / len(ancestry))
872
return dict((k, ancestry[k]) for k in present_keys)
874
def _get_parent_map(self, keys):
875
"""Helper for get_parent_map that performs the RPC."""
876
medium = self._client._medium
877
if medium._is_remote_before((1, 2)):
878
# We already found out that the server can't understand
879
# Repository.get_parent_map requests, so just fetch the whole
881
# XXX: Note that this will issue a deprecation warning. This is ok
882
# :- its because we're working with a deprecated server anyway, and
883
# the user will almost certainly have seen a warning about the
884
# server version already.
885
rg = self.get_revision_graph()
886
# There is an api discrepency between get_parent_map and
887
# get_revision_graph. Specifically, a "key:()" pair in
888
# get_revision_graph just means a node has no parents. For
889
# "get_parent_map" it means the node is a ghost. So fix up the
890
# graph to correct this.
891
# https://bugs.launchpad.net/bzr/+bug/214894
892
# There is one other "bug" which is that ghosts in
893
# get_revision_graph() are not returned at all. But we won't worry
894
# about that for now.
895
for node_id, parent_ids in rg.iteritems():
897
rg[node_id] = (NULL_REVISION,)
898
rg[NULL_REVISION] = ()
903
raise ValueError('get_parent_map(None) is not valid')
904
if NULL_REVISION in keys:
905
keys.discard(NULL_REVISION)
906
found_parents = {NULL_REVISION:()}
911
# TODO(Needs analysis): We could assume that the keys being requested
912
# from get_parent_map are in a breadth first search, so typically they
913
# will all be depth N from some common parent, and we don't have to
914
# have the server iterate from the root parent, but rather from the
915
# keys we're searching; and just tell the server the keyspace we
916
# already have; but this may be more traffic again.
918
# Transform self._parents_map into a search request recipe.
919
# TODO: Manage this incrementally to avoid covering the same path
920
# repeatedly. (The server will have to on each request, but the less
921
# work done the better).
922
parents_map = self._parents_map
923
if parents_map is None:
924
# Repository is not locked, so there's no cache.
926
start_set = set(parents_map)
927
result_parents = set()
928
for parents in parents_map.itervalues():
929
result_parents.update(parents)
930
stop_keys = result_parents.difference(start_set)
931
included_keys = start_set.intersection(result_parents)
932
start_set.difference_update(included_keys)
933
recipe = (start_set, stop_keys, len(parents_map))
934
body = self._serialise_search_recipe(recipe)
935
path = self.bzrdir._path_for_remote_call(self._client)
937
if type(key) is not str:
939
"key %r not a plain string" % (key,))
940
verb = 'Repository.get_parent_map'
941
args = (path,) + tuple(keys)
943
response = self._client.call_with_body_bytes_expecting_body(
944
verb, args, self._serialise_search_recipe(recipe))
945
except errors.UnknownSmartMethod:
946
# Server does not support this method, so get the whole graph.
947
# Worse, we have to force a disconnection, because the server now
948
# doesn't realise it has a body on the wire to consume, so the
949
# only way to recover is to abandon the connection.
951
'Server is too old for fast get_parent_map, reconnecting. '
952
'(Upgrade the server to Bazaar 1.2 to avoid this)')
954
# To avoid having to disconnect repeatedly, we keep track of the
955
# fact the server doesn't understand remote methods added in 1.2.
956
medium._remember_remote_is_before((1, 2))
957
return self.get_revision_graph(None)
958
response_tuple, response_handler = response
959
if response_tuple[0] not in ['ok']:
960
response_handler.cancel_read_body()
961
raise errors.UnexpectedSmartServerResponse(response_tuple)
962
if response_tuple[0] == 'ok':
963
coded = bz2.decompress(response_handler.read_body_bytes())
967
lines = coded.split('\n')
970
d = tuple(line.split())
972
revision_graph[d[0]] = d[1:]
974
# No parents - so give the Graph result (NULL_REVISION,).
975
revision_graph[d[0]] = (NULL_REVISION,)
976
return revision_graph
979
653
def get_signature_text(self, revision_id):
980
654
self._ensure_real()
981
655
return self._real_repository.get_signature_text(revision_id)
984
@symbol_versioning.deprecated_method(symbol_versioning.one_three)
985
658
def get_revision_graph_with_ghosts(self, revision_ids=None):
986
659
self._ensure_real()
987
660
return self._real_repository.get_revision_graph_with_ghosts(
1145
777
return self._real_repository.store_revision_signature(
1146
778
gpg_strategy, plaintext, revision_id)
1148
def add_signature_text(self, revision_id, signature):
1150
return self._real_repository.add_signature_text(revision_id, signature)
1152
780
def has_signature_for_revision_id(self, revision_id):
1153
781
self._ensure_real()
1154
782
return self._real_repository.has_signature_for_revision_id(revision_id)
1156
def item_keys_introduced_by(self, revision_ids, _files_pb=None):
1158
return self._real_repository.item_keys_introduced_by(revision_ids,
1159
_files_pb=_files_pb)
1161
def revision_graph_can_have_wrong_parents(self):
1162
# The answer depends on the remote repo format.
1164
return self._real_repository.revision_graph_can_have_wrong_parents()
1166
def _find_inconsistent_revision_parents(self):
1168
return self._real_repository._find_inconsistent_revision_parents()
1170
def _check_for_inconsistent_revision_parents(self):
1172
return self._real_repository._check_for_inconsistent_revision_parents()
1174
def _make_parents_provider(self):
1177
def _serialise_search_recipe(self, recipe):
1178
"""Serialise a graph search recipe.
1180
:param recipe: A search recipe (start, stop, count).
1181
:return: Serialised bytes.
1183
start_keys = ' '.join(recipe[0])
1184
stop_keys = ' '.join(recipe[1])
1185
count = str(recipe[2])
1186
return '\n'.join((start_keys, stop_keys, count))
1189
785
class RemoteBranchLockableFiles(LockableFiles):
1190
786
"""A 'LockableFiles' implementation that talks to a smart server.
1381
953
repo_token = self.repository.lock_write()
1382
954
self.repository.unlock()
1383
955
path = self.bzrdir._path_for_remote_call(self._client)
1385
response = self._client.call(
1386
'Branch.lock_write', path, branch_token, repo_token or '')
1387
except errors.ErrorFromSmartServer, err:
1388
self._translate_error(err, token=token)
1389
if response[0] != 'ok':
956
response = self._client.call('Branch.lock_write', path, branch_token,
958
if response[0] == 'ok':
959
ok, branch_token, repo_token = response
960
return branch_token, repo_token
961
elif response[0] == 'LockContention':
962
raise errors.LockContention('(remote lock)')
963
elif response[0] == 'TokenMismatch':
964
raise errors.TokenMismatch(token, '(remote token)')
965
elif response[0] == 'UnlockableTransport':
966
raise errors.UnlockableTransport(self.bzrdir.root_transport)
967
elif response[0] == 'ReadOnlyError':
968
raise errors.ReadOnlyError(self)
969
elif response[0] == 'LockFailed':
970
raise errors.LockFailed(response[1], response[2])
1390
972
raise errors.UnexpectedSmartServerResponse(response)
1391
ok, branch_token, repo_token = response
1392
return branch_token, repo_token
1394
974
def lock_write(self, token=None):
1395
975
if not self._lock_mode:
1396
976
remote_tokens = self._remote_lock_write(token)
1397
977
self._lock_token, self._repo_lock_token = remote_tokens
1398
if not self._lock_token:
1399
raise SmartProtocolError('Remote server did not return a token!')
978
assert self._lock_token, 'Remote server did not return a token!'
1400
979
# TODO: We really, really, really don't want to call _ensure_real
1401
980
# here, but it's the easiest way to ensure coherency between the
1402
981
# state of the RemoteBranch and RemoteRepository objects and the
1495
1069
def _gen_revision_history(self):
1496
1070
"""See Branch._gen_revision_history()."""
1497
1071
path = self.bzrdir._path_for_remote_call(self._client)
1498
response_tuple, response_handler = self._client.call_expecting_body(
1072
response = self._client.call_expecting_body(
1499
1073
'Branch.revision_history', path)
1500
if response_tuple[0] != 'ok':
1501
raise errors.UnexpectedSmartServerResponse(response_tuple)
1502
result = response_handler.read_body_bytes().split('\x00')
1074
assert response[0][0] == 'ok', ('unexpected response code %s'
1076
result = response[1].read_body_bytes().split('\x00')
1503
1077
if result == ['']:
1507
def _set_last_revision_descendant(self, revision_id, other_branch,
1508
allow_diverged=False, allow_overwrite_descendant=False):
1509
path = self.bzrdir._path_for_remote_call(self._client)
1511
response = self._client.call('Branch.set_last_revision_ex',
1512
path, self._lock_token, self._repo_lock_token, revision_id,
1513
int(allow_diverged), int(allow_overwrite_descendant))
1514
except errors.ErrorFromSmartServer, err:
1515
self._translate_error(err, other_branch=other_branch)
1516
self._clear_cached_state()
1517
if len(response) != 3 and response[0] != 'ok':
1518
raise errors.UnexpectedSmartServerResponse(response)
1519
new_revno, new_revision_id = response[1:]
1520
self._last_revision_info_cache = new_revno, new_revision_id
1521
self._real_branch._last_revision_info_cache = new_revno, new_revision_id
1523
def _set_last_revision(self, revision_id):
1524
path = self.bzrdir._path_for_remote_call(self._client)
1525
self._clear_cached_state()
1527
response = self._client.call('Branch.set_last_revision',
1528
path, self._lock_token, self._repo_lock_token, revision_id)
1529
except errors.ErrorFromSmartServer, err:
1530
self._translate_error(err)
1531
if response != ('ok',):
1532
raise errors.UnexpectedSmartServerResponse(response)
1534
1081
@needs_write_lock
1535
1082
def set_revision_history(self, rev_history):
1536
1083
# Send just the tip revision of the history; the server will generate
1537
1084
# the full history from that. If the revision doesn't exist in this
1538
1085
# branch, NoSuchRevision will be raised.
1086
path = self.bzrdir._path_for_remote_call(self._client)
1539
1087
if rev_history == []:
1540
1088
rev_id = 'null:'
1542
1090
rev_id = rev_history[-1]
1543
self._set_last_revision(rev_id)
1091
self._clear_cached_state()
1092
response = self._client.call('Branch.set_last_revision',
1093
path, self._lock_token, self._repo_lock_token, rev_id)
1094
if response[0] == 'NoSuchRevision':
1095
raise NoSuchRevision(self, rev_id)
1097
assert response == ('ok',), (
1098
'unexpected response code %r' % (response,))
1544
1099
self._cache_revision_history(rev_history)
1546
1101
def get_parent(self):
1592
1142
def is_locked(self):
1593
1143
return self._lock_count >= 1
1596
def revision_id_to_revno(self, revision_id):
1598
return self._real_branch.revision_id_to_revno(revision_id)
1601
1145
def set_last_revision_info(self, revno, revision_id):
1602
revision_id = ensure_null(revision_id)
1603
path = self.bzrdir._path_for_remote_call(self._client)
1605
response = self._client.call('Branch.set_last_revision_info',
1606
path, self._lock_token, self._repo_lock_token, str(revno), revision_id)
1607
except errors.UnknownSmartMethod:
1609
self._clear_cached_state_of_remote_branch_only()
1610
self._real_branch.set_last_revision_info(revno, revision_id)
1611
self._last_revision_info_cache = revno, revision_id
1613
except errors.ErrorFromSmartServer, err:
1614
self._translate_error(err)
1615
if response == ('ok',):
1616
self._clear_cached_state()
1617
self._last_revision_info_cache = revno, revision_id
1618
# Update the _real_branch's cache too.
1619
if self._real_branch is not None:
1620
cache = self._last_revision_info_cache
1621
self._real_branch._last_revision_info_cache = cache
1623
raise errors.UnexpectedSmartServerResponse(response)
1147
self._clear_cached_state()
1148
return self._real_branch.set_last_revision_info(revno, revision_id)
1626
1150
def generate_revision_history(self, revision_id, last_rev=None,
1627
1151
other_branch=None):
1628
medium = self._client._medium
1629
if not medium._is_remote_before((1, 6)):
1631
self._set_last_revision_descendant(revision_id, other_branch,
1632
allow_diverged=True, allow_overwrite_descendant=True)
1634
except errors.UnknownSmartMethod:
1635
medium._remember_remote_is_before((1, 6))
1636
self._clear_cached_state_of_remote_branch_only()
1637
1152
self._ensure_real()
1638
self._real_branch.generate_revision_history(
1153
return self._real_branch.generate_revision_history(
1639
1154
revision_id, last_rev=last_rev, other_branch=other_branch)
1647
1162
self._ensure_real()
1648
1163
return self._real_branch.set_push_location(location)
1651
def update_revisions(self, other, stop_revision=None, overwrite=False,
1653
"""See Branch.update_revisions."""
1656
if stop_revision is None:
1657
stop_revision = other.last_revision()
1658
if revision.is_null(stop_revision):
1659
# if there are no commits, we're done.
1661
self.fetch(other, stop_revision)
1664
# Just unconditionally set the new revision. We don't care if
1665
# the branches have diverged.
1666
self._set_last_revision(stop_revision)
1668
medium = self._client._medium
1669
if not medium._is_remote_before((1, 6)):
1671
self._set_last_revision_descendant(stop_revision, other)
1673
except errors.UnknownSmartMethod:
1674
medium._remember_remote_is_before((1, 6))
1675
# Fallback for pre-1.6 servers: check for divergence
1676
# client-side, then do _set_last_revision.
1677
last_rev = revision.ensure_null(self.last_revision())
1679
graph = self.repository.get_graph()
1680
if self._check_if_descendant_or_diverged(
1681
stop_revision, last_rev, graph, other):
1682
# stop_revision is a descendant of last_rev, but we aren't
1683
# overwriting, so we're done.
1685
self._set_last_revision(stop_revision)
1165
def update_revisions(self, other, stop_revision=None):
1167
return self._real_branch.update_revisions(
1168
other, stop_revision=stop_revision)
1171
class RemoteBranchConfig(BranchConfig):
1174
self.branch._ensure_real()
1175
return self.branch._real_branch.get_config().username()
1177
def _get_branch_data_config(self):
1178
self.branch._ensure_real()
1179
if self._branch_data_config is None:
1180
self._branch_data_config = TreeConfig(self.branch._real_branch)
1181
return self._branch_data_config
1690
1184
def _extract_tar(tar, to_dir):
1695
1189
for tarinfo in tar:
1696
1190
tar.extract(tarinfo, to_dir)
1699
def _translate_error(err, **context):
1700
"""Translate an ErrorFromSmartServer into a more useful error.
1702
Possible context keys:
1711
return context[name]
1712
except KeyError, keyErr:
1713
mutter('Missing key %r in context %r', keyErr.args[0], context)
1715
if err.error_verb == 'NoSuchRevision':
1716
raise NoSuchRevision(find('branch'), err.error_args[0])
1717
elif err.error_verb == 'nosuchrevision':
1718
raise NoSuchRevision(find('repository'), err.error_args[0])
1719
elif err.error_tuple == ('nobranch',):
1720
raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
1721
elif err.error_verb == 'norepository':
1722
raise errors.NoRepositoryPresent(find('bzrdir'))
1723
elif err.error_verb == 'LockContention':
1724
raise errors.LockContention('(remote lock)')
1725
elif err.error_verb == 'UnlockableTransport':
1726
raise errors.UnlockableTransport(find('bzrdir').root_transport)
1727
elif err.error_verb == 'LockFailed':
1728
raise errors.LockFailed(err.error_args[0], err.error_args[1])
1729
elif err.error_verb == 'TokenMismatch':
1730
raise errors.TokenMismatch(find('token'), '(remote token)')
1731
elif err.error_verb == 'Diverged':
1732
raise errors.DivergedBranches(find('branch'), find('other_branch'))
1733
elif err.error_verb == 'TipChangeRejected':
1734
raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))