107
122
if not self._real_bzrdir:
108
123
self._real_bzrdir = BzrDir.open_from_transport(
109
124
self.root_transport, _server_formats=False)
125
self._format._network_name = \
126
self._real_bzrdir._format.network_name()
111
128
def _translate_error(self, err, **context):
112
129
_translate_error(err, bzrdir=self, **context)
114
def cloning_metadir(self, stacked=False):
131
def break_lock(self):
132
# Prevent aliasing problems in the next_open_branch_result cache.
133
# See create_branch for rationale.
134
self._next_open_branch_result = None
135
return BzrDir.break_lock(self)
137
def _vfs_cloning_metadir(self, require_stacking=False):
115
138
self._ensure_real()
116
return self._real_bzrdir.cloning_metadir(stacked)
139
return self._real_bzrdir.cloning_metadir(
140
require_stacking=require_stacking)
142
def cloning_metadir(self, require_stacking=False):
143
medium = self._client._medium
144
if medium._is_remote_before((1, 13)):
145
return self._vfs_cloning_metadir(require_stacking=require_stacking)
146
verb = 'BzrDir.cloning_metadir'
151
path = self._path_for_remote_call(self._client)
153
response = self._call(verb, path, stacking)
154
except errors.UnknownSmartMethod:
155
medium._remember_remote_is_before((1, 13))
156
return self._vfs_cloning_metadir(require_stacking=require_stacking)
157
except errors.UnknownErrorFromSmartServer, err:
158
if err.error_tuple != ('BranchReference',):
160
# We need to resolve the branch reference to determine the
161
# cloning_metadir. This causes unnecessary RPCs to open the
162
# referenced branch (and bzrdir, etc) but only when the caller
163
# didn't already resolve the branch reference.
164
referenced_branch = self.open_branch()
165
return referenced_branch.bzrdir.cloning_metadir()
166
if len(response) != 3:
167
raise errors.UnexpectedSmartServerResponse(response)
168
control_name, repo_name, branch_info = response
169
if len(branch_info) != 2:
170
raise errors.UnexpectedSmartServerResponse(response)
171
branch_ref, branch_name = branch_info
172
format = bzrdir.network_format_registry.get(control_name)
174
format.repository_format = repository.network_format_registry.get(
176
if branch_ref == 'ref':
177
# XXX: we need possible_transports here to avoid reopening the
178
# connection to the referenced location
179
ref_bzrdir = BzrDir.open(branch_name)
180
branch_format = ref_bzrdir.cloning_metadir().get_branch_format()
181
format.set_branch_format(branch_format)
182
elif branch_ref == 'branch':
184
format.set_branch_format(
185
branch.network_format_registry.get(branch_name))
187
raise errors.UnexpectedSmartServerResponse(response)
118
190
def create_repository(self, shared=False):
119
191
# as per meta1 formats - just delegate to the format object which may
157
238
def get_branch_reference(self):
158
239
"""See BzrDir.get_branch_reference()."""
240
response = self._get_branch_reference()
241
if response[0] == 'ref':
246
def _get_branch_reference(self):
159
247
path = self._path_for_remote_call(self._client)
248
medium = self._client._medium
249
if not medium._is_remote_before((1, 13)):
251
response = self._call('BzrDir.open_branchV2', path)
252
if response[0] not in ('ref', 'branch'):
253
raise errors.UnexpectedSmartServerResponse(response)
255
except errors.UnknownSmartMethod:
256
medium._remember_remote_is_before((1, 13))
160
257
response = self._call('BzrDir.open_branch', path)
161
if response[0] == 'ok':
162
if response[1] == '':
163
# branch at this location.
166
# a branch reference, use the existing BranchReference logic.
258
if response[0] != 'ok':
259
raise errors.UnexpectedSmartServerResponse(response)
260
if response[1] != '':
261
return ('ref', response[1])
169
raise errors.UnexpectedSmartServerResponse(response)
263
return ('branch', '')
171
265
def _get_tree_branch(self):
172
266
"""See BzrDir._get_tree_branch()."""
173
267
return None, self.open_branch()
175
def open_branch(self, _unsupported=False):
269
def open_branch(self, _unsupported=False, ignore_fallbacks=False):
177
271
raise NotImplementedError('unsupported flag support not implemented yet.')
178
reference_url = self.get_branch_reference()
179
if reference_url is None:
180
# branch at this location.
181
return RemoteBranch(self, self.find_repository())
272
if self._next_open_branch_result is not None:
273
# See create_branch for details.
274
result = self._next_open_branch_result
275
self._next_open_branch_result = None
277
response = self._get_branch_reference()
278
if response[0] == 'ref':
183
279
# a branch reference, use the existing BranchReference logic.
184
280
format = BranchReferenceFormat()
185
return format.open(self, _found=True, location=reference_url)
281
return format.open(self, _found=True, location=response[1],
282
ignore_fallbacks=ignore_fallbacks)
283
branch_format_name = response[1]
284
if not branch_format_name:
285
branch_format_name = None
286
format = RemoteBranchFormat(network_name=branch_format_name)
287
return RemoteBranch(self, self.find_repository(), format=format,
288
setup_stacking=not ignore_fallbacks)
290
def _open_repo_v1(self, path):
291
verb = 'BzrDir.find_repository'
292
response = self._call(verb, path)
293
if response[0] != 'ok':
294
raise errors.UnexpectedSmartServerResponse(response)
295
# servers that only support the v1 method don't support external
298
repo = self._real_bzrdir.open_repository()
299
response = response + ('no', repo._format.network_name())
300
return response, repo
302
def _open_repo_v2(self, path):
303
verb = 'BzrDir.find_repositoryV2'
304
response = self._call(verb, path)
305
if response[0] != 'ok':
306
raise errors.UnexpectedSmartServerResponse(response)
308
repo = self._real_bzrdir.open_repository()
309
response = response + (repo._format.network_name(),)
310
return response, repo
312
def _open_repo_v3(self, path):
313
verb = 'BzrDir.find_repositoryV3'
314
medium = self._client._medium
315
if medium._is_remote_before((1, 13)):
316
raise errors.UnknownSmartMethod(verb)
318
response = self._call(verb, path)
319
except errors.UnknownSmartMethod:
320
medium._remember_remote_is_before((1, 13))
322
if response[0] != 'ok':
323
raise errors.UnexpectedSmartServerResponse(response)
324
return response, None
187
326
def open_repository(self):
188
327
path = self._path_for_remote_call(self._client)
189
verb = 'BzrDir.find_repositoryV2'
191
response = self._call(verb, path)
192
except errors.UnknownSmartMethod:
193
verb = 'BzrDir.find_repository'
194
response = self._call(verb, path)
329
for probe in [self._open_repo_v3, self._open_repo_v2,
332
response, real_repo = probe(path)
334
except errors.UnknownSmartMethod:
337
raise errors.UnknownSmartMethod('BzrDir.find_repository{3,2,}')
195
338
if response[0] != 'ok':
196
339
raise errors.UnexpectedSmartServerResponse(response)
197
if verb == 'BzrDir.find_repository':
198
# servers that don't support the V2 method don't support external
200
response = response + ('no', )
201
if not (len(response) == 5):
340
if len(response) != 6:
202
341
raise SmartProtocolError('incorrect response length %s' % (response,))
203
342
if response[1] == '':
204
format = RemoteRepositoryFormat()
205
format.rich_root_data = (response[2] == 'yes')
206
format.supports_tree_reference = (response[3] == 'yes')
207
# No wire format to check this yet.
208
format.supports_external_lookups = (response[4] == 'yes')
343
# repo is at this dir.
344
format = response_tuple_to_repo_format(response[2:])
209
345
# Used to support creating a real format instance when needed.
210
346
format._creating_bzrdir = self
211
347
remote_repo = RemoteRepository(self, format)
212
348
format._creating_repo = remote_repo
349
if real_repo is not None:
350
remote_repo._set_real_repository(real_repo)
213
351
return remote_repo
215
353
raise errors.NoRepositoryPresent(self)
339
508
response = a_bzrdir._call(verb, path, network_name, shared_str)
340
509
except errors.UnknownSmartMethod:
341
510
# Fallback - use vfs methods
511
medium._remember_remote_is_before((1, 13))
342
512
return self._vfs_initialize(a_bzrdir, shared)
344
514
# Turn the response into a RemoteRepository object.
345
format = RemoteRepositoryFormat()
346
format.rich_root_data = (response[1] == 'yes')
347
format.supports_tree_reference = (response[2] == 'yes')
348
format.supports_external_lookups = (response[3] == 'yes')
349
format._network_name = response[4]
515
format = response_tuple_to_repo_format(response[1:])
350
516
# Used to support creating a real format instance when needed.
351
517
format._creating_bzrdir = a_bzrdir
352
518
remote_repo = RemoteRepository(a_bzrdir, format)
353
519
format._creating_repo = remote_repo
354
520
return remote_repo
356
522
def open(self, a_bzrdir):
357
523
if not isinstance(a_bzrdir, RemoteBzrDir):
358
524
raise AssertionError('%r is not a RemoteBzrDir' % (a_bzrdir,))
359
525
return a_bzrdir.open_repository()
527
def _ensure_real(self):
528
if self._custom_format is None:
529
self._custom_format = repository.network_format_registry.get(
533
def _fetch_order(self):
535
return self._custom_format._fetch_order
538
def _fetch_uses_deltas(self):
540
return self._custom_format._fetch_uses_deltas
543
def _fetch_reconcile(self):
545
return self._custom_format._fetch_reconcile
361
547
def get_format_description(self):
362
548
return 'bzr remote repository'
364
550
def __eq__(self, other):
365
return self.__class__ == other.__class__
551
return self.__class__ is other.__class__
367
553
def check_conversion_target(self, target_format):
368
554
if self.rich_root_data and not target_format.rich_root_data:
920
1157
return repository.InterRepository.get(
921
1158
other, self).search_missing_revision_ids(revision_id, find_ghosts)
923
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False):
924
# Not delegated to _real_repository so that InterRepository.get has a
925
# chance to find an InterRepository specialised for RemoteRepository.
926
if self.has_same_location(source):
1160
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1162
# No base implementation to use as RemoteRepository is not a subclass
1163
# of Repository; so this is a copy of Repository.fetch().
1164
if fetch_spec is not None and revision_id is not None:
1165
raise AssertionError(
1166
"fetch_spec and revision_id are mutually exclusive.")
1167
if self.is_in_write_group():
1168
raise errors.InternalBzrError(
1169
"May not fetch while in a write group.")
1170
# fast path same-url fetch operations
1171
if self.has_same_location(source) and fetch_spec is None:
927
1172
# check that last_revision is in 'from' and then return a
929
1174
if (revision_id is not None and
930
1175
not revision.is_null(revision_id)):
931
1176
self.get_revision(revision_id)
1178
# if there is no specific appropriate InterRepository, this will get
1179
# the InterRepository base class, which raises an
1180
# IncompatibleRepositories when asked to fetch.
933
1181
inter = repository.InterRepository.get(source, self)
935
return inter.fetch(revision_id=revision_id, pb=pb, find_ghosts=find_ghosts)
936
except NotImplementedError:
937
raise errors.IncompatibleRepositories(source, self)
1182
return inter.fetch(revision_id=revision_id, pb=pb,
1183
find_ghosts=find_ghosts, fetch_spec=fetch_spec)
939
1185
def create_bundle(self, target, base, fileobj, format=None):
940
1186
self._ensure_real()
1333
1578
self._ensure_real()
1334
1579
self._real_repository._pack_collection.autopack()
1336
if self._real_repository is not None:
1337
# Reset the real repository's cache of pack names.
1338
# XXX: At some point we may be able to skip this and just rely on
1339
# the automatic retry logic to do the right thing, but for now we
1340
# err on the side of being correct rather than being optimal.
1341
self._real_repository._pack_collection.reload_pack_names()
1342
1582
if response[0] != 'ok':
1343
1583
raise errors.UnexpectedSmartServerResponse(response)
1346
1586
class RemoteStreamSink(repository.StreamSink):
1348
def _insert_real(self, stream, src_format):
1588
def _insert_real(self, stream, src_format, resume_tokens):
1349
1589
self.target_repo._ensure_real()
1350
1590
sink = self.target_repo._real_repository._get_sink()
1351
return sink.insert_stream(stream, src_format)
1353
def insert_stream(self, stream, src_format):
1354
repo = self.target_repo
1355
# Until we can handle deltas in stack repositories we can't hand all
1356
# the processing off to a remote server.
1357
if self.target_repo._fallback_repositories:
1358
return self._insert_real(stream, src_format)
1591
result = sink.insert_stream(stream, src_format, resume_tokens)
1593
self.target_repo.autopack()
1596
def insert_stream(self, stream, src_format, resume_tokens):
1597
target = self.target_repo
1598
if target._lock_token:
1599
verb = 'Repository.insert_stream_locked'
1600
extra_args = (target._lock_token or '',)
1601
required_version = (1, 14)
1603
verb = 'Repository.insert_stream'
1605
required_version = (1, 13)
1606
client = target._client
1607
medium = client._medium
1608
if medium._is_remote_before(required_version):
1609
# No possible way this can work.
1610
return self._insert_real(stream, src_format, resume_tokens)
1611
path = target.bzrdir._path_for_remote_call(client)
1612
if not resume_tokens:
1613
# XXX: Ugly but important for correctness, *will* be fixed during
1614
# 1.13 cycle. Pushing a stream that is interrupted results in a
1615
# fallback to the _real_repositories sink *with a partial stream*.
1616
# Thats bad because we insert less data than bzr expected. To avoid
1617
# this we do a trial push to make sure the verb is accessible, and
1618
# do not fallback when actually pushing the stream. A cleanup patch
1619
# is going to look at rewinding/restarting the stream/partial
1621
byte_stream = smart_repo._stream_to_byte_stream([], src_format)
1623
response = client.call_with_body_stream(
1624
(verb, path, '') + extra_args, byte_stream)
1625
except errors.UnknownSmartMethod:
1626
medium._remember_remote_is_before(required_version)
1627
return self._insert_real(stream, src_format, resume_tokens)
1628
byte_stream = smart_repo._stream_to_byte_stream(
1630
resume_tokens = ' '.join(resume_tokens)
1631
response = client.call_with_body_stream(
1632
(verb, path, resume_tokens) + extra_args, byte_stream)
1633
if response[0][0] not in ('ok', 'missing-basis'):
1634
raise errors.UnexpectedSmartServerResponse(response)
1635
if response[0][0] == 'missing-basis':
1636
tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
1637
resume_tokens = tokens
1638
return resume_tokens, missing_keys
1640
self.target_repo.refresh_data()
1644
class RemoteStreamSource(repository.StreamSource):
1645
"""Stream data from a remote server."""
1647
def get_stream(self, search):
1648
if (self.from_repository._fallback_repositories and
1649
self.to_format._fetch_order == 'topological'):
1650
return self._real_stream(self.from_repository, search)
1651
return self.missing_parents_chain(search, [self.from_repository] +
1652
self.from_repository._fallback_repositories)
1654
def _real_stream(self, repo, search):
1655
"""Get a stream for search from repo.
1657
This never called RemoteStreamSource.get_stream, and is a heler
1658
for RemoteStreamSource._get_stream to allow getting a stream
1659
reliably whether fallback back because of old servers or trying
1660
to stream from a non-RemoteRepository (which the stacked support
1663
source = repo._get_source(self.to_format)
1664
if isinstance(source, RemoteStreamSource):
1665
return repository.StreamSource.get_stream(source, search)
1666
return source.get_stream(search)
1668
def _get_stream(self, repo, search):
1669
"""Core worker to get a stream from repo for search.
1671
This is used by both get_stream and the stacking support logic. It
1672
deliberately gets a stream for repo which does not need to be
1673
self.from_repository. In the event that repo is not Remote, or
1674
cannot do a smart stream, a fallback is made to the generic
1675
repository._get_stream() interface, via self._real_stream.
1677
In the event of stacking, streams from _get_stream will not
1678
contain all the data for search - this is normal (see get_stream).
1680
:param repo: A repository.
1681
:param search: A search.
1683
# Fallbacks may be non-smart
1684
if not isinstance(repo, RemoteRepository):
1685
return self._real_stream(repo, search)
1359
1686
client = repo._client
1360
1687
medium = client._medium
1361
if medium._is_remote_before((1,13)):
1362
# No possible way this can work.
1363
return self._insert_real(stream, src_format)
1688
if medium._is_remote_before((1, 13)):
1689
# streaming was added in 1.13
1690
return self._real_stream(repo, search)
1364
1691
path = repo.bzrdir._path_for_remote_call(client)
1365
# XXX: Ugly but important for correctness, *will* be fixed during 1.13
1366
# cycle. Pushing a stream that is interrupted results in a fallback to
1367
# the _real_repositories sink *with a partial stream*. Thats bad
1368
# because we insert less data than bzr expected. To avoid this we do a
1369
# trial push to make sure the verb is accessible, and do not fallback
1370
# when actually pushing the stream. A cleanup patch is going to look at
1371
# rewinding/restarting the stream/partial buffering etc.
1372
byte_stream = self._stream_to_byte_stream([], src_format)
1374
response = client.call_with_body_stream(
1375
('Repository.insert_stream', path), byte_stream)
1693
search_bytes = repo._serialise_search_result(search)
1694
response = repo._call_with_body_bytes_expecting_body(
1695
'Repository.get_stream',
1696
(path, self.to_format.network_name()), search_bytes)
1697
response_tuple, response_handler = response
1376
1698
except errors.UnknownSmartMethod:
1377
1699
medium._remember_remote_is_before((1,13))
1378
return self._insert_real(stream, src_format)
1379
byte_stream = self._stream_to_byte_stream(stream, src_format)
1380
response = client.call_with_body_stream(
1381
('Repository.insert_stream', path), byte_stream)
1382
if response[0][0] not in ('ok', ):
1383
raise errors.UnexpectedSmartServerResponse(response)
1385
def _stream_to_byte_stream(self, stream, src_format):
1387
pack_writer = pack.ContainerWriter(bytes.append)
1389
pack_writer.add_bytes_record(src_format.network_name(), '')
1391
def get_adapter(adapter_key):
1393
return adapters[adapter_key]
1395
adapter_factory = adapter_registry.get(adapter_key)
1396
adapter = adapter_factory(self)
1397
adapters[adapter_key] = adapter
1399
for substream_type, substream in stream:
1400
for record in substream:
1401
if record.storage_kind in ('chunked', 'fulltext'):
1402
serialised = record_to_fulltext_bytes(record)
1700
return self._real_stream(repo, search)
1701
if response_tuple[0] != 'ok':
1702
raise errors.UnexpectedSmartServerResponse(response_tuple)
1703
byte_stream = response_handler.read_streamed_body()
1704
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1705
if src_format.network_name() != repo._format.network_name():
1706
raise AssertionError(
1707
"Mismatched RemoteRepository and stream src %r, %r" % (
1708
src_format.network_name(), repo._format.network_name()))
1711
def missing_parents_chain(self, search, sources):
1712
"""Chain multiple streams together to handle stacking.
1714
:param search: The overall search to satisfy with streams.
1715
:param sources: A list of Repository objects to query.
1717
self.serialiser = self.to_format._serializer
1718
self.seen_revs = set()
1719
self.referenced_revs = set()
1720
# If there are heads in the search, or the key count is > 0, we are not
1722
while not search.is_empty() and len(sources) > 1:
1723
source = sources.pop(0)
1724
stream = self._get_stream(source, search)
1725
for kind, substream in stream:
1726
if kind != 'revisions':
1727
yield kind, substream
1404
serialised = record.get_bytes_as(record.storage_kind)
1405
pack_writer.add_bytes_record(serialised, [(substream_type,)])
1729
yield kind, self.missing_parents_rev_handler(substream)
1730
search = search.refine(self.seen_revs, self.referenced_revs)
1731
self.seen_revs = set()
1732
self.referenced_revs = set()
1733
if not search.is_empty():
1734
for kind, stream in self._get_stream(sources[0], search):
1737
def missing_parents_rev_handler(self, substream):
1738
for content in substream:
1739
revision_bytes = content.get_bytes_as('fulltext')
1740
revision = self.serialiser.read_revision_from_string(revision_bytes)
1741
self.seen_revs.add(content.key[-1])
1742
self.referenced_revs.update(revision.parent_ids)
1414
1746
class RemoteBranchLockableFiles(LockableFiles):
1415
1747
"""A 'LockableFiles' implementation that talks to a smart server.
1417
1749
This is not a public interface class.
1434
1766
class RemoteBranchFormat(branch.BranchFormat):
1768
def __init__(self, network_name=None):
1437
1769
super(RemoteBranchFormat, self).__init__()
1438
1770
self._matchingbzrdir = RemoteBzrDirFormat()
1439
1771
self._matchingbzrdir.set_branch_format(self)
1772
self._custom_format = None
1773
self._network_name = network_name
1441
1775
def __eq__(self, other):
1442
return (isinstance(other, RemoteBranchFormat) and
1776
return (isinstance(other, RemoteBranchFormat) and
1443
1777
self.__dict__ == other.__dict__)
1779
def _ensure_real(self):
1780
if self._custom_format is None:
1781
self._custom_format = branch.network_format_registry.get(
1445
1784
def get_format_description(self):
1446
1785
return 'Remote BZR Branch'
1448
def get_format_string(self):
1449
return 'Remote BZR Branch'
1451
def open(self, a_bzrdir):
1452
return a_bzrdir.open_branch()
1787
def network_name(self):
1788
return self._network_name
1790
def open(self, a_bzrdir, ignore_fallbacks=False):
1791
return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
1793
def _vfs_initialize(self, a_bzrdir):
1794
# Initialisation when using a local bzrdir object, or a non-vfs init
1795
# method is not available on the server.
1796
# self._custom_format is always set - the start of initialize ensures
1798
if isinstance(a_bzrdir, RemoteBzrDir):
1799
a_bzrdir._ensure_real()
1800
result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
1802
# We assume the bzrdir is parameterised; it may not be.
1803
result = self._custom_format.initialize(a_bzrdir)
1804
if (isinstance(a_bzrdir, RemoteBzrDir) and
1805
not isinstance(result, RemoteBranch)):
1806
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
1454
1809
def initialize(self, a_bzrdir):
1455
# Delegate to a _real object here - the RemoteBzrDir format now
1456
# supports delegating to parameterised branch formats and as such
1457
# this RemoteBranchFormat method is only called when no specific format
1810
# 1) get the network name to use.
1811
if self._custom_format:
1812
network_name = self._custom_format.network_name()
1814
# Select the current bzrlib default and ask for that.
1815
reference_bzrdir_format = bzrdir.format_registry.get('default')()
1816
reference_format = reference_bzrdir_format.get_branch_format()
1817
self._custom_format = reference_format
1818
network_name = reference_format.network_name()
1819
# Being asked to create on a non RemoteBzrDir:
1459
1820
if not isinstance(a_bzrdir, RemoteBzrDir):
1460
result = a_bzrdir.create_branch()
1821
return self._vfs_initialize(a_bzrdir)
1822
medium = a_bzrdir._client._medium
1823
if medium._is_remote_before((1, 13)):
1824
return self._vfs_initialize(a_bzrdir)
1825
# Creating on a remote bzr dir.
1826
# 2) try direct creation via RPC
1827
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
1828
verb = 'BzrDir.create_branch'
1830
response = a_bzrdir._call(verb, path, network_name)
1831
except errors.UnknownSmartMethod:
1832
# Fallback - use vfs methods
1833
medium._remember_remote_is_before((1, 13))
1834
return self._vfs_initialize(a_bzrdir)
1835
if response[0] != 'ok':
1836
raise errors.UnexpectedSmartServerResponse(response)
1837
# Turn the response into a RemoteRepository object.
1838
format = RemoteBranchFormat(network_name=response[1])
1839
repo_format = response_tuple_to_repo_format(response[3:])
1840
if response[2] == '':
1841
repo_bzrdir = a_bzrdir
1462
a_bzrdir._ensure_real()
1463
result = a_bzrdir._real_bzrdir.create_branch()
1464
if not isinstance(result, RemoteBranch):
1465
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
1843
repo_bzrdir = RemoteBzrDir(
1844
a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
1846
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
1847
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
1848
format=format, setup_stacking=False)
1849
# XXX: We know this is a new branch, so it must have revno 0, revid
1850
# NULL_REVISION. Creating the branch locked would make this be unable
1851
# to be wrong; here its simply very unlikely to be wrong. RBC 20090225
1852
remote_branch._last_revision_info_cache = 0, NULL_REVISION
1853
return remote_branch
1855
def make_tags(self, branch):
1857
return self._custom_format.make_tags(branch)
1468
1859
def supports_tags(self):
1469
1860
# Remote branches might support tags, but we won't know until we
1470
1861
# access the real remote branch.
1863
return self._custom_format.supports_tags()
1865
def supports_stacking(self):
1867
return self._custom_format.supports_stacking()
1474
1870
class RemoteBranch(branch.Branch, _RpcHelper):
1956
2370
self.set_revision_history(self._lefthand_history(revision_id,
1957
2371
last_rev=last_rev,other_branch=other_branch))
1962
return self._real_branch.tags
1964
2373
def set_push_location(self, location):
1965
2374
self._ensure_real()
1966
2375
return self._real_branch.set_push_location(location)
1969
def update_revisions(self, other, stop_revision=None, overwrite=False,
1971
"""See Branch.update_revisions."""
2378
class RemoteBranchConfig(object):
2379
"""A Config that reads from a smart branch and writes via smart methods.
2381
It is a low-level object that considers config data to be name/value pairs
2382
that may be associated with a section. Assigning meaning to the these
2383
values is done at higher levels like bzrlib.config.TreeConfig.
2386
def __init__(self, branch):
2387
self._branch = branch
2389
def get_option(self, name, section=None, default=None):
2390
"""Return the value associated with a named option.
2392
:param name: The name of the value
2393
:param section: The section the option is in (if any)
2394
:param default: The value to return if the value is not set
2395
:return: The value or default value
2397
configobj = self._get_configobj()
2399
section_obj = configobj
2402
section_obj = configobj[section]
2405
return section_obj.get(name, default)
2407
def _get_configobj(self):
2408
path = self._branch._remote_path()
2409
response = self._branch._client.call_expecting_body(
2410
'Branch.get_config_file', path)
2411
if response[0][0] != 'ok':
2412
raise UnexpectedSmartServerResponse(response)
2413
lines = response[1].read_body_bytes().splitlines()
2414
return config.ConfigObj(lines, encoding='utf-8')
2416
def set_option(self, value, name, section=None):
2417
"""Set the value associated with a named option.
2419
:param value: The value to set
2420
:param name: The name of the value to set
2421
:param section: The section the option is in (if any)
2423
medium = self._branch._client._medium
2424
if medium._is_remote_before((1, 14)):
2425
return self._vfs_set_option(value, name, section)
1974
if stop_revision is None:
1975
stop_revision = other.last_revision()
1976
if revision.is_null(stop_revision):
1977
# if there are no commits, we're done.
1979
self.fetch(other, stop_revision)
2427
path = self._branch._remote_path()
2428
response = self._branch._client.call('Branch.set_config_option',
2429
path, self._branch._lock_token, self._branch._repo_lock_token,
2430
value.encode('utf8'), name, section or '')
2431
except errors.UnknownSmartMethod:
2432
medium._remember_remote_is_before((1, 14))
2433
return self._vfs_set_option(value, name, section)
2435
raise errors.UnexpectedSmartServerResponse(response)
1982
# Just unconditionally set the new revision. We don't care if
1983
# the branches have diverged.
1984
self._set_last_revision(stop_revision)
1986
medium = self._client._medium
1987
if not medium._is_remote_before((1, 6)):
1989
self._set_last_revision_descendant(stop_revision, other)
1991
except errors.UnknownSmartMethod:
1992
medium._remember_remote_is_before((1, 6))
1993
# Fallback for pre-1.6 servers: check for divergence
1994
# client-side, then do _set_last_revision.
1995
last_rev = revision.ensure_null(self.last_revision())
1997
graph = self.repository.get_graph()
1998
if self._check_if_descendant_or_diverged(
1999
stop_revision, last_rev, graph, other):
2000
# stop_revision is a descendant of last_rev, but we aren't
2001
# overwriting, so we're done.
2003
self._set_last_revision(stop_revision)
2437
def _vfs_set_option(self, value, name, section=None):
2438
self._branch._ensure_real()
2439
return self._branch._real_branch._get_config().set_option(
2440
value, name, section)
2008
2443
def _extract_tar(tar, to_dir):