--- a/mercurial/subrepo.py Thu Dec 31 17:10:03 2009 -0600
+++ b/mercurial/subrepo.py Thu Dec 31 13:16:03 2009 -0600
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
-import errno, os
+import errno, os, re
from i18n import _
import config, util, node, error
hg = None
@@ -250,6 +250,88 @@
other = hg.repository(self._repo.ui, dsturl)
self._repo.push(other, force)
+class svnsubrepo(object):
+ def __init__(self, ctx, path, state):
+ self._path = path
+ self._state = state
+ self._ctx = ctx
+ self._ui = ctx._repo.ui
+
+ def _svncommand(self, commands):
+ cmd = ['svn'] + commands + [self._path]
+ cmd = [util.shellquote(arg) for arg in cmd]
+ cmd = util.quotecommand(' '.join(cmd))
+ write, read, err = util.popen3(cmd)
+ retdata = read.read()
+ err = err.read().strip()
+ if err:
+ raise util.Abort(err)
+ return retdata
+
+ def _wcrev(self):
+ info = self._svncommand(['info'])
+ mat = re.search('Revision: ([\d]+)\n', info)
+ if not mat:
+ return 0
+ return mat.groups()[0]
+
+ def _url(self):
+ info = self._svncommand(['info'])
+ mat = re.search('URL: ([^\n]+)\n', info)
+ if not mat:
+ return 0
+ return mat.groups()[0]
+
+ def _wcclean(self):
+ status = self._svncommand(['status'])
+ status = '\n'.join([s for s in status.splitlines() if s[0] != '?'])
+ if status.strip():
+ return False
+ return True
+
+ def dirty(self):
+ if self._wcrev() == self._state[1] and self._wcclean():
+ 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():
+ return self._wcrev()
+ commitinfo = self._svncommand(['commit', '-m', text])
+ self._ui.status(commitinfo)
+ newrev = re.search('Committed revision ([\d]+).', commitinfo)
+ if not newrev:
+ raise util.Abort(commitinfo.splitlines()[-1])
+ newrev = newrev.groups()[0]
+ self._ui.status(self._svncommand(['update', '-r', newrev]))
+ return newrev
+
+ def remove(self):
+ if self.dirty():
+ self._repo.ui.warn('Not removing repo %s because'
+ 'it has changes.\n' % self._path)
+ return
+ self._repo.ui.note('removing subrepo %s\n' % self._path)
+ shutil.rmtree(self._ctx.repo.join(self._path))
+
+ def get(self, state):
+ status = self._svncommand(['checkout', state[0], '--revision', state[1]])
+ if not re.search('Checked out revision [\d]+.', status):
+ raise util.Abort(status.splitlines()[-1])
+ self._ui.status(status)
+
+ def merge(self, state):
+ old = int(self._state[1])
+ new = int(state[1])
+ if new > old:
+ self.get(state)
+
+ def push(self, force):
+ # nothing for svn
+ pass
+
types = {
'hg': hgsubrepo,
+ 'svn': svnsubrepo,
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-subrepo-svn Thu Dec 31 13:16:03 2009 -0600
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+"$TESTDIR/hghave" svn || exit 80
+
+escapedwd=$(pwd | \
+ python -c \
+ "import sys,urllib; print urllib.pathname2url(sys.stdin.read().strip())"
+ )
+filterpath="sed s+$escapedwd+/root+"
+
+echo % create subversion repo
+
+SVNREPO="file://$escapedwd/svn-repo"
+WCROOT="$(pwd)/svn-wc"
+svnadmin create svn-repo
+svn co $SVNREPO svn-wc
+cd svn-wc
+echo alpha > alpha
+svn add alpha
+svn ci -m 'Add alpha'
+cd ..
+
+echo % create hg repo
+
+rm -rf sub
+mkdir sub
+cd sub
+hg init t
+cd t
+
+echo % first revision, no sub
+echo a > a
+hg ci -Am0
+
+echo % add first svn sub
+echo "s = [svn]$SVNREPO" >> .hgsub
+svn co --quiet $SVNREPO s
+hg add .hgsub
+hg ci -m1
+echo % debugsub
+hg debugsub | $filterpath
+
+echo
+echo % change file in svn and hg, commit
+echo a >> a
+echo alpha >> s/alpha
+hg commit -m 'Message!'
+hg debugsub | $filterpath
+
+echo
+echo a > s/a
+echo % should be empty despite change to s/a
+hg st
+
+echo
+echo % add a commit from svn
+pushd "$WCROOT" > /dev/null
+svn up
+echo xyz >> alpha
+svn ci -m 'amend a from svn'
+popd > /dev/null
+echo % this commit from hg will fail
+echo zzz >> s/alpha
+hg ci -m 'amend alpha from hg'
+
+echo
+echo % clone
+cd ..
+hg clone t tc
+cd tc
+echo % debugsub in clone
+hg debugsub | $filterpath
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-subrepo-svn.out Thu Dec 31 13:16:03 2009 -0600
@@ -0,0 +1,48 @@
+% create subversion repo
+Checked out revision 0.
+A alpha
+Adding alpha
+Transmitting file data .
+Committed revision 1.
+% create hg repo
+% first revision, no sub
+adding a
+% add first svn sub
+committing subrepository s
+% debugsub
+path s
+ source file:///root/svn-repo
+ revision 1
+
+% change file in svn and hg, commit
+committing subrepository s
+Sending s/alpha
+Transmitting file data .
+Committed revision 2.
+At revision 2.
+path s
+ source file:///root/svn-repo
+ revision 2
+
+% should be empty despite change to s/a
+
+% add a commit from svn
+U alpha
+Updated to revision 2.
+Sending alpha
+Transmitting file data .
+Committed revision 3.
+% this commit from hg will fail
+committing subrepository s
+abort: svn: Commit failed (details follow):
+svn: File '/alpha' is out of date
+
+% clone
+updating to branch default
+A s/alpha
+Checked out revision 2.
+3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% debugsub in clone
+path s
+ source file:///root/svn-repo
+ revision 2