changeset 764:bc5c176b63eb

svnexternals: support pushing subrepo based externals
author Patrick Mezard <pmezard@gmail.com>
date Thu, 25 Nov 2010 21:55:21 +0100
parents 6463b34bbcb6
children 62c9e6bd2ca7
files hgsubversion/svnexternals.py hgsubversion/util.py tests/test_externals.py tests/test_util.py
diffstat 4 files changed, 88 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/svnexternals.py
+++ b/hgsubversion/svnexternals.py
@@ -409,3 +409,10 @@ if subrepo:
                 wcrev == self._state[1]) and not self._wcchanged()[0]:
                 return False
             return True
+
+        def commit(self, text, user, date):
+            rev = super(svnsubrepo, self).commit(text, user, date)
+            # Keep unversioned externals unversioned
+            if self._state[1] == 'HEAD':
+                rev = 'HEAD'
+            return rev
--- a/hgsubversion/util.py
+++ b/hgsubversion/util.py
@@ -13,7 +13,7 @@ try:
 except ImportError:
     pass
 
-ignoredfiles = set(['.hgtags', '.hgsvnexternals'])
+ignoredfiles = set(['.hgtags', '.hgsvnexternals', '.hgsub', '.hgsubstate'])
 
 b_re = re.compile(r'^\+\+\+ b\/([^\n]*)', re.MULTILINE)
 a_re = re.compile(r'^--- a\/([^\n]*)', re.MULTILINE)
--- a/tests/test_externals.py
+++ b/tests/test_externals.py
@@ -242,13 +242,10 @@ 2 deps/project2
         checkdeps(ui, repo, 4, ['subdir/deps/project1'], ['deps/project2'])
 
 class TestPushExternals(test_util.TestBase):
-    def setUp(self):
-        test_util.TestBase.setUp(self)
+    def test_push_externals(self, stupid=False):
         test_util.load_fixture_and_fetch('pushexternals.svndump',
                                          self.repo_path,
                                          self.wc_path)
-
-    def test_push_externals(self, stupid=False):
         # Add a new reference on an existing and non-existing directory
         changes = [
             ('.hgsvnexternals', '.hgsvnexternals',
@@ -295,6 +292,71 @@ class TestPushExternals(test_util.TestBa
     def test_push_externals_stupid(self):
         self.test_push_externals(True)
 
+    def test_push_hgsub(self, stupid=False):
+        if subrepo is None:
+            return
+
+        test_util.load_fixture_and_fetch('pushexternals.svndump',
+                                         self.repo_path,
+                                         self.wc_path,
+                                         externals='subrepos')
+        # Add a new reference on an existing and non-existing directory
+        changes = [
+            ('.hgsub', '.hgsub', """\
+dir/deps/project2 = [hgsubversion] dir:^/externals/project2 deps/project2
+subdir1/deps/project1 = [hgsubversion] subdir1:^/externals/project1 deps/project1
+subdir2/deps/project2 = [hgsubversion] subdir2:^/externals/project2 deps/project2
+"""),
+            ('.hgsubstate', '.hgsubstate', """\
+HEAD dir/deps/project2
+HEAD subdir1/deps/project1
+HEAD subdir2/deps/project2
+"""),
+            ('subdir1/a', 'subdir1/a', 'a'),
+            ('subdir2/a', 'subdir2/a', 'a'),
+            ]
+        self.svnco('externals/project2', '2', 'dir/deps/project2')
+        self.svnco('externals/project1', '2', 'subdir1/deps/project1')
+        self.svnco('externals/project2', '2', 'subdir2/deps/project2')
+        self.commitchanges(changes)
+        self.pushrevisions(stupid)
+        self.assertchanges(changes, self.repo['tip'])
+
+        # Check .hgsub and .hgsubstate were not pushed
+        self.assertEqual(['dir', 'subdir1', 'subdir1/a','subdir2',
+                          'subdir2/a'], self.svnls('trunk'))
+
+        # Remove all references from one directory, add a new one
+        # to the other (test multiline entries)
+        changes = [
+            ('.hgsub', '.hgsub', """\
+subdir1/deps/project1 = [hgsubversion] subdir1:^/externals/project1 deps/project1
+subdir1/deps/project2 = [hgsubversion] subdir1:^/externals/project2 deps/project2
+"""),
+            ('.hgsubstate', '.hgsubstate', """\
+HEAD subdir1/deps/project1
+HEAD subdir1/deps/project2
+"""),
+            # This removal used to trigger the parent directory removal
+            ('subdir1/a', None, None),
+            ]
+        self.svnco('externals/project1', '2', 'subdir1/deps/project1')
+        self.svnco('externals/project2', '2', 'subdir1/deps/project2')
+        self.commitchanges(changes)
+        self.pushrevisions(stupid)
+        self.assertchanges(changes, self.repo['tip'])
+        # Check subdir2/a is still there even if the externals were removed
+        self.assertTrue('subdir2/a' in self.repo['tip'])
+        self.assertTrue('subdir1/a' not in self.repo['tip'])
+
+        # Test externals removal
+        changes = [
+            ('.hgsub', None, None),
+            ('.hgsubstate', None, None),
+            ]
+        self.commitchanges(changes)
+        self.pushrevisions(stupid)
+        self.assertchanges(changes, self.repo['tip'])
 
 def suite():
     all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExternals),
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -337,6 +337,20 @@ class TestBase(unittest.TestCase):
         entries.sort()
         return entries
 
+    def svnco(self, svnpath, rev, path):
+        path = os.path.join(self.wc_path, path)
+        subpath = os.path.dirname(path)
+        if not os.path.isdir(subpath):
+            os.makedirs(subpath)
+        svnpath = fileurl(self.repo_path + '/' + svnpath)
+        args = ['svn', 'co', '-r', rev, svnpath, path]
+        p = subprocess.Popen(args,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT)
+        stdout, stderr = p.communicate()
+        if p.returncode:
+            raise Exception('svn co failed on %s: %r' % (svnpath, stderr))
+
     def commitchanges(self, changes, parent='tip', message='automated test'):
         """Commit changes to mercurial directory