--- a/hgext/convert/__init__.py Mon Aug 27 15:39:07 2007 -0700
+++ b/hgext/convert/__init__.py Mon Aug 27 15:41:31 2007 -0700
@@ -397,6 +397,23 @@
that use unix logins to identify authors (eg: CVS). One line per author
mapping and the line format is:
srcauthor=whatever string you want
+
+ The filemap is a file that allows filtering and remapping of files
+ and directories. Comment lines start with '#'. Each line can
+ contain one of the following directives:
+
+ include path/to/file
+
+ exclude path/to/file
+
+ rename from/file to/file
+
+ The 'include' directive causes a file, or all files under a
+ directory, to be included in the destination repository. The
+ 'exclude' directive causes files or directories to be omitted.
+ The 'rename' directive renames a file or directory. To rename
+ from a subdirectory into the root of the repository, use '.' as
+ the path to rename to.
"""
util._encoding = 'UTF-8'
--- a/mercurial/commands.py Mon Aug 27 15:39:07 2007 -0700
+++ b/mercurial/commands.py Mon Aug 27 15:41:31 2007 -0700
@@ -1645,11 +1645,7 @@
other = hg.repository(ui, source)
ui.status(_('comparing with %s\n') % source)
if revs:
- if 'lookup' in other.capabilities:
- revs = [other.lookup(rev) for rev in revs]
- else:
- error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
- raise util.Abort(error)
+ revs = [other.lookup(rev) for rev in revs]
incoming = repo.findincoming(other, heads=revs, force=opts["force"])
if not incoming:
try:
@@ -1667,8 +1663,6 @@
if revs is None:
cg = other.changegroup(incoming, "incoming")
else:
- if 'changegroupsubset' not in other.capabilities:
- raise util.Abort(_("Partial incoming cannot be done because other repository doesn't support changegroupsubset."))
cg = other.changegroupsubset(incoming, revs, 'incoming')
bundletype = other.local() and "HG10BZ" or "HG10UN"
fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
@@ -2078,10 +2072,11 @@
other = hg.repository(ui, source)
ui.status(_('pulling from %s\n') % (source))
if revs:
- if 'lookup' in other.capabilities:
+ try:
revs = [other.lookup(rev) for rev in revs]
- else:
- error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
+ except repo.NoCapability:
+ error = _("Other repository doesn't support revision lookup, "
+ "so a rev cannot be specified.")
raise util.Abort(error)
modheads = repo.pull(other, heads=revs, force=opts['force'])
--- a/mercurial/httprepo.py Mon Aug 27 15:39:07 2007 -0700
+++ b/mercurial/httprepo.py Mon Aug 27 15:41:31 2007 -0700
@@ -276,9 +276,9 @@
def get_caps(self):
if self.caps is None:
try:
- self.caps = self.do_read('capabilities').split()
+ self.caps = util.set(self.do_read('capabilities').split())
except repo.RepoError:
- self.caps = ()
+ self.caps = util.set()
self.ui.debug(_('capabilities: %s\n') %
(' '.join(self.caps or ['none'])))
return self.caps
@@ -354,6 +354,7 @@
fp.close()
def lookup(self, key):
+ self.requirecap('lookup', _('look up remote revision'))
d = self.do_cmd("lookup", key = key).read()
success, data = d[:-1].split(' ', 1)
if int(success):
@@ -391,6 +392,7 @@
return util.chunkbuffer(zgenerator(f))
def changegroupsubset(self, bases, heads, source):
+ self.requirecap('changegroupsubset', _('look up remote changes'))
baselst = " ".join([hex(n) for n in bases])
headlst = " ".join([hex(n) for n in heads])
f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
--- a/mercurial/localrepo.py Mon Aug 27 15:39:07 2007 -0700
+++ b/mercurial/localrepo.py Mon Aug 27 15:41:31 2007 -0700
@@ -13,7 +13,7 @@
import os, revlog, time, util, extensions, hook
class localrepository(repo.repository):
- capabilities = ('lookup', 'changegroupsubset')
+ capabilities = util.set(('lookup', 'changegroupsubset'))
supported = ('revlogv1', 'store')
def __init__(self, parentui, path=None, create=0):
--- a/mercurial/repo.py Mon Aug 27 15:39:07 2007 -0700
+++ b/mercurial/repo.py Mon Aug 27 15:41:31 2007 -0700
@@ -9,16 +9,26 @@
class RepoError(Exception):
pass
+class NoCapability(RepoError):
+ pass
+
class repository(object):
def capable(self, name):
'''tell whether repo supports named capability.
return False if not supported.
if boolean capability, return True.
if string capability, return string.'''
+ if name in self.capabilities:
+ return True
name_eq = name + '='
for cap in self.capabilities:
- if name == cap:
- return True
if cap.startswith(name_eq):
return cap[len(name_eq):]
return False
+
+ def requirecap(self, name, purpose):
+ '''raise an exception if the given capability is not present'''
+ if not self.capable(name):
+ raise NoCapability(_('cannot %s; remote repository does not '
+ 'support the %r capability') %
+ (purpose, name))
--- a/mercurial/sshrepo.py Mon Aug 27 15:39:07 2007 -0700
+++ b/mercurial/sshrepo.py Mon Aug 27 15:41:31 2007 -0700
@@ -71,11 +71,11 @@
else:
self.raise_(repo.RepoError(_("no suitable response from remote hg")))
- self.capabilities = ()
+ self.capabilities = util.set()
lines.reverse()
for l in lines:
if l.startswith("capabilities:"):
- self.capabilities = l[:-1].split(":")[1].split()
+ self.capabilities.update(l[:-1].split(":")[1].split())
break
def readerr(self):
@@ -131,6 +131,7 @@
self.call("unlock")
def lookup(self, key):
+ self.requirecap('lookup', _('look up remote revision'))
d = self.call("lookup", key=key)
success, data = d[:-1].split(" ", 1)
if int(success):
@@ -168,6 +169,7 @@
return self.do_cmd("changegroup", roots=n)
def changegroupsubset(self, bases, heads, kind):
+ self.requirecap('changegroupsubset', _('look up remote changes'))
bases = " ".join(map(hex, bases))
heads = " ".join(map(hex, heads))
return self.do_cmd("changegroupsubset", bases=bases, heads=heads)
--- a/tests/hghave Mon Aug 27 15:39:07 2007 -0700
+++ b/tests/hghave Mon Aug 27 15:41:31 2007 -0700
@@ -5,11 +5,22 @@
"""
import optparse
import os
+import re
import sys
import tempfile
tempprefix = 'hg-hghave-'
+def matchoutput(cmd, regexp):
+ """Return True if cmd executes successfully and its output
+ is matched by the supplied regular expression.
+ """
+ r = re.compile(regexp)
+ fh = os.popen(cmd)
+ s = fh.read()
+ ret = fh.close()
+ return ret is None and r.search(s)
+
def has_symlink():
return hasattr(os, "symlink")
@@ -52,10 +63,18 @@
return False
def has_git():
- fh = os.popen('git --version 2>&1')
- s = fh.read()
- ret = fh.close()
- return ret is None and s.startswith('git version')
+ return matchoutput('git --version 2>&1', r'^git version')
+
+def has_svn():
+ return matchoutput('svn --version 2>&1', r'^svn, version') and \
+ matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
+
+def has_svn_bindings():
+ try:
+ import svn.core
+ return True
+ except ImportError:
+ return False
checks = {
"eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
@@ -64,6 +83,8 @@
"fifo": (has_fifo, "named pipes"),
"hotshot": (has_hotshot, "python hotshot module"),
"lsprof": (has_lsprof, "python lsprof module"),
+ "svn": (has_svn, "subversion client and admin tools"),
+ "svn-bindings": (has_svn_bindings, "subversion python bindings"),
"symlink": (has_symlink, "symbolic links"),
}
--- a/tests/run-tests.py Mon Aug 27 15:39:07 2007 -0700
+++ b/tests/run-tests.py Mon Aug 27 15:41:31 2007 -0700
@@ -152,7 +152,13 @@
os.chdir(TESTDIR)
os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
- os.environ["PYTHONPATH"] = PYTHONDIR
+
+ pythonpath = os.environ.get("PYTHONPATH")
+ if pythonpath:
+ pythonpath = PYTHONDIR + os.pathsep + pythonpath
+ else:
+ pythonpath = PYTHONDIR
+ os.environ["PYTHONPATH"] = pythonpath
use_correct_python()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-convert-svn Mon Aug 27 15:41:31 2007 -0700
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+"$TESTDIR/hghave" svn svn-bindings || exit 80
+
+fix_path()
+{
+ tr '\\' /
+}
+
+echo "[extensions]" >> $HGRCPATH
+echo "convert = " >> $HGRCPATH
+
+svnadmin create svn-repo
+
+echo % initial svn import
+mkdir t
+cd t
+echo a > a
+cd ..
+
+svnpath=`pwd | tr '\\' /`
+# SVN wants all paths to start with a slash. Unfortunately,
+# Windows ones don't. Handle that.
+expr $svnpath : "\/" > /dev/null
+if [ $? -ne 0 ]; then
+ svnpath='/'$svnpath
+fi
+
+svnurl=file://$svnpath/svn-repo/trunk
+svn import -m init t $svnurl | fix_path
+
+echo % update svn repository
+svn co $svnurl t2 | fix_path
+cd t2
+echo b >> a
+echo b > b
+svn add b
+svn ci -m changea
+cd ..
+
+echo % convert to hg once
+hg convert $svnurl
+
+echo % update svn repository again
+cd t2
+echo c >> a
+echo c >> b
+svn ci -m changeb
+cd ..
+
+echo % test incremental conversion
+hg convert $svnurl
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-convert-svn.out Mon Aug 27 15:41:31 2007 -0700
@@ -0,0 +1,32 @@
+% initial svn import
+Adding t/a
+
+Committed revision 1.
+% update svn repository
+A t2/a
+Checked out revision 1.
+A b
+Sending a
+Adding b
+Transmitting file data ..
+Committed revision 2.
+% convert to hg once
+assuming destination trunk-hg
+initializing destination trunk-hg repository
+scanning source...
+sorting...
+converting...
+1 init
+0 changea
+% update svn repository again
+Sending a
+Sending b
+Transmitting file data ..
+Committed revision 3.
+% test incremental conversion
+assuming destination trunk-hg
+destination trunk-hg is a Mercurial repository
+scanning source...
+sorting...
+converting...
+0 changeb