diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py --- a/hgext/convert/subversion.py +++ b/hgext/convert/subversion.py @@ -563,11 +563,15 @@ class svn_source(converter_source): reported. Return None if computed module does not belong to rootmodule subtree. """ - def findchanges(path, start, stop): - stream = self._getlog([path], start, stop) + def findchanges(path, start, stop=None): + stream = self._getlog([path], start, stop or 1) try: for entry in stream: paths, revnum, author, date, message = entry + if stop is None and paths: + # We do not know the latest changed revision, + # keep the first one with changed paths. + break if revnum <= stop: break @@ -580,6 +584,8 @@ class svn_source(converter_source): (path, newpath, revnum)) path = newpath break + if not paths: + revnum = None return revnum, path finally: stream.close() @@ -605,6 +611,19 @@ class svn_source(converter_source): # development, but it might be in *another module*. Fetch the # log and detect renames down to the latest revision. revnum, realpath = findchanges(path, stop, dirent.created_rev) + if revnum is None: + # Tools like svnsync can create empty revision, when + # synchronizing only a subtree for instance. These empty + # revisions created_rev still have their original values + # despite all changes having disappeared and can be + # returned by ra.stat(), at least when stating the root + # module. In that case, do not trust created_rev and scan + # the whole history. + revnum, realpath = findchanges(path, stop) + if revnum is None: + self.ui.debug('ignoring empty branch %r\n' % realpath) + return None + if not realpath.startswith(self.rootmodule): self.ui.debug('ignoring foreign branch %r\n' % realpath) return None diff --git a/tests/svn/empty.svndump b/tests/svn/empty.svndump new file mode 100644 --- /dev/null +++ b/tests/svn/empty.svndump @@ -0,0 +1,129 @@ +SVN-fs-dump-format-version: 2 + +UUID: b70c45d5-2b76-4722-a373-d9babae61626 + +Revision-number: 0 +Prop-content-length: 260 +Content-length: 260 + +K 8 +svn:date +V 27 +2012-04-18T11:35:14.752409Z +K 17 +svn:sync-from-url +V 73 +file:///Users/pmezard/dev/hg/hg-pmezard/tests/svn/temp/svn-repo/trunk/dir +K 18 +svn:sync-from-uuid +V 36 +56625b9e-e7e9-45be-ab61-052d41f0e1dd +K 24 +svn:sync-last-merged-rev +V 1 +4 +PROPS-END + +Revision-number: 1 +Prop-content-length: 112 +Content-length: 112 + +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2012-04-18T11:35:14.769622Z +K 7 +svn:log +V 10 +init projA +PROPS-END + +Node-path: trunk +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 2 +Prop-content-length: 107 +Content-length: 107 + +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2012-04-18T11:35:15.052989Z +K 7 +svn:log +V 6 +adddir +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: 3 +Prop-content-length: 105 +Content-length: 105 + +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2012-04-18T11:35:16.050353Z +K 7 +svn:log +V 4 +addb +PROPS-END + +Revision-number: 4 +Prop-content-length: 105 +Content-length: 105 + +K 10 +svn:author +V 7 +pmezard +K 8 +svn:date +V 27 +2012-04-18T11:35:17.050768Z +K 7 +svn:log +V 4 +addc +PROPS-END + diff --git a/tests/svn/svndump-empty.sh b/tests/svn/svndump-empty.sh new file mode 100755 --- /dev/null +++ b/tests/svn/svndump-empty.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# +# Use this script to generate empty.svndump +# + +mkdir temp +cd temp + +mkdir project-orig +cd project-orig +mkdir trunk +mkdir branches +mkdir tags +cd .. + +svnadmin create svn-repo +svnurl=file://`pwd`/svn-repo +svn import project-orig $svnurl -m "init projA" + +svn co $svnurl project +cd project +mkdir trunk/dir +echo a > trunk/dir/a +svn add trunk/dir +svn ci -m adddir + +echo b > trunk/b +svn add trunk/b +svn ci -m addb + +echo c > c +svn add c +svn ci -m addc +cd .. + +# svnsync repo/trunk/dir only so the last two revisions are empty +svnadmin create svn-empty +cat > svn-empty/hooks/pre-revprop-change < ../empty.svndump diff --git a/tests/test-convert-svn-source.t b/tests/test-convert-svn-source.t --- a/tests/test-convert-svn-source.t +++ b/tests/test-convert-svn-source.t @@ -187,3 +187,24 @@ This is also the only place testing more extra: branch=default extra: convert_revision=svn:........-....-....-....-............/proj B/mytrunk@1 (re) $ cd .. + +Test converting empty heads (issue3347) + + $ svnadmin create svn-empty + $ svnadmin load -q svn-empty < "$TESTDIR/svn/empty.svndump" + $ hg --config convert.svn.trunk= convert svn-empty + assuming destination svn-empty-hg + initializing destination svn-empty-hg repository + scanning source... + sorting... + converting... + 1 init projA + 0 adddir + $ hg --config convert.svn.trunk= convert file://$svnpath/svn-empty/trunk + assuming destination trunk-hg + initializing destination trunk-hg repository + scanning source... + sorting... + converting... + 1 init projA + 0 adddir