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