436
435
# revisions. We don't need to see all lines in the inventory because
437
436
# only those added in an inventory in rev X can contain a revision=X
439
for line in w.iter_lines_added_or_present_in_versions(selected_revision_ids):
440
start = line.find('file_id="')+9
441
if start < 9: continue
442
end = line.find('"', start)
444
file_id = _unescape_xml(line[start:end])
438
pb = ui.ui_factory.nested_progress_bar()
440
for line in w.iter_lines_added_or_present_in_versions(
441
selected_revision_ids, pb=pb):
442
start = line.find('file_id="')+9
443
if start < 9: continue
444
end = line.find('"', start)
446
file_id = _unescape_xml(line[start:end])
446
start = line.find('revision="')+10
447
if start < 10: continue
448
end = line.find('"', start)
450
revision_id = _unescape_xml(line[start:end])
451
if revision_id in selected_revision_ids:
452
result.setdefault(file_id, set()).add(revision_id)
448
start = line.find('revision="')+10
449
if start < 10: continue
450
end = line.find('"', start)
452
revision_id = _unescape_xml(line[start:end])
453
if revision_id in selected_revision_ids:
454
result.setdefault(file_id, set()).add(revision_id)
785
795
parent_trees[p_id] = repository.revision_tree(None)
787
797
inv = revision_tree.inventory
798
entries = inv.iter_entries()
789
799
# backwards compatability hack: skip the root id.
790
entries = inv.iter_entries()
800
if not repository.supports_rich_root():
801
path, root = entries.next()
802
if root.revision != rev.revision_id:
803
raise errors.IncompatibleRevision(repr(repository))
792
804
# Add the texts that are not already present
793
805
for path, ie in entries:
794
806
w = repository.weave_store.get_weave_or_empty(ie.file_id,
1009
1021
return self._get_revision_vf().get_parents(revision_id)
1024
class KnitRepository2(KnitRepository):
1026
def __init__(self, _format, a_bzrdir, control_files, _revision_store,
1027
control_store, text_store):
1028
KnitRepository.__init__(self, _format, a_bzrdir, control_files,
1029
_revision_store, control_store, text_store)
1030
self._serializer = xml6.serializer_v6
1032
def deserialise_inventory(self, revision_id, xml):
1033
"""Transform the xml into an inventory object.
1035
:param revision_id: The expected revision id of the inventory.
1036
:param xml: A serialised inventory.
1038
result = self._serializer.read_inventory_from_string(xml)
1039
assert result.root.revision is not None
1042
def serialise_inventory(self, inv):
1043
"""Transform the inventory object into XML text.
1045
:param revision_id: The expected revision id of the inventory.
1046
:param xml: A serialised inventory.
1048
assert inv.revision_id is not None
1049
assert inv.root.revision is not None
1050
return KnitRepository.serialise_inventory(self, inv)
1052
def get_commit_builder(self, branch, parents, config, timestamp=None,
1053
timezone=None, committer=None, revprops=None,
1055
"""Obtain a CommitBuilder for this repository.
1057
:param branch: Branch to commit to.
1058
:param parents: Revision ids of the parents of the new revision.
1059
:param config: Configuration to use.
1060
:param timestamp: Optional timestamp recorded for commit.
1061
:param timezone: Optional timezone for timestamp.
1062
:param committer: Optional committer to set for commit.
1063
:param revprops: Optional dictionary of revision properties.
1064
:param revision_id: Optional revision id.
1066
return RootCommitBuilder(self, parents, config, timestamp, timezone,
1067
committer, revprops, revision_id)
1012
1070
class RepositoryFormat(object):
1013
1071
"""A repository format.
1491
1560
versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
1494
def get_format_string(self):
1495
"""See RepositoryFormat.get_format_string()."""
1496
return "Bazaar-NG Knit Repository Format 1"
1498
def get_format_description(self):
1499
"""See RepositoryFormat.get_format_description()."""
1500
return "Knit repository format 1"
1502
1563
def _get_revision_store(self, repo_transport, control_files):
1503
1564
"""See RepositoryFormat._get_revision_store()."""
1504
1565
from bzrlib.store.revision.knit import KnitRevisionStore
1581
1642
text_store=text_store)
1645
class RepositoryFormatKnit1(RepositoryFormatKnit):
1646
"""Bzr repository knit format 1.
1648
This repository format has:
1649
- knits for file texts and inventory
1650
- hash subdirectory based stores.
1651
- knits for revisions and signatures
1652
- TextStores for revisions and signatures.
1653
- a format marker of its own
1654
- an optional 'shared-storage' flag
1655
- an optional 'no-working-trees' flag
1658
This format was introduced in bzr 0.8.
1660
def get_format_string(self):
1661
"""See RepositoryFormat.get_format_string()."""
1662
return "Bazaar-NG Knit Repository Format 1"
1664
def get_format_description(self):
1665
"""See RepositoryFormat.get_format_description()."""
1666
return "Knit repository format 1"
1668
def check_conversion_target(self, target_format):
1672
class RepositoryFormatKnit2(RepositoryFormatKnit):
1673
"""Bzr repository knit format 2.
1675
THIS FORMAT IS EXPERIMENTAL
1676
This repository format has:
1677
- knits for file texts and inventory
1678
- hash subdirectory based stores.
1679
- knits for revisions and signatures
1680
- TextStores for revisions and signatures.
1681
- a format marker of its own
1682
- an optional 'shared-storage' flag
1683
- an optional 'no-working-trees' flag
1685
- Support for recording full info about the tree root
1689
rich_root_data = True
1691
def get_format_string(self):
1692
"""See RepositoryFormat.get_format_string()."""
1693
return "Bazaar Knit Repository Format 2\n"
1695
def get_format_description(self):
1696
"""See RepositoryFormat.get_format_description()."""
1697
return "Knit repository format 2"
1699
def check_conversion_target(self, target_format):
1700
if not target_format.rich_root_data:
1701
raise errors.BadConversionTarget(
1702
'Does not support rich root data.', target_format)
1704
def open(self, a_bzrdir, _found=False, _override_transport=None):
1705
"""See RepositoryFormat.open().
1707
:param _override_transport: INTERNAL USE ONLY. Allows opening the
1708
repository at a slightly different url
1709
than normal. I.e. during 'upgrade'.
1712
format = RepositoryFormat.find_format(a_bzrdir)
1713
assert format.__class__ == self.__class__
1714
if _override_transport is not None:
1715
repo_transport = _override_transport
1717
repo_transport = a_bzrdir.get_repository_transport(None)
1718
control_files = lockable_files.LockableFiles(repo_transport, 'lock',
1720
text_store = self._get_text_store(repo_transport, control_files)
1721
control_store = self._get_control_store(repo_transport, control_files)
1722
_revision_store = self._get_revision_store(repo_transport, control_files)
1723
return KnitRepository2(_format=self,
1725
control_files=control_files,
1726
_revision_store=_revision_store,
1727
control_store=control_store,
1728
text_store=text_store)
1584
1732
# formats which have no format string are not discoverable
1585
1733
# and not independently creatable, so are not registered.
1586
1734
RepositoryFormat.register_format(RepositoryFormat7())
1587
1735
_default_format = RepositoryFormatKnit1()
1588
1736
RepositoryFormat.register_format(_default_format)
1737
RepositoryFormat.register_format(RepositoryFormatKnit2())
1589
1738
RepositoryFormat.set_default_format(_default_format)
1590
1739
_legacy_formats = [RepositoryFormat4(),
1591
1740
RepositoryFormat5(),
1604
1753
InterRepository.get(other).method_name(parameters).
1608
1757
"""The available optimised InterRepository types."""
1611
1759
def copy_content(self, revision_id=None, basis=None):
1612
"""Make a complete copy of the content in self into destination.
1614
This is a destructive operation! Do not use it on existing
1617
:param revision_id: Only copy the content needed to construct
1618
revision_id and its parents.
1619
:param basis: Copy the needed data preferentially from basis.
1622
self.target.set_make_working_trees(self.source.make_working_trees())
1623
except NotImplementedError:
1625
# grab the basis available data
1626
if basis is not None:
1627
self.target.fetch(basis, revision_id=revision_id)
1628
# but don't bother fetching if we have the needed data now.
1629
if (revision_id not in (None, _mod_revision.NULL_REVISION) and
1630
self.target.has_revision(revision_id)):
1632
self.target.fetch(self.source, revision_id=revision_id)
1760
raise NotImplementedError(self.copy_content)
1635
1762
def fetch(self, revision_id=None, pb=None):
1636
1763
"""Fetch the content required to construct revision_id.
1638
The content is copied from source to target.
1765
The content is copied from self.source to self.target.
1640
1767
:param revision_id: if None all content is copied, if NULL_REVISION no
1641
1768
content is copied.
1645
1772
Returns the copied revision count and the failed revisions in a tuple:
1646
1773
(copied, failures).
1648
from bzrlib.fetch import GenericRepoFetcher
1649
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1650
self.source, self.source._format, self.target, self.target._format)
1651
f = GenericRepoFetcher(to_repository=self.target,
1652
from_repository=self.source,
1653
last_revision=revision_id,
1655
return f.count_copied, f.failed_revisions
1775
raise NotImplementedError(self.fetch)
1657
1777
@needs_read_lock
1658
1778
def missing_revision_ids(self, revision_id=None):
1659
1779
"""Return the revision ids that source has that target does not.
1678
1798
return [rev_id for rev_id in source_ids if rev_id in result_set]
1681
class InterWeaveRepo(InterRepository):
1801
class InterSameDataRepository(InterRepository):
1802
"""Code for converting between repositories that represent the same data.
1804
Data format and model must match for this to work.
1807
_matching_repo_format = RepositoryFormat4()
1808
"""Repository format for testing with."""
1811
def is_compatible(source, target):
1812
if not isinstance(source, Repository):
1814
if not isinstance(target, Repository):
1816
if source._format.rich_root_data == target._format.rich_root_data:
1822
def copy_content(self, revision_id=None, basis=None):
1823
"""Make a complete copy of the content in self into destination.
1825
This is a destructive operation! Do not use it on existing
1828
:param revision_id: Only copy the content needed to construct
1829
revision_id and its parents.
1830
:param basis: Copy the needed data preferentially from basis.
1833
self.target.set_make_working_trees(self.source.make_working_trees())
1834
except NotImplementedError:
1836
# grab the basis available data
1837
if basis is not None:
1838
self.target.fetch(basis, revision_id=revision_id)
1839
# but don't bother fetching if we have the needed data now.
1840
if (revision_id not in (None, _mod_revision.NULL_REVISION) and
1841
self.target.has_revision(revision_id)):
1843
self.target.fetch(self.source, revision_id=revision_id)
1846
def fetch(self, revision_id=None, pb=None):
1847
"""See InterRepository.fetch()."""
1848
from bzrlib.fetch import GenericRepoFetcher
1849
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1850
self.source, self.source._format, self.target,
1851
self.target._format)
1852
f = GenericRepoFetcher(to_repository=self.target,
1853
from_repository=self.source,
1854
last_revision=revision_id,
1856
return f.count_copied, f.failed_revisions
1859
class InterWeaveRepo(InterSameDataRepository):
1682
1860
"""Optimised code paths between Weave based repositories."""
1684
1862
_matching_repo_format = RepositoryFormat7()
1858
2036
# that against the revision records.
1859
2037
return self.source._eliminate_revisions_not_present(required_topo_revisions)
2040
class InterModel1and2(InterRepository):
2042
_matching_repo_format = None
2045
def is_compatible(source, target):
2046
if not isinstance(source, Repository):
2048
if not isinstance(target, Repository):
2050
if not source._format.rich_root_data and target._format.rich_root_data:
2056
def fetch(self, revision_id=None, pb=None):
2057
"""See InterRepository.fetch()."""
2058
from bzrlib.fetch import Model1toKnit2Fetcher
2059
f = Model1toKnit2Fetcher(to_repository=self.target,
2060
from_repository=self.source,
2061
last_revision=revision_id,
2063
return f.count_copied, f.failed_revisions
2066
def copy_content(self, revision_id=None, basis=None):
2067
"""Make a complete copy of the content in self into destination.
2069
This is a destructive operation! Do not use it on existing
2072
:param revision_id: Only copy the content needed to construct
2073
revision_id and its parents.
2074
:param basis: Copy the needed data preferentially from basis.
2077
self.target.set_make_working_trees(self.source.make_working_trees())
2078
except NotImplementedError:
2080
# grab the basis available data
2081
if basis is not None:
2082
self.target.fetch(basis, revision_id=revision_id)
2083
# but don't bother fetching if we have the needed data now.
2084
if (revision_id not in (None, _mod_revision.NULL_REVISION) and
2085
self.target.has_revision(revision_id)):
2087
self.target.fetch(self.source, revision_id=revision_id)
2090
class InterKnit1and2(InterKnitRepo):
2092
_matching_repo_format = None
2095
def is_compatible(source, target):
2096
"""Be compatible with Knit1 source and Knit2 target"""
2098
return (isinstance(source._format, (RepositoryFormatKnit1)) and
2099
isinstance(target._format, (RepositoryFormatKnit2)))
2100
except AttributeError:
2104
def fetch(self, revision_id=None, pb=None):
2105
"""See InterRepository.fetch()."""
2106
from bzrlib.fetch import Knit1to2Fetcher
2107
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
2108
self.source, self.source._format, self.target,
2109
self.target._format)
2110
f = Knit1to2Fetcher(to_repository=self.target,
2111
from_repository=self.source,
2112
last_revision=revision_id,
2114
return f.count_copied, f.failed_revisions
2117
InterRepository.register_optimiser(InterSameDataRepository)
1861
2118
InterRepository.register_optimiser(InterWeaveRepo)
1862
2119
InterRepository.register_optimiser(InterKnitRepo)
2120
InterRepository.register_optimiser(InterModel1and2)
2121
InterRepository.register_optimiser(InterKnit1and2)
1865
2124
class RepositoryTestProviderAdapter(object):
1930
2189
# default format.
1931
2190
# XXX: robertc 20060220 reinstate this when there are two supported
1932
2191
# formats which do not have an optimal code path between them.
1933
result.append((InterRepository,
1934
RepositoryFormat6(),
1935
RepositoryFormatKnit1()))
2192
#result.append((InterRepository,
2193
# RepositoryFormat6(),
2194
# RepositoryFormatKnit1()))
1936
2195
for optimiser in InterRepository._optimisers:
1937
result.append((optimiser,
1938
optimiser._matching_repo_format,
1939
optimiser._matching_repo_format
2196
if optimiser._matching_repo_format is not None:
2197
result.append((optimiser,
2198
optimiser._matching_repo_format,
2199
optimiser._matching_repo_format
1941
2201
# if there are specific combinations we want to use, we can add them
2203
result.append((InterModel1and2, RepositoryFormat5(),
2204
RepositoryFormatKnit2()))
2205
result.append((InterKnit1and2, RepositoryFormatKnit1(),
2206
RepositoryFormatKnit2()))
2063
2328
self.new_inventory, self._config)
2064
2329
return self._new_revision_id
2331
def revision_tree(self):
2332
"""Return the tree that was just committed.
2334
After calling commit() this can be called to get a RevisionTree
2335
representing the newly committed tree. This is preferred to
2336
calling Repository.revision_tree() because that may require
2337
deserializing the inventory, while we already have a copy in
2340
return RevisionTree(self.repository, self.new_inventory,
2341
self._new_revision_id)
2066
2343
def finish_inventory(self):
2067
2344
"""Tell the builder that the inventory is finished."""
2068
2345
if self.new_inventory.root is None:
2203
2479
record_root_entry = True
2482
class RootCommitBuilder(CommitBuilder):
2483
"""This commitbuilder actually records the root id"""
2485
record_root_entry = True
2487
def record_entry_contents(self, ie, parent_invs, path, tree):
2488
"""Record the content of ie from tree into the commit if needed.
2490
Side effect: sets ie.revision when unchanged
2492
:param ie: An inventory entry present in the commit.
2493
:param parent_invs: The inventories of the parent revisions of the
2495
:param path: The path the entry is at in the tree.
2496
:param tree: The tree which contains this entry and should be used to
2499
assert self.new_inventory.root is not None or ie.parent_id is None
2500
self.new_inventory.add(ie)
2502
# ie.revision is always None if the InventoryEntry is considered
2503
# for committing. ie.snapshot will record the correct revision
2504
# which may be the sole parent if it is untouched.
2505
if ie.revision is not None:
2508
previous_entries = ie.find_previous_heads(
2510
self.repository.weave_store,
2511
self.repository.get_transaction())
2512
# we are creating a new revision for ie in the history store
2514
ie.snapshot(self._new_revision_id, path, previous_entries, tree, self)
2206
2517
_unescape_map = {