changeset 901:bd12a4da0f35

replay: workaround svn not telling us about x/l flags (issue346)
author Bryan O'Sullivan <bryano@fb.com>
date Sun, 13 May 2012 15:28:50 +0200
parents abd8f2f2c58a
children 7d9cd708f412
files hgsubversion/editor.py hgsubversion/svnwrap/svn_swig_wrapper.py tests/fixtures/addspecial.sh tests/fixtures/addspecial.svndump tests/test_fetch_symlinks.py
diffstat 5 files changed, 295 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/editor.py
+++ b/hgsubversion/editor.py
@@ -25,7 +25,7 @@ class NeverClosingStringIO(object):
 class RevisionData(object):
 
     __slots__ = [
-        'file', 'files', 'deleted', 'rev', 'execfiles', 'symlinks', 'batons',
+        'file', 'added', 'files', 'deleted', 'rev', 'execfiles', 'symlinks', 'batons',
         'copies', 'missing', 'emptybranches', 'base', 'externals', 'ui',
         'exception',
     ]
@@ -36,6 +36,7 @@ class RevisionData(object):
 
     def clear(self):
         self.file = None
+        self.added = set()
         self.files = {}
         self.deleted = {}
         self.rev = None
@@ -194,6 +195,7 @@ class HgEditor(svnwrap.Editor):
         self.current.file = path
         if not copyfrom_path:
             self.ui.note('A %s\n' % path)
+            self.current.added.add(path)
             self.current.set(path, '', False, False)
             return
         self.ui.note('A+ %s\n' % path)
--- a/hgsubversion/svnwrap/svn_swig_wrapper.py
+++ b/hgsubversion/svnwrap/svn_swig_wrapper.py
@@ -415,6 +415,19 @@ class SubversionRepo(object):
             else:
                 raise
 
+        # if we're not pulling the whole repo, svn fails to report
+        # file properties for files merged from subtrees outside ours
+        if self.svn_url != self.root:
+            links, execs = editor.current.symlinks, editor.current.execfiles
+            l = len(self.subdir) - 1
+            for f in editor.current.added:
+                sf = f[l:]
+                if links[f] or execs[f]:
+                    continue
+                props = self.list_props(sf, revision)
+                links[f] = props.get('svn:special') == '*'
+                execs[f] = props.get('svn:executable') == '*'
+
     def get_revision(self, revision, editor):
         ''' feed the contents of the given revision to the given editor '''
 
new file mode 100644
--- /dev/null
+++ b/tests/fixtures/addspecial.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+mkdir temp
+cd temp
+
+svnadmin create repo
+svn co file://`pwd`/repo wc
+cd wc
+
+mkdir -p trunk branches
+svn add trunk branches
+svn ci -m'initial structure'
+cd trunk
+echo a>a
+svn add a
+svn ci -mci1 a
+cd ..
+svn up
+svn cp trunk branches/foo
+svn ci -m'branch foo'
+cd branches/foo
+ln -s a fnord
+svn add fnord
+svn ci -msymlink fnord
+svn up ../..
+echo foo > exe
+chmod +x exe
+svn add exe
+svn ci -mexecutable exe
+svn up ../..
+cd ../../trunk
+svn merge ../branches/foo
+svn ci -mmerge
+svn up
+
+pwd
+cd ../../..
+svnadmin dump temp/repo > addspecial.svndump
+echo
+echo 'Complete.'
+echo 'You probably want to clean up temp now.'
+echo 'Dump in addspecial.svndump'
+exit 0
new file mode 100644
--- /dev/null
+++ b/tests/fixtures/addspecial.svndump
@@ -0,0 +1,224 @@
+SVN-fs-dump-format-version: 2
+
+UUID: c8aac64d-a89b-4b18-8be4-1648446ccf98
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2012-05-13T12:00:44.718813Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 17
+initial structure
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T12:00:45.074954Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+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: 103
+Content-length: 103
+
+K 7
+svn:log
+V 3
+ci1
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T12:00:46.061349Z
+PROPS-END
+
+Node-path: trunk/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: 111
+Content-length: 111
+
+K 7
+svn:log
+V 10
+branch foo
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T12:00:49.059324Z
+PROPS-END
+
+Node-path: branches/foo
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk
+
+
+Revision-number: 4
+Prop-content-length: 107
+Content-length: 107
+
+K 7
+svn:log
+V 7
+symlink
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T12:00:50.080078Z
+PROPS-END
+
+Node-path: branches/foo/fnord
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: c118dba188202a1efc975bef6064180b
+Text-content-sha1: 41f94e4692313bf7f7c92aa600002f1dff93d6bf
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link a
+
+Revision-number: 5
+Prop-content-length: 111
+Content-length: 111
+
+K 7
+svn:log
+V 10
+executable
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T12:00:52.082785Z
+PROPS-END
+
+Node-path: branches/foo/exe
+Node-kind: file
+Node-action: add
+Prop-content-length: 36
+Text-content-length: 4
+Text-content-md5: d3b07384d113edec49eaa6238ad5ff00
+Text-content-sha1: f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
+Content-length: 40
+
+K 14
+svn:executable
+V 1
+*
+PROPS-END
+foo
+
+
+Revision-number: 6
+Prop-content-length: 105
+Content-length: 105
+
+K 7
+svn:log
+V 5
+merge
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T12:00:55.062876Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 52
+Content-length: 52
+
+K 13
+svn:mergeinfo
+V 17
+/branches/foo:3-5
+PROPS-END
+
+
+Node-path: trunk/exe
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: branches/foo/exe
+Text-copy-source-md5: d3b07384d113edec49eaa6238ad5ff00
+Text-copy-source-sha1: f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
+
+
+Node-path: trunk/fnord
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: branches/foo/fnord
+Text-copy-source-md5: c118dba188202a1efc975bef6064180b
+Text-copy-source-sha1: 41f94e4692313bf7f7c92aa600002f1dff93d6bf
+
+
--- a/tests/test_fetch_symlinks.py
+++ b/tests/test_fetch_symlinks.py
@@ -50,7 +50,17 @@ class TestFetchSymlinks(test_util.TestBa
     def test_symlinks_stupid(self):
         self.test_symlinks(True)
 
+class TestMergeSpecial(test_util.TestBase):
+    def test_special(self):
+        repo = self._load_fixture_and_fetch('addspecial.svndump',
+                                            subdir='trunk')
+        ctx = repo['tip']
+        self.assertEqual(ctx['fnord'].flags(), 'l')
+        self.assertEqual(ctx['exe'].flags(), 'x')
+
 def suite():
-    all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks),
-          ]
+    all_tests = [
+        unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks),
+        unittest.TestLoader().loadTestsFromTestCase(TestMergeSpecial),
+        ]
     return unittest.TestSuite(all_tests)