changeset 11572:324bad1dc230

Merge with stable
author Martin Geisler <mg@lazybytes.net>
date Thu, 15 Jul 2010 14:11:14 +0200
parents 2d88369a27bf (diff) 636554d58665 (current diff)
children 7ecf4a082c5f
files mercurial/subrepo.py
diffstat 25 files changed, 288 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/check-code.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/contrib/check-code.py	Thu Jul 15 14:11:14 2010 +0200
@@ -70,6 +70,11 @@
 ]
 
 pypats = [
+    (r'^\s*def\s*\w+\s*\(.*,\s*\(',
+     "tuple parameter unpacking not available in Python 3+"),
+    (r'lambda\s*\(.*,.*\)',
+     "tuple parameter unpacking not available in Python 3+"),
+    (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
     (r'^\s*\t', "don't use tabs"),
     (r'\S;\s*\n', "semicolon"),
     (r'\w,\w', "missing whitespace after ,"),
--- a/contrib/mergetools.hgrc	Thu Jul 15 13:24:02 2010 +0200
+++ b/contrib/mergetools.hgrc	Thu Jul 15 14:11:14 2010 +0200
@@ -13,6 +13,9 @@
 gvimdiff.regname=path
 gvimdiff.priority=-9
 
+vimdiff.args=$local $other $base
+vimdiff.priority=-10
+
 merge.checkconflicts=True
 merge.priority=-100
 
--- a/doc/gendoc.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/doc/gendoc.py	Thu Jul 15 14:11:14 2010 +0200
@@ -110,7 +110,7 @@
             ui.write(".. _%s:\n" % name)
         ui.write("\n")
         section(sec)
-        if callable(doc):
+        if hasattr(doc, '__call__'):
             doc = doc()
         ui.write(doc)
         ui.write("\n")
--- a/hgext/bugzilla.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/bugzilla.py	Thu Jul 15 14:11:14 2010 +0200
@@ -437,5 +437,5 @@
                 bz.update(id, ctx)
             bz.notify(ids, util.email(ctx.user()))
     except MySQLdb.MySQLError, err:
-        raise util.Abort(_('database error: %s') % err[1])
+        raise util.Abort(_('database error: %s') % err.args[1])
 
--- a/hgext/churn.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/churn.py	Thu Jul 15 14:11:14 2010 +0200
@@ -149,7 +149,8 @@
 
     if opts.get('diffstat'):
         width -= 15
-        def format(name, (added, removed)):
+        def format(name, diffstat):
+            added, removed = diffstat
             return "%s %15s %s%s\n" % (pad(name, maxname),
                                        '+%d/-%d' % (added, removed),
                                        ui.label('+' * charnum(added),
--- a/hgext/convert/transport.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/convert/transport.py	Thu Jul 15 14:11:14 2010 +0200
@@ -98,9 +98,8 @@
             svn.ra.reparent(self.ra, self.svn_url.encode('utf8'))
 
     class Reporter(object):
-        def __init__(self, (reporter, report_baton)):
-            self._reporter = reporter
-            self._baton = report_baton
+        def __init__(self, reporter_data):
+            self._reporter, self._baton = reporter_data
 
         def set_path(self, path, revnum, start_empty, lock_token, pool=None):
             svn.ra.reporter2_invoke_set_path(self._reporter, self._baton,
--- a/hgext/inotify/client.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/inotify/client.py	Thu Jul 15 14:11:14 2010 +0200
@@ -27,11 +27,11 @@
         except (OSError, socket.error), err:
             autostart = self.ui.configbool('inotify', 'autostart', True)
 
-            if err[0] == errno.ECONNREFUSED:
+            if err.args[0] == errno.ECONNREFUSED:
                 self.ui.warn(_('inotify-client: found dead inotify server '
                                'socket; removing it\n'))
                 os.unlink(os.path.join(self.root, '.hg', 'inotify.sock'))
-            if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
+            if err.args[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
                 self.ui.debug('(starting inotify server)\n')
                 try:
                     try:
@@ -49,13 +49,13 @@
                         return function(self, *args)
                     except socket.error, err:
                         self.ui.warn(_('inotify-client: could not talk to new '
-                                       'inotify server: %s\n') % err[-1])
-            elif err[0] in (errno.ECONNREFUSED, errno.ENOENT):
+                                       'inotify server: %s\n') % err.args[-1])
+            elif err.args[0] in (errno.ECONNREFUSED, errno.ENOENT):
                 # silently ignore normal errors if autostart is False
                 self.ui.debug('(inotify server not running)\n')
             else:
                 self.ui.warn(_('inotify-client: failed to contact inotify '
-                               'server: %s\n') % err[-1])
+                               'server: %s\n') % err.args[-1])
 
         self.ui.traceback()
         raise QueryFailed('inotify query failed')
@@ -75,7 +75,7 @@
         try:
             self.sock.connect(sockpath)
         except socket.error, err:
-            if err[0] == "AF_UNIX path too long":
+            if err.args[0] == "AF_UNIX path too long":
                 sockpath = os.readlink(sockpath)
                 self.sock.connect(sockpath)
             else:
--- a/hgext/inotify/linux/_inotify.c	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/inotify/linux/_inotify.c	Thu Jul 15 14:11:14 2010 +0200
@@ -15,6 +15,15 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
+#include <util.h>
+
+/* Variables used in the event string representation */
+static PyObject *join;
+static PyObject *er_wm;
+static PyObject *er_wmc;
+static PyObject *er_wmn;
+static PyObject *er_wmcn;
+
 static PyObject *init(PyObject *self, PyObject *args)
 {
 	PyObject *ret = NULL;
@@ -312,8 +321,8 @@
 };
 
 PyDoc_STRVAR(
-    event_doc,
-    "event: Structure describing an inotify event.");
+	event_doc,
+	"event: Structure describing an inotify event.");
 
 static PyObject *event_new(PyTypeObject *t, PyObject *a, PyObject *k)
 {
@@ -327,20 +336,15 @@
 	Py_XDECREF(evt->cookie);
 	Py_XDECREF(evt->name);
 
-	(*evt->ob_type->tp_free)(evt);
+	Py_TYPE(evt)->tp_free(evt);
 }
 
 static PyObject *event_repr(struct event *evt)
 {
-	int wd = PyInt_AsLong(evt->wd);
 	int cookie = evt->cookie == Py_None ? -1 : PyInt_AsLong(evt->cookie);
 	PyObject *ret = NULL, *pymasks = NULL, *pymask = NULL;
-	PyObject *join = NULL;
 	char *maskstr;
-
-	join = PyString_FromString("|");
-	if (join == NULL)
-		goto bail;
+	PyObject *tuple = NULL, *formatstr = NULL;
 
 	pymasks = decode_mask(PyInt_AsLong(evt->mask));
 	if (pymasks == NULL)
@@ -350,33 +354,35 @@
 	if (pymask == NULL)
 		goto bail;
 
-	maskstr = PyString_AsString(pymask);
-
 	if (evt->name != Py_None) {
-		PyObject *pyname = PyString_Repr(evt->name, 1);
-		char *name = pyname ? PyString_AsString(pyname) : "???";
-
-		if (cookie == -1)
-			ret = PyString_FromFormat(
-				"event(wd=%d, mask=%s, name=%s)",
-				wd, maskstr, name);
-		else
-			ret = PyString_FromFormat("event(wd=%d, mask=%s, "
-						  "cookie=0x%x, name=%s)",
-						  wd, maskstr, cookie, name);
-
-		Py_XDECREF(pyname);
+		if (cookie == -1) {
+			formatstr = er_wmn;
+			tuple = PyTuple_Pack(3, evt->wd, pymask, evt->name);
+		}
+		else {
+			formatstr = er_wmcn;
+			tuple = PyTuple_Pack(4, evt->wd, pymask,
+					     evt->cookie, evt->name);
+		}
 	} else {
-		if (cookie == -1)
-			ret = PyString_FromFormat("event(wd=%d, mask=%s)",
-						  wd, maskstr);
+		if (cookie == -1) {
+			formatstr = er_wm;
+			tuple = PyTuple_Pack(2, evt->wd, pymask);
+		}
 		else {
-			ret = PyString_FromFormat(
-				"event(wd=%d, mask=%s, cookie=0x%x)",
-				wd, maskstr, cookie);
+			formatstr = er_wmc;
+			tuple = PyTuple_Pack(3, evt->wd, pymask, evt->cookie);
 		}
 	}
 
+	if (tuple == NULL)
+		goto bail;
+
+	ret = PyNumber_Remainder(formatstr, tuple);
+
+	if (ret == NULL)
+		goto bail;
+
 	goto done;
 bail:
 	Py_CLEAR(ret);
@@ -384,14 +390,13 @@
 done:
 	Py_XDECREF(pymask);
 	Py_XDECREF(pymasks);
-	Py_XDECREF(join);
+	Py_XDECREF(tuple);
 
 	return ret;
 }
 
 static PyTypeObject event_type = {
-	PyObject_HEAD_INIT(NULL)
-	0,                         /*ob_size*/
+	PyVarObject_HEAD_INIT(NULL, 0)
 	"_inotify.event",             /*tp_name*/
 	sizeof(struct event), /*tp_basicsize*/
 	0,                         /*tp_itemsize*/
@@ -561,6 +566,17 @@
 	return ret;
 }
 
+static int init_globals(void)
+{
+	join = PyString_FromString("|");
+	er_wm = PyString_FromString("event(wd=%d, mask=%s)");
+	er_wmn = PyString_FromString("event(wd=%d, mask=%s, name=%s)");
+	er_wmc = PyString_FromString("event(wd=%d, mask=%s, cookie=0x%x)");
+	er_wmcn = PyString_FromString("event(wd=%d, mask=%s, cookie=0x%x, name=%s)");
+
+	return join && er_wm && er_wmn && er_wmc && er_wmcn;
+}
+
 PyDoc_STRVAR(
 	read_doc,
 	"read(fd, bufsize[=65536]) -> list_of_events\n"
@@ -585,6 +601,35 @@
 	{NULL},
 };
 
+#ifdef IS_PY3K
+static struct PyModuleDef _inotify_module = {
+	PyModuleDef_HEAD_INIT,
+	"_inotify",
+	doc,
+	-1,
+	methods
+};
+
+PyMODINIT_FUNC PyInit__inotify(void)
+{
+	PyObject *mod, *dict;
+
+	mod = PyModule_Create(&_inotify_module);
+
+	if (mod == NULL)
+		return NULL;
+
+	if (!init_globals())
+		return;
+
+	dict = PyModule_GetDict(mod);
+
+	if (dict)
+		define_consts(dict);
+
+	return mod;
+}
+#else
 void init_inotify(void)
 {
 	PyObject *mod, *dict;
@@ -592,6 +637,9 @@
 	if (PyType_Ready(&event_type) == -1)
 		return;
 
+	if (!init_globals())
+		return;
+
 	mod = Py_InitModule3("_inotify", methods, doc);
 
 	dict = PyModule_GetDict(mod);
@@ -599,3 +647,4 @@
 	if (dict)
 		define_consts(dict);
 }
+#endif
--- a/hgext/inotify/linuxserver.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/inotify/linuxserver.py	Thu Jul 15 14:11:14 2010 +0200
@@ -117,7 +117,7 @@
             try:
                 events = cls.poll.poll(timeout)
             except select.error, err:
-                if err[0] == errno.EINTR:
+                if err.args[0] == errno.EINTR:
                     continue
                 raise
             if events:
--- a/hgext/inotify/server.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/inotify/server.py	Thu Jul 15 14:11:14 2010 +0200
@@ -336,10 +336,10 @@
         try:
             self.sock.bind(self.sockpath)
         except socket.error, err:
-            if err[0] == errno.EADDRINUSE:
+            if err.args[0] == errno.EADDRINUSE:
                 raise AlreadyStartedException(_('cannot start: socket is '
                                                 'already bound'))
-            if err[0] == "AF_UNIX path too long":
+            if err.args[0] == "AF_UNIX path too long":
                 if os.path.islink(self.sockpath) and \
                         not os.path.exists(self.sockpath):
                     raise util.Abort('inotify-server: cannot start: '
@@ -437,7 +437,7 @@
             finally:
                 sock.shutdown(socket.SHUT_WR)
         except socket.error, err:
-            if err[0] != errno.EPIPE:
+            if err.args[0] != errno.EPIPE:
                 raise
 
 if sys.platform == 'linux2':
--- a/hgext/record.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/hgext/record.py	Thu Jul 15 14:11:14 2010 +0200
@@ -10,7 +10,7 @@
 from mercurial.i18n import gettext, _
 from mercurial import cmdutil, commands, extensions, hg, mdiff, patch
 from mercurial import util
-import copy, cStringIO, errno, operator, os, re, tempfile
+import copy, cStringIO, errno, os, re, tempfile
 
 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
 
@@ -186,7 +186,8 @@
             self.hunk = []
             self.stream = []
 
-        def addrange(self, (fromstart, fromend, tostart, toend, proc)):
+        def addrange(self, limits):
+            fromstart, fromend, tostart, toend, proc = limits
             self.fromline = int(fromstart)
             self.toline = int(tostart)
             self.proc = proc
@@ -354,8 +355,8 @@
                 applied[chunk.filename()].append(chunk)
             else:
                 fixoffset += chunk.removed - chunk.added
-    return reduce(operator.add, [h for h in applied.itervalues()
-                                 if h[0].special() or len(h) > 1], [])
+    return sum([h for h in applied.itervalues()
+               if h[0].special() or len(h) > 1], [])
 
 def record(ui, repo, *pats, **opts):
     '''interactively select changes to commit
@@ -485,7 +486,8 @@
 
             # 3a. apply filtered patch to clean repo  (clean)
             if backups:
-                hg.revert(repo, repo.dirstate.parents()[0], backups.has_key)
+                hg.revert(repo, repo.dirstate.parents()[0],
+                          lambda key: key in backups)
 
             # 3b. (apply)
             if dopatch:
--- a/mercurial/archival.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/archival.py	Thu Jul 15 14:11:14 2010 +0200
@@ -12,7 +12,7 @@
 import cStringIO, os, stat, tarfile, time, zipfile
 import zlib, gzip
 
-def tidyprefix(dest, prefix, suffixes):
+def tidyprefix(dest, kind, prefix):
     '''choose prefix to use for names in archive.  make sure prefix is
     safe for consumers.'''
 
@@ -23,7 +23,7 @@
             raise ValueError('dest must be string if no prefix')
         prefix = os.path.basename(dest)
         lower = prefix.lower()
-        for sfx in suffixes:
+        for sfx in exts.get(kind, []):
             if lower.endswith(sfx):
                 prefix = prefix[:-len(sfx)]
                 break
@@ -35,6 +35,20 @@
         raise util.Abort(_('archive prefix contains illegal components'))
     return prefix
 
+exts = {
+    'tar': ['.tar'],
+    'tbz2': ['.tbz2', '.tar.bz2'],
+    'tgz': ['.tgz', '.tar.gz'],
+    'zip': ['.zip'],
+    }
+
+def guesskind(dest):
+    for kind, extensions in exts.iteritems():
+        if util.any(dest.endswith(ext) for ext in extensions):
+            return kind
+    return None
+
+
 class tarit(object):
     '''write archive to tar file or stream.  can write uncompressed,
     or compress with gzip or bzip2.'''
@@ -66,9 +80,7 @@
             if fname:
                 self.fileobj.write(fname + '\000')
 
-    def __init__(self, dest, prefix, mtime, kind=''):
-        self.prefix = tidyprefix(dest, prefix, ['.tar', '.tar.bz2', '.tar.gz',
-                                                '.tgz', '.tbz2'])
+    def __init__(self, dest, mtime, kind=''):
         self.mtime = mtime
 
         def taropen(name, mode, fileobj=None):
@@ -90,7 +102,7 @@
             self.z = taropen(name='', mode='w|', fileobj=dest)
 
     def addfile(self, name, mode, islink, data):
-        i = tarfile.TarInfo(self.prefix + name)
+        i = tarfile.TarInfo(name)
         i.mtime = self.mtime
         i.size = len(data)
         if islink:
@@ -129,8 +141,7 @@
     '''write archive to zip file or stream.  can write uncompressed,
     or compressed with deflate.'''
 
-    def __init__(self, dest, prefix, mtime, compress=True):
-        self.prefix = tidyprefix(dest, prefix, ('.zip',))
+    def __init__(self, dest, mtime, compress=True):
         if not isinstance(dest, str):
             try:
                 dest.tell()
@@ -142,7 +153,7 @@
         self.date_time = time.gmtime(mtime)[:6]
 
     def addfile(self, name, mode, islink, data):
-        i = zipfile.ZipInfo(self.prefix + name, self.date_time)
+        i = zipfile.ZipInfo(name, self.date_time)
         i.compress_type = self.z.compression
         # unzip will not honor unix file modes unless file creator is
         # set to unix (id 3).
@@ -160,9 +171,7 @@
 class fileit(object):
     '''write archive as files in directory.'''
 
-    def __init__(self, name, prefix, mtime):
-        if prefix:
-            raise util.Abort(_('cannot give prefix when archiving to files'))
+    def __init__(self, name, mtime):
         self.basedir = name
         self.opener = util.opener(self.basedir)
 
@@ -182,9 +191,9 @@
 archivers = {
     'files': fileit,
     'tar': tarit,
-    'tbz2': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'bz2'),
-    'tgz': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'gz'),
-    'uzip': lambda name, prefix, mtime: zipit(name, prefix, mtime, False),
+    'tbz2': lambda name, mtime: tarit(name, mtime, 'bz2'),
+    'tgz': lambda name, mtime: tarit(name, mtime, 'gz'),
+    'uzip': lambda name, mtime: zipit(name, mtime, False),
     'zip': zipit,
     }
 
@@ -204,19 +213,25 @@
 
     prefix is name of path to put before every archive member.'''
 
+    if kind == 'files':
+        if prefix:
+            raise util.Abort(_('cannot give prefix when archiving to files'))
+    else:
+        prefix = tidyprefix(dest, kind, prefix)
+
     def write(name, mode, islink, getdata):
         if matchfn and not matchfn(name):
             return
         data = getdata()
         if decode:
             data = repo.wwritedata(name, data)
-        archiver.addfile(name, mode, islink, data)
+        archiver.addfile(prefix + name, mode, islink, data)
 
     if kind not in archivers:
         raise util.Abort(_("unknown archive type '%s'") % kind)
 
     ctx = repo[node]
-    archiver = archivers[kind](dest, prefix, mtime or ctx.date()[0])
+    archiver = archivers[kind](dest, mtime or ctx.date()[0])
 
     if repo.ui.configbool("ui", "archivemeta", True):
         def metadata():
--- a/mercurial/commands.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/commands.py	Thu Jul 15 14:11:14 2010 +0200
@@ -83,7 +83,7 @@
     Returns 0 if all files are successfully added.
     """
     try:
-        sim = float(opts.get('similarity') or 0)
+        sim = float(opts.get('similarity') or 100)
     except ValueError:
         raise util.Abort(_('similarity must be a number'))
     if sim < 0 or sim > 100:
@@ -196,20 +196,7 @@
     if os.path.realpath(dest) == repo.root:
         raise util.Abort(_('repository root cannot be destination'))
 
-    def guess_type():
-        exttypes = {
-            'tar': ['.tar'],
-            'tbz2': ['.tbz2', '.tar.bz2'],
-            'tgz': ['.tgz', '.tar.gz'],
-            'zip': ['.zip'],
-        }
-
-        for type, extensions in exttypes.items():
-            if util.any(dest.endswith(ext) for ext in extensions):
-                return type
-        return None
-
-    kind = opts.get('type') or guess_type() or 'files'
+    kind = opts.get('type') or archival.guesskind(dest) or 'files'
     prefix = opts.get('prefix')
 
     if dest == '-':
@@ -1867,7 +1854,10 @@
         if not doc:
             doc = _("(no help text available)")
         if hasattr(entry[0], 'definition'):  # aliased command
-            doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
+            if entry[0].definition.startswith('!'):  # shell alias
+                doc = _('shell alias for::\n\n    %s') % entry[0].definition[1:]
+            else:
+                doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
         if ui.quiet:
             doc = doc.splitlines()[0]
         keep = ui.verbose and ['verbose'] or []
--- a/mercurial/dispatch.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/dispatch.py	Thu Jul 15 14:11:14 2010 +0200
@@ -6,7 +6,7 @@
 # GNU General Public License version 2 or any later version.
 
 from i18n import _
-import os, sys, atexit, signal, pdb, socket, errno, shlex, time
+import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback
 import util, commands, hg, fancyopts, extensions, hook, error
 import cmdutil, encoding
 import ui as uimod
@@ -49,6 +49,8 @@
         try:
             # enter the debugger before command execution
             if '--debugger' in args:
+                ui.warn(_("entering debugger - "
+                        "type c to continue starting hg or h for help\n"))
                 pdb.set_trace()
             try:
                 return _dispatch(ui, args)
@@ -57,6 +59,7 @@
         except:
             # enter the debugger when we hit an exception
             if '--debugger' in args:
+                traceback.print_exc()
                 pdb.post_mortem(sys.exc_info()[2])
             ui.traceback()
             raise
@@ -205,6 +208,13 @@
 
             return
 
+        if self.definition.startswith('!'):
+            def fn(ui, *args):
+                cmd = '%s %s' % (self.definition[1:], ' '.join(args))
+                return util.system(cmd)
+            self.fn = fn
+            return
+
         args = shlex.split(self.definition)
         cmd = args.pop(0)
         args = map(util.expandpath, args)
--- a/mercurial/httprepo.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/httprepo.py	Thu Jul 15 14:11:14 2010 +0200
@@ -249,9 +249,9 @@
                     self.ui.status(_('remote: '), l)
                 return ret
             except socket.error, err:
-                if err[0] in (errno.ECONNRESET, errno.EPIPE):
-                    raise util.Abort(_('push failed: %s') % err[1])
-                raise util.Abort(err[1])
+                if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
+                    raise util.Abort(_('push failed: %s') % err.args[1])
+                raise util.Abort(err.args[1])
         finally:
             fp.close()
             os.unlink(tempname)
--- a/mercurial/revlog.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/revlog.py	Thu Jul 15 14:11:14 2010 +0200
@@ -131,7 +131,7 @@
         self.dataf = dataf
         self.s = struct.calcsize(indexformatng)
         self.datasize = size
-        self.l = size / self.s
+        self.l = size // self.s
         self.index = [None] * self.l
         self.map = {nullid: nullrev}
         self.allmap = 0
@@ -176,8 +176,8 @@
                 # limit blocksize so that we don't get too much data.
                 blocksize = max(self.datasize - blockstart, 0)
             data = self.dataf.read(blocksize)
-        lend = len(data) / self.s
-        i = blockstart / self.s
+        lend = len(data) // self.s
+        i = blockstart // self.s
         off = 0
         # lazyindex supports __delitem__
         if lend > len(self.index) - i:
--- a/mercurial/subrepo.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/subrepo.py	Thu Jul 15 14:11:14 2010 +0200
@@ -182,22 +182,49 @@
         raise util.Abort(_('unknown subrepo type %s') % state[2])
     return types[state[2]](ctx, path, state[:2])
 
-# subrepo classes need to implement the following methods:
-# __init__(self, ctx, path, state)
-# dirty(self): returns true if the dirstate of the subrepo
-#   does not match current stored state
-# commit(self, text, user, date): commit the current changes
-#   to the subrepo with the given log message. Use given
-#   user and date if possible. Return the new state of the subrepo.
-# remove(self): remove the subrepo (should verify the dirstate
-#   is not dirty first)
-# get(self, state): run whatever commands are needed to put the
-#   subrepo into this state
-# merge(self, state): merge currently-saved state with the new state.
-# push(self, force): perform whatever action is analogous to 'hg push'
-#   This may be a no-op on some systems.
+# subrepo classes need to implement the following abstract class:
+
+class abstractsubrepo(object):
+
+    def dirty(self):
+        """returns true if the dirstate of the subrepo does not match
+        current stored state
+        """
+        raise NotImplementedError
+
+    def commit(self, text, user, date):
+        """commit the current changes to the subrepo with the given
+        log message. Use given user and date if possible. Return the
+        new state of the subrepo.
+        """
+        raise NotImplementedError
+
+    def remove(self):
+        """remove the subrepo
 
-class hgsubrepo(object):
+        (should verify the dirstate is not dirty first)
+        """
+        raise NotImplementedError
+
+    def get(self, state):
+        """run whatever commands are needed to put the subrepo into
+        this state
+        """
+        raise NotImplementedError
+
+    def merge(self, state):
+        """merge currently-saved state with the new state."""
+        raise NotImplementedError
+
+    def push(self, force):
+        """perform whatever action is analogous to 'hg push'
+
+        This may be a no-op on some systems.
+        """
+        raise NotImplementedError
+
+
+class hgsubrepo(abstractsubrepo):
     def __init__(self, ctx, path, state):
         self._path = path
         self._state = state
@@ -294,15 +321,15 @@
         other = hg.repository(self._repo.ui, dsturl)
         return self._repo.push(other, force)
 
-class svnsubrepo(object):
+class svnsubrepo(abstractsubrepo):
     def __init__(self, ctx, path, state):
         self._path = path
         self._state = state
         self._ctx = ctx
         self._ui = ctx._repo.ui
 
-    def _svncommand(self, commands):
-        path = os.path.join(self._ctx._repo.origroot, self._path)
+    def _svncommand(self, commands, filename=''):
+        path = os.path.join(self._ctx._repo.origroot, self._path, filename)
         cmd = ['svn'] + commands + [path]
         cmd = [util.shellquote(arg) for arg in cmd]
         cmd = util.quotecommand(' '.join(cmd))
--- a/mercurial/util.h	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/util.h	Thu Jul 15 14:11:14 2010 +0200
@@ -12,6 +12,48 @@
 
 #define IS_PY3K
 #define PyInt_FromLong PyLong_FromLong
+#define PyInt_AsLong PyLong_AsLong
+
+/*
+ Mapping of some of the python < 2.x PyString* functions to py3k's PyUnicode.
+
+ The commented names below represent those that are present in the PyBytes
+ definitions for python < 2.6 (below in this file) that don't have a direct
+ implementation.
+*/
+
+#define PyStringObject PyUnicodeObject
+#define PyString_Type PyUnicode_Type
+
+#define PyString_Check PyUnicode_Check
+#define PyString_CheckExact PyUnicode_CheckExact
+#define PyString_CHECK_INTERNED PyUnicode_CHECK_INTERNED
+#define PyString_AS_STRING PyUnicode_AsLatin1String
+#define PyString_GET_SIZE PyUnicode_GET_SIZE
+
+#define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+#define PyString_FromString PyUnicode_FromString
+#define PyString_FromFormatV PyUnicode_FromFormatV
+#define PyString_FromFormat PyUnicode_FromFormat
+/* #define PyString_Size PyUnicode_GET_SIZE */
+/* #define PyString_AsString */
+/* #define PyString_Repr */
+#define PyString_Concat PyUnicode_Concat
+#define PyString_ConcatAndDel PyUnicode_AppendAndDel
+#define _PyString_Resize PyUnicode_Resize
+/* #define _PyString_Eq */
+#define PyString_Format PyUnicode_Format
+/* #define _PyString_FormatLong */
+/* #define PyString_DecodeEscape */
+#define _PyString_Join PyUnicode_Join
+#define PyString_Decode PyUnicode_Decode
+#define PyString_Encode PyUnicode_Encode
+#define PyString_AsEncodedObject PyUnicode_AsEncodedObject
+#define PyString_AsEncodedString PyUnicode_AsEncodedString
+#define PyString_AsDecodedObject PyUnicode_AsDecodedObject
+#define PyString_AsDecodedString PyUnicode_AsDecodedUnicode
+/* #define PyString_AsStringAndSize */
+#define _PyString_InsertThousandsGrouping _PyUnicode_InsertThousandsGrouping
 
 #endif /* PY_MAJOR_VERSION */
 
--- a/mercurial/util.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/mercurial/util.py	Thu Jul 15 14:11:14 2010 +0200
@@ -38,9 +38,15 @@
 
 import __builtin__
 
-def fakebuffer(sliceable, offset=0):
-    return sliceable[offset:]
-if not hasattr(__builtin__, 'buffer'):
+if sys.version_info[0] < 3:
+    def fakebuffer(sliceable, offset=0):
+        return sliceable[offset:]
+else:
+    def fakebuffer(sliceable, offset=0):
+        return memoryview(sliceable)[offset:]
+try:
+    buffer
+except NameError:
     __builtin__.buffer = fakebuffer
 
 import subprocess
--- a/setup.py	Thu Jul 15 13:24:02 2010 +0200
+++ b/setup.py	Thu Jul 15 14:11:14 2010 +0200
@@ -9,6 +9,17 @@
 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
     raise SystemExit("Mercurial requires Python 2.4 or later.")
 
+if sys.version_info[0] >= 3:
+    def b(s):
+        '''A helper function to emulate 2.6+ bytes literals using string
+        literals.'''
+        return s.encode('latin1')
+else:
+    def b(s):
+        '''A helper function to emulate 2.6+ bytes literals using string
+        literals.'''
+        return s
+
 # Solaris Python packaging brain damage
 try:
     import hashlib
@@ -114,8 +125,8 @@
     # fine, we don't want to load it anyway.  Python may warn about
     # a missing __init__.py in mercurial/locale, we also ignore that.
     err = [e for e in err.splitlines()
-           if not e.startswith('Not trusting file') \
-              and not e.startswith('warning: Not importing')]
+           if not e.startswith(b('Not trusting file')) \
+              and not e.startswith(b('warning: Not importing'))]
     if err:
         return ''
     return out
@@ -275,7 +286,8 @@
     cc = new_compiler()
     if hasfunction(cc, 'inotify_add_watch'):
         inotify = Extension('hgext.inotify.linux._inotify',
-                            ['hgext/inotify/linux/_inotify.c'])
+                            ['hgext/inotify/linux/_inotify.c'],
+                            ['mercurial'])
         inotify.optional = True
         extmodules.append(inotify)
         packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
--- a/tests/test-alias	Thu Jul 15 13:24:02 2010 +0200
+++ b/tests/test-alias	Thu Jul 15 14:11:14 2010 +0200
@@ -14,6 +14,7 @@
 dln = lognull --debug
 nousage = rollback
 put = export -r 0 -o "\$FOO/%R.diff"
+echo = !echo
 
 [defaults]
 mylog = -q
@@ -64,3 +65,6 @@
 echo '% path expanding'
 FOO=`pwd` hg put
 cat 0.diff
+
+echo '% shell aliases'
+hg echo foo
--- a/tests/test-alias.out	Thu Jul 15 13:24:02 2010 +0200
+++ b/tests/test-alias.out	Thu Jul 15 14:11:14 2010 +0200
@@ -43,3 +43,5 @@
 +++ b/foo	Thu Jan 01 00:00:00 1970 +0000
 @@ -0,0 +1,1 @@
 +foo
+% shell aliases
+foo
--- a/tests/test-diff-upgrade	Thu Jul 15 13:24:02 2010 +0200
+++ b/tests/test-diff-upgrade	Thu Jul 15 14:11:14 2010 +0200
@@ -35,7 +35,7 @@
 python -c "file('binary', 'wb').write('\0\0')"
 python -c "file('newbinary', 'wb').write('\0')"
 rm rmbinary
-hg addremove
+hg addremove -s 0
 
 echo '% git=no: regular diff for all files'
 hg autodiff --git=no
--- a/tests/test-issue660	Thu Jul 15 13:24:02 2010 +0200
+++ b/tests/test-issue660	Thu Jul 15 14:11:14 2010 +0200
@@ -56,7 +56,7 @@
 echo a > a/a
 echo b > b
 
-hg addremove
+hg addremove -s 0
 hg st
 
 echo % commit
--- a/tests/test-rename	Thu Jul 15 13:24:02 2010 +0200
+++ b/tests/test-rename	Thu Jul 15 14:11:14 2010 +0200
@@ -26,7 +26,7 @@
 
 echo '# rename --after a single file when src and tgt already tracked'
 mv d1/d11/a1 d2/c
-hg addrem
+hg addrem -s 0
 hg rename --after d1/d11/a1 d2/c
 hg status -C
 hg update -C