changeset 10273:e898bc7810ad

subrepo: handle svn externals and meta changes (issue1982) - Detect changes to meta on regular and external entries - Do not try to commit external entries
author Patrick Mezard <pmezard@gmail.com>
date Thu, 21 Jan 2010 13:26:26 +0100
parents 886858b834da
children 6109a02c682b
files mercurial/subrepo.py tests/test-subrepo-svn tests/test-subrepo-svn.out
diffstat 3 files changed, 118 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/subrepo.py	Thu Jan 21 15:13:40 2010 +0100
+++ b/mercurial/subrepo.py	Thu Jan 21 13:26:26 2010 +0100
@@ -282,27 +282,45 @@
             return 0
         return int(entries[0].getAttribute('revision') or 0)
 
-    def _wcclean(self):
+    def _wcchanged(self):
+        """Return (changes, extchanges) where changes is True
+        if the working directory was changed, and extchanges is
+        True if any of these changes concern an external entry.
+        """
         output = self._svncommand(['status', '--xml'])
+        externals, changes = [], []
         doc = xml.dom.minidom.parseString(output)
-        for s in doc.getElementsByTagName('wc-status'):
-            st = s.getAttribute('item')
-            if st and st != 'unversioned':
-                return False
-            props = s.getAttribute('props')
-            if props and props != 'none':
-                return False
-        return True
+        for e in doc.getElementsByTagName('entry'):
+            s = e.getElementsByTagName('wc-status')
+            if not s:
+                continue
+            item = s[0].getAttribute('item')
+            props = s[0].getAttribute('props')
+            path = e.getAttribute('path')
+            if item == 'external':
+                externals.append(path)
+            if (item not in ('', 'normal', 'unversioned', 'external')
+                or props not in ('', 'none')):
+                changes.append(path)
+        for path in changes:
+            for ext in externals:
+                if path == ext or path.startswith(ext + os.sep):
+                    return True, True
+        return bool(changes), False
 
     def dirty(self):
-        if self._wcrev() == self._state[1] and self._wcclean():
+        if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
             return False
         return True
 
     def commit(self, text, user, date):
         # user and date are out of our hands since svn is centralized
-        if self._wcclean():
+        changed, extchanged = self._wcchanged()
+        if not changed:
             return self._wcrev()
+        if extchanged:
+            # Do not try to commit externals
+            raise util.Abort(_('cannot commit svn externals'))
         commitinfo = self._svncommand(['commit', '-m', text])
         self._ui.status(commitinfo)
         newrev = re.search('Committed revision ([\d]+).', commitinfo)
--- a/tests/test-subrepo-svn	Thu Jan 21 15:13:40 2010 +0100
+++ b/tests/test-subrepo-svn	Thu Jan 21 13:26:26 2010 +0100
@@ -23,9 +23,19 @@
 svnadmin create svn-repo
 svn co $SVNREPO svn-wc
 cd svn-wc
-echo alpha > alpha
-svn add alpha
+mkdir src
+echo alpha > src/alpha
+svn add src
+mkdir externals
+echo other > externals/other
+svn add externals
 svn ci -m 'Add alpha'
+svn up
+cat > extdef <<EOF
+externals -r1 $SVNREPO/externals
+EOF
+svn propset -F extdef svn:externals src
+svn ci -m 'Setting externals'
 cd ..
 
 echo % create hg repo
@@ -39,8 +49,8 @@
 hg ci -Am0
 
 echo % add first svn sub
-echo "s = [svn]$SVNREPO" >> .hgsub
-svn co --quiet $SVNREPO s
+echo "s = [svn]$SVNREPO/src" >> .hgsub
+svn co --quiet $SVNREPO/src s
 hg add .hgsub
 hg ci -m1
 echo % debugsub
@@ -60,14 +70,32 @@
 
 echo
 echo % add a commit from svn
-cd "$WCROOT"
+cd "$WCROOT"/src
 svn up
 echo xyz >> alpha
+svn propset svn:mime-type 'text/xml' alpha
 svn ci -m 'amend a from svn'
-cd ../sub/t
+cd ../../sub/t
+
 echo % this commit from hg will fail
 echo zzz >> s/alpha
 hg ci -m 'amend alpha from hg'
+svn revert -q s/alpha
+
+echo % this commit fails because of meta changes
+svn propset svn:mime-type 'text/html' s/alpha
+hg ci -m 'amend alpha from hg'
+svn revert -q s/alpha
+
+echo % this commit fails because of externals changes
+echo zzz > s/externals/other
+hg ci -m 'amend externals from hg'
+svn revert -q s/externals/other
+
+echo % this commit fails because of externals meta changes
+svn propset svn:mime-type 'text/html' s/externals/other
+hg ci -m 'amend externals from hg'
+svn revert -q s/externals/other
 
 echo
 echo % clone
--- a/tests/test-subrepo-svn.out	Thu Jan 21 15:13:40 2010 +0100
+++ b/tests/test-subrepo-svn.out	Thu Jan 21 13:26:26 2010 +0100
@@ -1,9 +1,20 @@
 % create subversion repo
 Checked out revision 0.
-A         alpha
-Adding         alpha
-Transmitting file data .
+A         src
+A         src/alpha
+A         externals
+A         externals/other
+Adding         externals
+Adding         externals/other
+Adding         src
+Adding         src/alpha
+Transmitting file data ..
 Committed revision 1.
+At revision 1.
+property 'svn:externals' set on 'src'
+Sending        src
+
+Committed revision 2.
 % create hg repo
 % first revision, no sub
 adding a
@@ -11,38 +22,66 @@
 committing subrepository s
 % debugsub
 path s
- source   file:///root/svn-repo
- revision 1
+ source   file:///root/svn-repo/src
+ revision 2
 
 % change file in svn and hg, commit
 committing subrepository s
 Sending        s/alpha
 Transmitting file data .
-Committed revision 2.
-At revision 2.
+Committed revision 3.
+
+Fetching external item into 's/externals'
+External at revision 1.
+
+At revision 3.
 path s
- source   file:///root/svn-repo
- revision 2
+ source   file:///root/svn-repo/src
+ revision 3
 
 % should be empty despite change to s/a
 
 % add a commit from svn
 U    alpha
-Updated to revision 2.
-Sending        alpha
+
+Fetching external item into 'externals'
+A    externals/other
+Updated external to revision 1.
+
+Updated to revision 3.
+property 'svn:mime-type' set on 'alpha'
+Sending        src/alpha
 Transmitting file data .
-Committed revision 3.
+Committed revision 4.
 % this commit from hg will fail
 committing subrepository s
 abort: svn: Commit failed (details follow):
-svn: File '/alpha' is out of date
+svn: File '/src/alpha' is out of date
+% this commit fails because of meta changes
+property 'svn:mime-type' set on 's/alpha'
+committing subrepository s
+abort: svn: Commit failed (details follow):
+svn: File '/src/alpha' is out of date
+% this commit fails because of externals changes
+committing subrepository s
+abort: cannot commit svn externals
+% this commit fails because of externals meta changes
+property 'svn:mime-type' set on 's/externals/other'
+committing subrepository s
+abort: cannot commit svn externals
 
 % clone
 updating to branch default
 A    s/alpha
-Checked out revision 2.
+ U   s
+
+Fetching external item into 's/externals'
+A    s/externals/other
+Checked out external at revision 1.
+
+Checked out revision 3.
 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 % debugsub in clone
 path s
- source   file:///root/svn-repo
- revision 2
+ source   file:///root/svn-repo/src
+ revision 3