1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005-2010 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
1028
1029
:seealso: add_inventory, for the contract.
1030
inv_lines = self._serialise_inventory_to_lines(inv)
1031
inv_lines = self._serializer.write_inventory_to_lines(inv)
1031
1032
return self._inventory_add_lines(revision_id, parents,
1032
1033
inv_lines, check_content=False)
1240
1241
"""Check a single text from this repository."""
1241
1242
if kind == 'inventories':
1242
1243
rev_id = record.key[0]
1243
inv = self.deserialise_inventory(rev_id,
1244
inv = self._deserialise_inventory(rev_id,
1244
1245
record.get_bytes_as('fulltext'))
1245
1246
if last_object is not None:
1246
1247
delta = inv._make_delta(last_object)
1484
1485
:param using: If True, list only branches using this repository.
1486
1487
if using and not self.is_shared():
1488
return [self.bzrdir.open_branch()]
1489
except errors.NotBranchError:
1488
return self.bzrdir.list_branches()
1491
1489
class Evaluator(object):
1493
1491
def __init__(self):
1502
1500
except errors.NoRepositoryPresent:
1505
return False, (None, repository)
1503
return False, ([], repository)
1506
1504
self.first_call = False
1508
value = (bzrdir.open_branch(), None)
1509
except errors.NotBranchError:
1510
value = (None, None)
1505
value = (bzrdir.list_branches(), None)
1511
1506
return True, value
1514
for branch, repository in bzrdir.BzrDir.find_bzrdirs(
1509
for branches, repository in bzrdir.BzrDir.find_bzrdirs(
1515
1510
self.bzrdir.root_transport, evaluate=Evaluator()):
1516
if branch is not None:
1517
branches.append(branch)
1511
if branches is not None:
1512
ret.extend(branches)
1518
1513
if not using and repository is not None:
1519
branches.extend(repository.find_branches())
1514
ret.extend(repository.find_branches())
1522
1517
@needs_read_lock
1523
1518
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1901
1896
rev = self._serializer.read_revision_from_string(text)
1902
1897
yield (revid, rev)
1905
def get_revision_xml(self, revision_id):
1906
# TODO: jam 20070210 This shouldn't be necessary since get_revision
1907
# would have already do it.
1908
# TODO: jam 20070210 Just use _serializer.write_revision_to_string()
1909
# TODO: this can't just be replaced by:
1910
# return self._serializer.write_revision_to_string(
1911
# self.get_revision(revision_id))
1912
# as cStringIO preservers the encoding unlike write_revision_to_string
1913
# or some other call down the path.
1914
rev = self.get_revision(revision_id)
1915
rev_tmp = cStringIO.StringIO()
1916
# the current serializer..
1917
self._serializer.write_revision(rev, rev_tmp)
1919
return rev_tmp.getvalue()
1921
1899
def get_deltas_for_revisions(self, revisions, specific_fileids=None):
1922
1900
"""Produce a generator of revision deltas.
2166
2144
selected_keys = set((revid,) for revid in revision_ids)
2167
2145
w = _inv_weave or self.inventories
2168
pb = ui.ui_factory.nested_progress_bar()
2170
return self._find_file_ids_from_xml_inventory_lines(
2171
w.iter_lines_added_or_present_in_keys(
2172
selected_keys, pb=pb),
2146
return self._find_file_ids_from_xml_inventory_lines(
2147
w.iter_lines_added_or_present_in_keys(
2148
selected_keys, pb=None),
2177
2151
def iter_files_bytes(self, desired_files):
2178
2152
"""Iterate through file versions.
2388
2362
"""single-document based inventory iteration."""
2389
2363
inv_xmls = self._iter_inventory_xmls(revision_ids, ordering)
2390
2364
for text, revision_id in inv_xmls:
2391
yield self.deserialise_inventory(revision_id, text)
2365
yield self._deserialise_inventory(revision_id, text)
2393
2367
def _iter_inventory_xmls(self, revision_ids, ordering):
2394
2368
if ordering is None:
2426
2400
next_key = None
2429
def deserialise_inventory(self, revision_id, xml):
2403
def _deserialise_inventory(self, revision_id, xml):
2430
2404
"""Transform the xml into an inventory object.
2432
2406
:param revision_id: The expected revision id of the inventory.
2440
2414
result.revision_id, revision_id))
2443
def serialise_inventory(self, inv):
2444
return self._serializer.write_inventory_to_string(inv)
2446
def _serialise_inventory_to_lines(self, inv):
2447
return self._serializer.write_inventory_to_lines(inv)
2449
2417
def get_serializer_format(self):
2450
2418
return self._serializer.format_num
2452
2420
@needs_read_lock
2453
def get_inventory_xml(self, revision_id):
2454
"""Get inventory XML as a file object."""
2421
def _get_inventory_xml(self, revision_id):
2422
"""Get serialized inventory as a string."""
2455
2423
texts = self._iter_inventory_xmls([revision_id], 'unordered')
2457
2425
text, revision_id = texts.next()
2459
2427
raise errors.HistoryMissing(self, 'inventory', revision_id)
2463
def get_inventory_sha1(self, revision_id):
2464
"""Return the sha1 hash of the inventory entry
2466
return self.get_revision(revision_id).inventory_sha1
2468
2430
def get_rev_id_for_revno(self, revno, known_pair):
2469
2431
"""Return the revision id of a revno, given a later (revno, revid)
2470
2432
pair in the same history.
2522
2484
next_id = parents[0]
2525
def get_revision_inventory(self, revision_id):
2526
"""Return inventory of a past revision."""
2527
# TODO: Unify this with get_inventory()
2528
# bzr 0.0.6 and later imposes the constraint that the inventory_id
2529
# must be the same as its revision, so this is trivial.
2530
if revision_id is None:
2531
# This does not make sense: if there is no revision,
2532
# then it is the current tree inventory surely ?!
2533
# and thus get_root_id() is something that looks at the last
2534
# commit on the branch, and the get_root_id is an inventory check.
2535
raise NotImplementedError
2536
# return Inventory(self.get_root_id())
2538
return self.get_inventory(revision_id)
2540
2486
def is_shared(self):
2541
2487
"""Return True if this repository is flagged as a shared repository."""
2542
2488
raise NotImplementedError(self.is_shared)
2576
2522
return RevisionTree(self, Inventory(root_id=None),
2577
2523
_mod_revision.NULL_REVISION)
2579
inv = self.get_revision_inventory(revision_id)
2525
inv = self.get_inventory(revision_id)
2580
2526
return RevisionTree(self, inv, revision_id)
2582
2528
def revision_trees(self, revision_ids):
3431
3379
:param revision_id: if None all content is copied, if NULL_REVISION no
3432
3380
content is copied.
3433
:param pb: optional progress bar to use for progress reports. If not
3434
provided a default one will be created.
3384
ui.ui_factory.warn_experimental_format_fetch(self)
3437
3385
f = _mod_fetch.RepoFetcher(to_repository=self.target,
3438
3386
from_repository=self.source,
3439
3387
last_revision=revision_id,
3440
3388
fetch_spec=fetch_spec,
3441
pb=pb, find_ghosts=find_ghosts)
3389
find_ghosts=find_ghosts)
3443
3391
def _walk_to_common_revisions(self, revision_ids):
3444
3392
"""Walk out from revision_ids in source to revisions target has.
4018
3966
"""See InterRepository.fetch()."""
4019
3967
if fetch_spec is not None:
4020
3968
raise AssertionError("Not implemented yet...")
3969
# See <https://launchpad.net/bugs/456077> asking for a warning here
3971
# nb this is only active for local-local fetches; other things using
3973
ui.ui_factory.warn_cross_format_fetch(self.source._format,
3974
self.target._format)
3975
ui.ui_factory.warn_experimental_format_fetch(self)
4021
3976
if (not self.source.supports_rich_root()
4022
3977
and self.target.supports_rich_root()):
4023
3978
self._converting_to_rich_root = True
4098
4053
:param to_convert: The disk object to convert.
4099
4054
:param pb: a progress bar to use for progress information.
4056
pb = ui.ui_factory.nested_progress_bar()
4104
4059
# this is only useful with metadir layouts - separated repo content.
4105
4060
# trigger an assertion if not such
4106
4061
repo._format.get_format_string()
4107
4062
self.repo_dir = repo.bzrdir
4108
self.step('Moving repository to repository.backup')
4063
pb.update('Moving repository to repository.backup')
4109
4064
self.repo_dir.transport.move('repository', 'repository.backup')
4110
4065
backup_transport = self.repo_dir.transport.clone('repository.backup')
4111
4066
repo._format.check_conversion_target(self.target_format)
4112
4067
self.source_repo = repo._format.open(self.repo_dir,
4114
4069
_override_transport=backup_transport)
4115
self.step('Creating new repository')
4070
pb.update('Creating new repository')
4116
4071
converted = self.target_format.initialize(self.repo_dir,
4117
4072
self.source_repo.is_shared())
4118
4073
converted.lock_write()
4120
self.step('Copying content')
4075
pb.update('Copying content')
4121
4076
self.source_repo.copy_content_into(converted)
4123
4078
converted.unlock()
4124
self.step('Deleting old repository content')
4079
pb.update('Deleting old repository content')
4125
4080
self.repo_dir.transport.delete_tree('repository.backup')
4126
4081
ui.ui_factory.note('repository converted')
4128
def step(self, message):
4129
"""Update the pb by a step."""
4131
self.pb.update(message, self.count, self.total)
4134
4085
_unescape_map = {
4316
4267
self._extract_and_insert_inventories(
4317
4268
substream, src_serializer)
4318
4269
elif substream_type == 'inventory-deltas':
4270
ui.ui_factory.warn_cross_format_fetch(src_format,
4271
self.target_repo._format)
4319
4272
self._extract_and_insert_inventory_deltas(
4320
4273
substream, src_serializer)
4321
4274
elif substream_type == 'chk_bytes':
4627
4580
def _get_convertable_inventory_stream(self, revision_ids,
4628
4581
delta_versus_null=False):
4629
# The source is using CHKs, but the target either doesn't or it has a
4630
# different serializer. The StreamSink code expects to be able to
4582
# The two formats are sufficiently different that there is no fast
4583
# path, so we need to send just inventorydeltas, which any
4584
# sufficiently modern client can insert into any repository.
4585
# The StreamSink code expects to be able to
4631
4586
# convert on the target, so we need to put bytes-on-the-wire that can
4632
4587
# be converted. That means inventory deltas (if the remote is <1.19,
4633
4588
# RemoteStreamSink will fallback to VFS to insert the deltas).