Rev 1739: initial work handling knit corruption because of incorrect text parents. in http://people.samba.org/bzr/jelmer/bzr-svn/trunk
Jelmer Vernooij
jelmer at samba.org
Sat Nov 8 20:02:05 GMT 2008
At http://people.samba.org/bzr/jelmer/bzr-svn/trunk
------------------------------------------------------------
revno: 1739
revision-id: jelmer at samba.org-20081108200202-kplsv702oazebfu9
parent: jelmer at samba.org-20081108181139-rirv83qgy4wyu6nd
committer: Jelmer Vernooij <jelmer at samba.org>
branch nick: 0.4
timestamp: Sat 2008-11-08 21:02:02 +0100
message:
initial work handling knit corruption because of incorrect text parents.
modified:
commit.py commit.py-20060607190346-qvq128wgfubhhgm2-1
fetch.py fetch.py-20060625004942-x2lfaib8ra707a8p-1
fileids.py fileids.py-20060714013623-u5iiyqqnko11grcf-1
mapping.py mapping.py-20080128201303-6cp01phc0dmc0kiv-1
mapping3/__init__.py __init__.py-20080502174630-9324zh25kka98vlw-1
=== modified file 'commit.py'
--- a/commit.py 2008-11-08 17:53:15 +0000
+++ b/commit.py 2008-11-08 20:02:02 +0000
@@ -38,6 +38,7 @@
from bzrlib.plugins.svn.mapping import parse_revision_id
from bzrlib.plugins.svn.repository import SvnRepositoryFormat, SvnRepository
from bzrlib.plugins.svn.transport import _url_escape_uri
+from bzrlib.plugins.svn.versionedfiles import SvnTexts
def _revision_id_to_svk_feature(revid):
@@ -131,7 +132,7 @@
def __init__(self, repository, branch, parents, config, timestamp,
timezone, committer, revprops, revision_id, old_inv=None,
push_metadata=True,
- graph=None):
+ graph=None, texts=None):
"""Instantiate a new SvnCommitBuilder.
:param repository: SvnRepository to commit to.
@@ -152,6 +153,8 @@
config, timestamp, timezone, committer, revprops, revision_id)
self.branch = branch
self.push_metadata = push_metadata
+ self._text_parents = {}
+ self._texts = texts
# Gather information about revision on top of which the commit is
# happening
@@ -433,30 +436,32 @@
old_inv.id2path(child_ie.file_id) != new_child_path or
old_inv[child_ie.file_id].revision != child_ie.revision or
old_inv[child_ie.file_id].parent_id != child_ie.parent_id):
- ret.append((child_ie.file_id, new_child_path, child_ie.revision))
+ ret.append((child_ie.file_id, new_child_path, child_ie.revision, self._text_parents[child_ie.file_id]))
if (child_ie.kind == 'directory' and
child_ie.file_id in self.visit_dirs):
ret += _dir_process_file_id(old_inv, new_inv, new_child_path, child_ie.file_id)
return ret
-
fileids = {}
text_parents = {}
-
+ text_revisions = {}
changes = []
if (self.old_inv.root is None or
self.new_inventory.root.file_id != self.old_inv.root.file_id):
- changes.append((self.new_inventory.root.file_id, "", self.new_inventory.root.revision))
+ changes.append((self.new_inventory.root.file_id, "", self.new_inventory.root.revision, self._text_parents[self.new_inventory.root.file_id]))
changes += _dir_process_file_id(self.old_inv, self.new_inventory, "", self.new_inventory.root.file_id)
- for id, path, revid in changes:
+ for id, path, revid, parents in changes:
fileids[path] = id
if revid is not None and revid != self.base_revid and revid != self._new_revision_id:
- text_parents[path] = revid
- return (fileids, text_parents)
+ text_revisions[path] = revid
+ if ((id not in self.old_inv and parents != []) or
+ (id in self.old_inv and parents != [self.base_revid])):
+ text_parents[path] = parents
+ return (fileids, text_revisions, text_parents)
def commit(self, message):
"""Finish the commit.
@@ -476,8 +481,9 @@
repository_latest_revnum = self.repository.get_latest_revnum()
lock = self.repository.transport.lock_write(".")
- (fileids, text_parents) = self._determine_texts_identity()
+ (fileids, text_revisions, text_parents) = self._determine_texts_identity()
+ self.base_mapping.export_text_revisions(self.supports_custom_revprops, text_revisions, self._svn_revprops, self._svnprops)
self.base_mapping.export_text_parents(self.supports_custom_revprops, text_parents,
self._svn_revprops, self._svnprops)
self.base_mapping.export_fileid_map(self.supports_custom_revprops, fileids,
@@ -589,6 +595,27 @@
accessed when the entry has a revision of None - that is when
it is a candidate to commit.
"""
+ if self._texts is None:
+ self._text_parents[ie.file_id] = [parent_inv[ie.file_id].revision for parent_inv in parent_invs if ie.file_id in parent_inv]
+ elif isinstance(self._texts, SvnTexts):
+ overridden_parents = self._texts._get_parent(ie.file_id, ie.revision)
+ if overridden_parents is None:
+ if ie.file_id in self.old_inv:
+ self._text_parents[ie.file_id] = [self.old_inv[ie.file_id].revision]
+ else:
+ self._text_parents[ie.file_id] = []
+ else:
+ self._text_parents[ie.file_id] = overridden_parents
+ else:
+ key = (ie.file_id, ie.revision)
+ parent_map = self._texts.get_parent_map([key])
+ if ie.parent_id is None and (not key in parent_map or parent_map[key] is None):
+ # non-rich-root repositories don't have a text for the root
+ self._text_parents[ie.file_id] = self.parents
+ else:
+ assert parent_map[key] is not None, "No parents found for %r" % (key,)
+ self._text_parents[ie.file_id] = [r[1] for r in parent_map[key]]
+
self.new_inventory.add(ie)
assert (ie.file_id not in self.old_inv or
self.old_inv[ie.file_id].revision is not None)
@@ -745,7 +772,8 @@
rev.timezone, rev.committer, rev.properties,
revision_id, base_tree.inventory,
push_metadata=push_metadata,
- graph=graph)
+ graph=graph,
+ texts=source_repo.texts)
replay_delta(builder, base_tree, old_tree)
try:
=== modified file 'fetch.py'
--- a/fetch.py 2008-11-03 02:12:28 +0000
+++ b/fetch.py 2008-11-08 20:02:02 +0000
@@ -227,9 +227,13 @@
assert self.editor.revid is not None
ie.revision = self.editor.revid
+ text_revision = self.editor._get_text_revid(self.path) or ie.revision
+ text_parents = self.editor._get_text_parents(self.path)
+ if text_parents is None:
+ text_parents = self.parent_revids
self.editor.texts.add_lines(
- (self.new_id, self.editor._get_text_revid(self.path) or ie.revision),
- [(self.new_id, revid) for revid in self.parent_revids], [])
+ (self.new_id, text_revision),
+ [(self.new_id, revid) for revid in text_parents], [])
if self.new_id == self.editor.inventory.root.file_id:
assert self.editor.inventory.root.revision is not None
@@ -340,8 +344,12 @@
actual_checksum = md5_strings(lines)
assert checksum is None or checksum == actual_checksum
- self.editor.texts.add_lines((self.file_id, self.editor._get_text_revid(self.path) or self.editor.revid),
- [(self.file_id, revid) for revid in self.file_parents], lines)
+ text_revision = self.editor._get_text_revid(self.path) or self.editor.revid
+ text_parents = self.editor._get_text_parents(self.path)
+ if text_parents is None:
+ text_parents = self.file_parents
+ self.editor.texts.add_lines((self.file_id, text_revision),
+ [(self.file_id, revid) for revid in text_parents], lines)
if self.is_special is not None:
self.is_symlink = (self.is_special and len(lines) > 0 and lines[0].startswith("link "))
@@ -382,6 +390,7 @@
self.texts = target.texts
self.revid = revid
self._text_revids = None
+ self._text_parents = None
self._premature_deletes = set()
mapping = self.source.lookup_revision_id(revid)[2]
self.old_inventory = prev_inventory
@@ -489,10 +498,15 @@
def _get_text_revid(self, path):
if self._text_revids is None:
- self._text_revids = self.mapping.import_text_parents(self.revmeta.revprops,
+ self._text_revids = self.mapping.import_text_revisions(self.revmeta.revprops,
self.revmeta.fileprops)
return self._text_revids.get(path)
+ def _get_text_parents(self, path):
+ if self._text_parents is None:
+ self._text_parents = self.mapping.import_text_parents(self.revmeta.revprops,
+ self.revmeta.fileprops)
+ return self._text_parents.get(path)
class FileTreeDeltaBuildEditor(FileBuildEditor):
=== modified file 'fileids.py'
--- a/fileids.py 2008-08-23 14:55:24 +0000
+++ b/fileids.py 2008-11-08 20:02:02 +0000
@@ -108,7 +108,7 @@
self.repos = repos
def _use_text_revids(self, mapping, revmeta, map):
- text_revids = mapping.import_text_parents(revmeta.revprops, revmeta.fileprops).items()
+ text_revids = mapping.import_text_revisions(revmeta.revprops, revmeta.fileprops).items()
for path, revid in text_revids:
assert path in map
map[path] = (map[path][0], revid)
=== modified file 'mapping.py'
--- a/mapping.py 2008-08-25 00:05:15 +0000
+++ b/mapping.py 2008-11-08 20:02:02 +0000
@@ -32,6 +32,7 @@
SVN_PROP_BZR_MERGE = 'bzr:merge'
SVN_PROP_BZR_REVISION_INFO = 'bzr:revision-info'
SVN_PROP_BZR_REVISION_ID = 'bzr:revision-id:v%d-' % MAPPING_VERSION
+SVN_PROP_BZR_TEXT_REVISIONS = 'bzr:text-revisions'
SVN_PROP_BZR_TEXT_PARENTS = 'bzr:text-parents'
SVN_PROP_BZR_LOG = 'bzr:log'
@@ -46,6 +47,7 @@
SVN_REVPROP_BZR_SIGNATURE = 'bzr:gpg-signature'
SVN_REVPROP_BZR_TIMESTAMP = 'bzr:timestamp'
SVN_REVPROP_BZR_LOG = 'bzr:log'
+SVN_REVPROP_BZR_TEXT_REVISIONS = 'bzr:text-revisions'
SVN_REVPROP_BZR_TEXT_PARENTS = 'bzr:text-parents'
@@ -384,6 +386,15 @@
"""
raise NotImplementedError(self.export_text_parents)
+ def export_text_revisions(self, can_use_custom_revprops, text_revisions, revprops, fileprops):
+ """Store a text revisions map.
+
+ :param text_parents: Text revision map
+ :param revprops: Revision properties
+ :param fileprops: File properties
+ """
+ raise NotImplementedError(self.export_text_revisions)
+
def export_revision(self, can_use_custom_revprops, branch_root, timestamp, timezone, committer, revprops, revision_id, revno, merges, fileprops):
"""Determines the revision properties and branch root file
properties.
@@ -472,10 +483,22 @@
return ret
+def parse_text_revisions_property(text):
+ ret = {}
+ for line in text.splitlines():
+ (entry, revid) = line.split("\t", 1)
+ ret[urllib.unquote(entry)] = osutils.safe_revision_id(revid)
+ return ret
+
+
def generate_text_parents_property(text_parents):
return "".join(["%s\t%s\n" % (urllib.quote(path.encode("utf-8")), text_parents[path]) for path in sorted(text_parents.keys())])
+def generate_text_revisions_property(text_revisions):
+ return "".join(["%s\t%s\n" % (urllib.quote(path.encode("utf-8")), text_revisions[path]) for path in sorted(text_revisions.keys())])
+
+
class BzrSvnMappingFileProps(object):
@classmethod
def supports_custom_fileprops(cls):
@@ -496,12 +519,24 @@
return {}
return parse_text_parents_property(metadata)
+ def import_text_revisions(self, svn_revprops, fileprops):
+ metadata = fileprops.get(SVN_PROP_BZR_TEXT_REVISIONS)
+ if metadata is None:
+ return {}
+ return parse_text_revisions_property(metadata)
+
def export_text_parents(self, can_use_custom_revprops, text_parents, svn_revprops, fileprops):
if text_parents != {}:
fileprops[SVN_PROP_BZR_TEXT_PARENTS] = generate_text_parents_property(text_parents)
else:
fileprops[SVN_PROP_BZR_TEXT_PARENTS] = ""
+ def export_text_revisions(self, can_use_custom_revprops, text_revisions, svn_revprops, fileprops):
+ if text_revisions != {}:
+ fileprops[SVN_PROP_BZR_TEXT_REVISIONS] = generate_text_revisions_property(text_revisions)
+ else:
+ fileprops[SVN_PROP_BZR_TEXT_REVISIONS] = ""
+
def get_rhs_parents(self, branch_path, revprops, fileprops):
bzr_merges = fileprops.get(SVN_PROP_BZR_ANCESTRY+str(self.scheme), None)
if bzr_merges is not None:
@@ -600,9 +635,17 @@
return {}
return parse_text_parents_property(svn_revprops[SVN_REVPROP_BZR_TEXT_PARENTS])
+ def import_text_revisions(self, svn_revprops, fileprops):
+ if not svn_revprops.has_key(SVN_REVPROP_BZR_TEXT_REVISIONS):
+ return {}
+ return parse_text_revisions_property(svn_revprops[SVN_REVPROP_BZR_TEXT_REVISIONS])
+
def export_text_parents(self, can_use_custom_revprops, text_parents, svn_revprops, fileprops):
svn_revprops[SVN_REVPROP_BZR_TEXT_PARENTS] = generate_text_parents_property(text_parents)
+ def export_text_revisions(self, can_use_custom_revprops, text_revisions, svn_revprops, fileprops):
+ svn_revprops[SVN_REVPROP_BZR_TEXT_REVISIONS] = generate_text_revisions_property(text_revisions)
+
def get_rhs_parents(self, branch_path, svn_revprops,
fileprops):
if svn_revprops[SVN_REVPROP_BZR_ROOT] != branch:
=== modified file 'mapping3/__init__.py'
--- a/mapping3/__init__.py 2008-11-03 02:12:28 +0000
+++ b/mapping3/__init__.py 2008-11-08 20:02:02 +0000
@@ -344,6 +344,11 @@
if can_use_custom_revprops:
self.revprop_map.export_text_parents(can_use_custom_revprops, text_parents, svn_revprops, fileprops)
+ def export_text_revisions(self, can_use_custom_revprops, text_revisions, svn_revprops, fileprops):
+ mapping.BzrSvnMappingFileProps.export_text_revisions(self, can_use_custom_revprops, text_revisions, svn_revprops, fileprops)
+ if can_use_custom_revprops:
+ self.revprop_map.export_text_revisions(can_use_custom_revprops, text_revisions, svn_revprops, fileprops)
+
def export_revision(self, can_use_custom_revprops, branch_root, timestamp, timezone, committer, revprops, revision_id, revno, merges, old_fileprops):
(svn_revprops, fileprops) = mapping.BzrSvnMappingFileProps.export_revision(self, can_use_custom_revprops, branch_root, timestamp, timezone, committer, revprops, revision_id, revno, merges, old_fileprops)
if can_use_custom_revprops:
@@ -393,6 +398,12 @@
else:
return self.fileprops.import_text_parents(svn_revprops, fileprops)
+ def import_text_revisions(self, svn_revprops, fileprops):
+ if svn_revprops.has_key(mapping.SVN_REVPROP_BZR_TEXT_REVISIONS):
+ return self.revprops.import_text_revisions(svn_revprops, fileprops)
+ else:
+ return self.fileprops.import_text_revisions(svn_revprops, fileprops)
+
def import_fileid_map(self, svn_revprops, fileprops):
if svn_revprops.has_key(mapping.SVN_REVPROP_BZR_MAPPING_VERSION):
return self.revprops.import_fileid_map(svn_revprops, fileprops)
@@ -415,6 +426,10 @@
self.fileprops.export_text_parents(can_use_custom_revprops, text_parents, revprops, fileprops)
self.revprops.export_text_parents(can_use_custom_revprops, text_parents, revprops, fileprops)
+ def export_text_revisions(self, can_use_custom_revprops, text_revisions, revprops, fileprops):
+ self.fileprops.export_text_revisions(can_use_custom_revprops, text_revisions, revprops, fileprops)
+ self.revprops.export_text_revisions(can_use_custom_revprops, text_revisions, revprops, fileprops)
+
def import_revision(self, svn_revprops, fileprops, uuid, branch, revnum, rev):
self.fileprops.import_revision(svn_revprops, fileprops, uuid, branch, revnum, rev)
self.revprops.import_revision(svn_revprops, fileprops, uuid, branch, revnum, rev)
More information about the bazaar-commits
mailing list