109
104
# the default CommitBuilder does not manage trees whose root is versioned.
110
105
_versioned_root = False
112
def __init__(self, repository, parents, config_stack, timestamp=None,
107
def __init__(self, repository, parents, config, timestamp=None,
113
108
timezone=None, committer=None, revprops=None,
114
109
revision_id=None, lossy=False):
115
110
super(VersionedFileCommitBuilder, self).__init__(repository,
116
parents, config_stack, timestamp, timezone, committer, revprops,
111
parents, config, timestamp, timezone, committer, revprops,
117
112
revision_id, lossy)
119
114
basis_id = self.parents[0]
200
195
revision_id=self._new_revision_id,
201
196
properties=self._revprops)
202
197
rev.parent_ids = self.parents
203
if self._config_stack.get('create_signatures') == _mod_config.SIGN_ALWAYS:
204
testament = Testament(rev, self.revision_tree())
205
plaintext = testament.as_short_text()
206
self.repository.store_revision_signature(
207
gpg.GPGStrategy(self._config_stack), plaintext,
208
self._new_revision_id)
209
self.repository._add_revision(rev)
198
self.repository.add_revision(self._new_revision_id, rev,
199
self.new_inventory, self._config)
210
200
self._ensure_fallback_inventories()
211
201
self.repository.commit_write_group()
212
202
return self._new_revision_id
1038
1028
self.inventories._access.flush()
1041
def add_revision(self, revision_id, rev, inv=None):
1031
def add_revision(self, revision_id, rev, inv=None, config=None):
1042
1032
"""Add rev to the revision store as revision_id.
1044
1034
:param revision_id: the revision id to use.
1045
1035
:param rev: The revision object.
1046
1036
:param inv: The inventory for the revision. if None, it will be looked
1047
1037
up in the inventory storer
1038
:param config: If None no digital signature will be created.
1039
If supplied its signature_needed method will be used
1040
to determine if a signature should be made.
1049
1042
# TODO: jam 20070210 Shouldn't we check rev.revision_id and
1050
1043
# rev.parent_ids?
1051
1044
_mod_revision.check_not_reserved_id(revision_id)
1045
if config is not None and config.signature_needed():
1047
inv = self.get_inventory(revision_id)
1048
tree = InventoryRevisionTree(self, inv, revision_id)
1049
testament = Testament(rev, tree)
1050
plaintext = testament.as_short_text()
1051
self.store_revision_signature(
1052
gpg.GPGStrategy(config), plaintext, revision_id)
1052
1053
# check inventory present
1053
1054
if not self.inventories.get_parent_map([(revision_id,)]):
1054
1055
if inv is None:
1218
1219
# rather copying them?
1219
1220
self._safe_to_return_from_cache = False
1221
def fetch(self, source, revision_id=None, find_ghosts=False,
1223
"""Fetch the content required to construct revision_id from source.
1225
If revision_id is None and fetch_spec is None, then all content is
1228
fetch() may not be used when the repository is in a write group -
1229
either finish the current write group before using fetch, or use
1230
fetch before starting the write group.
1232
:param find_ghosts: Find and copy revisions in the source that are
1233
ghosts in the target (and not reachable directly by walking out to
1234
the first-present revision in target from revision_id).
1235
:param revision_id: If specified, all the content needed for this
1236
revision ID will be copied to the target. Fetch will determine for
1237
itself which content needs to be copied.
1238
:param fetch_spec: If specified, a SearchResult or
1239
PendingAncestryResult that describes which revisions to copy. This
1240
allows copying multiple heads at once. Mutually exclusive with
1243
if fetch_spec is not None and revision_id is not None:
1244
raise AssertionError(
1245
"fetch_spec and revision_id are mutually exclusive.")
1246
if self.is_in_write_group():
1247
raise errors.InternalBzrError(
1248
"May not fetch while in a write group.")
1249
# fast path same-url fetch operations
1250
# TODO: lift out to somewhere common with RemoteRepository
1251
# <https://bugs.launchpad.net/bzr/+bug/401646>
1252
if (self.has_same_location(source)
1253
and fetch_spec is None
1254
and self._has_same_fallbacks(source)):
1255
# check that last_revision is in 'from' and then return a
1257
if (revision_id is not None and
1258
not _mod_revision.is_null(revision_id)):
1259
self.get_revision(revision_id)
1261
inter = InterRepository.get(source, self)
1262
if (fetch_spec is not None and
1263
not getattr(inter, "supports_fetch_spec", False)):
1264
raise errors.UnsupportedOperation(
1265
"fetch_spec not supported for %r" % inter)
1266
return inter.fetch(revision_id=revision_id,
1267
find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1269
1222
@needs_read_lock
1270
1223
def gather_stats(self, revid=None, committers=None):
1271
1224
"""See Repository.gather_stats()."""
1280
1233
# result['size'] = t
1283
def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
1236
def get_commit_builder(self, branch, parents, config, timestamp=None,
1284
1237
timezone=None, committer=None, revprops=None,
1285
1238
revision_id=None, lossy=False):
1286
1239
"""Obtain a CommitBuilder for this repository.
1288
1241
:param branch: Branch to commit to.
1289
1242
:param parents: Revision ids of the parents of the new revision.
1290
:param config_stack: Configuration stack to use.
1243
:param config: Configuration to use.
1291
1244
:param timestamp: Optional timestamp recorded for commit.
1292
1245
:param timezone: Optional timezone for timestamp.
1293
1246
:param committer: Optional committer to set for commit.
1300
1253
raise errors.BzrError("Cannot commit directly to a stacked branch"
1301
1254
" in pre-2a formats. See "
1302
1255
"https://bugs.launchpad.net/bzr/+bug/375013 for details.")
1303
result = self._commit_builder_class(self, parents, config_stack,
1256
result = self._commit_builder_class(self, parents, config,
1304
1257
timestamp, timezone, committer, revprops, revision_id,
1306
1259
self.start_write_group()
1562
1515
text_keys[(file_id, revision_id)] = callable_data
1563
1516
for record in self.texts.get_record_stream(text_keys, 'unordered', True):
1564
1517
if record.storage_kind == 'absent':
1565
raise errors.RevisionNotPresent(record.key[1], record.key[0])
1518
raise errors.RevisionNotPresent(record.key, self)
1566
1519
yield text_keys[record.key], record.get_bytes_as('chunked')
1568
1521
def _generate_text_key_index(self, text_key_references=None,
1746
1699
if ((None in revision_ids)
1747
1700
or (_mod_revision.NULL_REVISION in revision_ids)):
1748
1701
raise ValueError('cannot get null revision inventory')
1749
for inv, revid in self._iter_inventories(revision_ids, ordering):
1751
raise errors.NoSuchRevision(self, revid)
1702
return self._iter_inventories(revision_ids, ordering)
1754
1704
def _iter_inventories(self, revision_ids, ordering):
1755
1705
"""single-document based inventory iteration."""
1756
1706
inv_xmls = self._iter_inventory_xmls(revision_ids, ordering)
1757
1707
for text, revision_id in inv_xmls:
1759
yield None, revision_id
1761
yield self._deserialise_inventory(revision_id, text), revision_id
1708
yield self._deserialise_inventory(revision_id, text)
1763
1710
def _iter_inventory_xmls(self, revision_ids, ordering):
1764
1711
if ordering is None:
1783
1730
yield ''.join(chunks), record.key[-1]
1785
yield None, record.key[-1]
1732
raise errors.NoSuchRevision(self, record.key)
1786
1733
if order_as_requested:
1787
1734
# Yield as many results as we can while preserving order.
1788
1735
while next_key in text_chunks:
1817
1764
def _get_inventory_xml(self, revision_id):
1818
1765
"""Get serialized inventory as a string."""
1819
1766
texts = self._iter_inventory_xmls([revision_id], 'unordered')
1820
text, revision_id = texts.next()
1822
raise errors.NoSuchRevision(self, revision_id)
1768
text, revision_id = texts.next()
1769
except StopIteration:
1770
raise errors.HistoryMissing(self, 'inventory', revision_id)
1825
1773
@needs_read_lock
1900
1848
"""Return the graph walker for text revisions."""
1901
1849
return graph.Graph(self.texts)
1903
def revision_ids_to_search_result(self, result_set):
1904
"""Convert a set of revision ids to a graph SearchResult."""
1905
result_parents = set()
1906
for parents in self.get_graph().get_parent_map(
1907
result_set).itervalues():
1908
result_parents.update(parents)
1909
included_keys = result_set.intersection(result_parents)
1910
start_keys = result_set.difference(included_keys)
1911
exclude_keys = result_parents.difference(result_set)
1912
result = vf_search.SearchResult(start_keys, exclude_keys,
1913
len(result_set), result_set)
1916
1851
def _get_versioned_file_checker(self, text_key_references=None,
1917
1852
ancestors=None):
1918
1853
"""Return an object suitable for checking versioned files.
2637
2570
searcher.stop_searching_any(stop_revs)
2638
2571
if searcher_exhausted:
2640
(started_keys, excludes, included_keys) = searcher.get_state()
2641
return vf_search.SearchResult(started_keys, excludes,
2642
len(included_keys), included_keys)
2573
return searcher.get_result()
2644
2575
@needs_read_lock
2645
2576
def search_missing_revision_ids(self,