# HG changeset patch # User Patrick Mezard # Date 2010-01-21 12:26:26 # Node ID e898bc7810ad08affd99d4420c89165252db194c # Parent 886858b834dab9f3e26e8c519ac2ad457996a0f6 subrepo: handle svn externals and meta changes (issue1982) - Detect changes to meta on regular and external entries - Do not try to commit external entries diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -282,27 +282,45 @@ class svnsubrepo(object): 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) diff --git a/tests/test-subrepo-svn b/tests/test-subrepo-svn --- a/tests/test-subrepo-svn +++ b/tests/test-subrepo-svn @@ -23,9 +23,19 @@ WCROOT="`pwd`/svn-wc" 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 < a 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 @@ hg st 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 diff --git a/tests/test-subrepo-svn.out b/tests/test-subrepo-svn.out --- a/tests/test-subrepo-svn.out +++ b/tests/test-subrepo-svn.out @@ -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 @@ adding a 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