changeset 960:502613f6b583

editor: ignore added or copied files excluded by a filemap Files brought by a copied add_directory() were processed despite being excluded by the filemap. This was also the case with added files. The conversion was still correct because they were eventually filtered out in the replay.convert_rev() but processing them in itself may be problematic. Filemaps are often use to exclude large binary files and before this change, some of them could be marked as missing and be fetched before being discarded. A test configuration entry named hgsubversion.failoninvalidreplayfile was added to help testing this case. It should become the default behaviour in the future.
author Patrick Mezard <patrick@mezard.eu>
date Sun, 14 Oct 2012 15:51:12 +0200
parents 8b2480175bae
children b729909d3793
files hgsubversion/editor.py hgsubversion/replay.py tests/fixtures/copies.sh tests/fixtures/copies.svndump tests/test_fetch_mappings.py
diffstat 5 files changed, 145 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/editor.py
+++ b/hgsubversion/editor.py
@@ -312,10 +312,9 @@ class HgEditor(svnwrap.Editor):
     @svnwrap.ieditor
     def open_file(self, path, parent_baton, base_revision, p=None):
         self._checkparentdir(parent_baton)
-        fpath, branch = self.meta.split_branch_path(path)[:2]
-        if not fpath:
-            self.ui.debug('WARNING: Opening non-existant file %s\n' % path)
+        if not self.meta.is_path_valid(path):
             return None
+        fpath, branch = self.meta.split_branch_path(path)[:2]
 
         self.ui.note('M %s\n' % path)
 
@@ -324,9 +323,6 @@ class HgEditor(svnwrap.Editor):
             base, isexec, islink, copypath = copy.resolve(self._getctx)
             return self._openfile(path, base, isexec, islink, copypath)
 
-        if not self.meta.is_path_valid(path):
-            return None
-
         baserev = base_revision
         if baserev is None or baserev == -1:
             baserev = self.current.rev.revnum - 1
@@ -350,16 +346,20 @@ class HgEditor(svnwrap.Editor):
     def add_file(self, path, parent_baton=None, copyfrom_path=None,
                  copyfrom_revision=None, file_pool=None):
         self._checkparentdir(parent_baton)
+        # Use existing=False because we use the fact a file is being
+        # added here to populate the branchmap which is used with
+        # existing=True.
+        fpath, branch = self.meta.split_branch_path(path, existing=False)[:2]
+        if not fpath or fpath not in self.meta.filemap:
+            return None
         if path in self._svncopies:
             raise EditingError('trying to replace copied file %s' % path)
         if path in self._deleted:
             self._deleted.remove(path)
-        fpath, branch = self.meta.split_branch_path(path, existing=False)[:2]
-        if not fpath:
-            return None
         if (branch not in self.meta.branches and
             not self.meta.get_path_tag(self.meta.remotename(branch))):
-            # we know this branch will exist now, because it has at least one file. Rock.
+            # we know this branch will exist now, because it has at
+            # least one file. Rock.
             self.meta.branches[branch] = None, 0, self.current.rev.revnum
         if not copyfrom_path:
             self.ui.note('A %s\n' % path)
@@ -478,6 +478,8 @@ class HgEditor(svnwrap.Editor):
             if not f.startswith(frompath):
                 continue
             dest = path + '/' + f[len(frompath):]
+            if not self.meta.is_path_valid(dest):
+                continue
             if dest in self._deleted:
                 self._deleted.remove(dest)
             if copyfromparent:
--- a/hgsubversion/replay.py
+++ b/hgsubversion/replay.py
@@ -99,8 +99,12 @@ def _convert_rev(ui, meta, svn, r, tbdel
     date = meta.fixdate(rev.date)
 
     # build up the branches that have files on them
+    failoninvalid = ui.configbool('hgsubversion',
+            'failoninvalidreplayfile', False)
     for f in files_to_commit:
         if not meta.is_path_valid(f):
+            if failoninvalid:
+                raise hgutil.Abort('file %s should not be in commit list' % f)
             continue
         p, b = meta.split_branch_path(f)[:2]
         if b not in branch_batches:
new file mode 100755
--- /dev/null
+++ b/tests/fixtures/copies.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Generate copies.svndump
+#
+
+rm -rf temp
+mkdir temp
+cd temp
+mkdir -p import/trunk/dir
+echo a > import/trunk/dir/a
+
+svnadmin create testrepo
+svnurl=file://`pwd`/testrepo
+svn import import $svnurl -m init
+
+svn co $svnurl project
+cd project
+svn cp trunk/dir trunk/dir2
+echo b >> trunk/dir2/a
+svn ci -m 'copy/edit trunk/dir/a'
+cd ..
+
+svnadmin dump testrepo > ../copies.svndump
new file mode 100644
--- /dev/null
+++ b/tests/fixtures/copies.svndump
@@ -0,0 +1,100 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 707bea87-43e4-45d9-8f28-5d06ca9e3f3b
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2012-10-14T12:41:39.387675Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-14T12:41:39.409053Z
+K 7
+svn:log
+V 4
+init
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Revision-number: 2
+Prop-content-length: 123
+Content-length: 123
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-14T12:41:41.048526Z
+K 7
+svn:log
+V 21
+copy/edit trunk/dir/a
+PROPS-END
+
+Node-path: trunk/dir2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk/dir
+
+
+Node-path: trunk/dir2/a
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: dd8c6a395b5dd36c56d23275028f526c
+Text-content-sha1: 05dec960e24d918b8a73a1c53bcbbaac2ee5c2e0
+Content-length: 4
+
+a
+b
+
+
--- a/tests/test_fetch_mappings.py
+++ b/tests/test_fetch_mappings.py
@@ -108,6 +108,8 @@ class MapTests(test_util.TestBase):
         filemap.close()
         ui = self.ui(stupid)
         ui.setconfig('hgsubversion', 'filemap', self.filemap)
+        ui.setconfig('hgsubversion', 'failoninvalidreplayfile', 'true')
+        ui.setconfig('hgsubversion', 'failonmissing', 'true')
         commands.clone(ui, test_util.fileurl(repo_path),
                        self.wc_path, filemap=self.filemap)
         return self.repo
@@ -143,6 +145,10 @@ class MapTests(test_util.TestBase):
         self.assertEqual(self.repo['default'].manifest().keys(),
                          ['alpha', 'beta'])
 
+    def test_file_map_copy(self):
+        repo = self._loadwithfilemap('copies.svndump', "exclude dir2\n")
+        self.assertEqual(['dir/a'], list(repo['tip']))
+
     def test_branchmap(self, stupid=False):
         repo_path = self.load_svndump('branchmap.svndump')
         branchmap = open(self.branchmap, 'w')