changeset 20622:352abbb0be88

extensions: remove the inotify extension (BC) This extension has always had correctness issues and has been unmaintained for years. It is now removed in favor of the third-party hgwatchman which is maintained and appears to be correct. Users with inotify enabled in their config files will fall back to standard status performance.
author Matt Mackall <mpm@selenic.com>
date Sat, 01 Mar 2014 16:20:15 -0600
parents 5beb49fd5958
children 84f6bc03b4e5
files hgext/inotify/__init__.py hgext/inotify/client.py hgext/inotify/common.py hgext/inotify/linux/__init__.py hgext/inotify/linux/_inotify.c hgext/inotify/linux/watcher.py hgext/inotify/linuxserver.py hgext/inotify/server.py mercurial/extensions.py setup.py tests/blacklists/inotify-failures tests/blacklists/linux-vfat tests/hghave.py tests/run-tests.py tests/test-check-pyflakes.t tests/test-duplicateoptions.py tests/test-help.t tests/test-inotify-debuginotify.t tests/test-inotify-dirty-dirstate.t tests/test-inotify-issue1371.t tests/test-inotify-issue1542.t tests/test-inotify-issue1556.t tests/test-inotify-lookup.t tests/test-inotify.t
diffstat 24 files changed, 3 insertions(+), 2740 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/inotify/__init__.py	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-# __init__.py - inotify-based status acceleration for Linux
-#
-# Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
-# Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-'''accelerate status report using Linux's inotify service'''
-
-# todo: socket permissions
-
-from mercurial.i18n import _
-from mercurial import util
-import server
-from client import client, QueryFailed
-
-testedwith = 'internal'
-
-def serve(ui, repo, **opts):
-    '''start an inotify server for this repository'''
-    server.start(ui, repo.dirstate, repo.root, opts)
-
-def debuginotify(ui, repo, **opts):
-    '''debugging information for inotify extension
-
-    Prints the list of directories being watched by the inotify server.
-    '''
-    cli = client(ui, repo)
-    response = cli.debugquery()
-
-    ui.write(_('directories being watched:\n'))
-    for path in response:
-        ui.write(('  %s/\n') % path)
-
-def reposetup(ui, repo):
-    if not util.safehasattr(repo, 'dirstate'):
-        return
-
-    class inotifydirstate(repo.dirstate.__class__):
-
-        # We'll set this to false after an unsuccessful attempt so that
-        # next calls of status() within the same instance don't try again
-        # to start an inotify server if it won't start.
-        _inotifyon = True
-
-        def status(self, match, subrepos, ignored, clean, unknown):
-            files = match.files()
-            if '.' in files:
-                files = []
-            if (self._inotifyon and not ignored and not subrepos and
-                not self._dirty):
-                cli = client(ui, repo)
-                try:
-                    result = cli.statusquery(files, match, False,
-                                            clean, unknown)
-                except QueryFailed, instr:
-                    ui.debug(str(instr))
-                    # don't retry within the same hg instance
-                    inotifydirstate._inotifyon = False
-                    pass
-                else:
-                    if ui.config('inotify', 'debug'):
-                        r2 = super(inotifydirstate, self).status(
-                            match, [], False, clean, unknown)
-                        for c, a, b in zip('LMARDUIC', result, r2):
-                            for f in a:
-                                if f not in b:
-                                    ui.warn('*** inotify: %s +%s\n' % (c, f))
-                            for f in b:
-                                if f not in a:
-                                    ui.warn('*** inotify: %s -%s\n' % (c, f))
-                        result = r2
-                    return result
-            return super(inotifydirstate, self).status(
-                match, subrepos, ignored, clean, unknown)
-
-    repo.dirstate.__class__ = inotifydirstate
-
-cmdtable = {
-    'debuginotify':
-        (debuginotify, [], ('hg debuginotify')),
-    '^inserve':
-        (serve,
-         [('d', 'daemon', None, _('run server in background')),
-          ('', 'daemon-pipefds', '',
-           _('used internally by daemon mode'), _('NUM')),
-          ('t', 'idle-timeout', '',
-           _('minutes to sit idle before exiting'), _('NUM')),
-          ('', 'pid-file', '',
-           _('name of file to write process ID to'), _('FILE'))],
-         _('hg inserve [OPTION]...')),
-    }
--- a/hgext/inotify/client.py	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +0,0 @@
-# client.py - inotify status client
-#
-# Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
-# Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
-# Copyright 2009 Nicolas Dumazet <nicdumz@gmail.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from mercurial.i18n import _
-import common, server
-import errno, os, socket, struct
-
-class QueryFailed(Exception):
-    pass
-
-def start_server(function):
-    """
-    Decorator.
-    Tries to call function, if it fails, try to (re)start inotify server.
-    Raise QueryFailed if something went wrong
-    """
-    def decorated_function(self, *args):
-        try:
-            return function(self, *args)
-        except (OSError, socket.error), err:
-            autostart = self.ui.configbool('inotify', 'autostart', True)
-
-            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.args[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
-                try:
-                    try:
-                        server.start(self.ui, self.dirstate, self.root,
-                                     dict(daemon=True, daemon_pipefds=''))
-                    except server.AlreadyStartedException, inst:
-                        # another process may have started its own
-                        # inotify server while this one was starting.
-                        self.ui.debug(str(inst))
-                except Exception, inst:
-                    self.ui.warn(_('inotify-client: could not start inotify '
-                                   'server: %s\n') % inst)
-                else:
-                    try:
-                        return function(self, *args)
-                    except socket.error, err:
-                        self.ui.warn(_('inotify-client: could not talk to new '
-                                       '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.args[-1])
-
-        self.ui.traceback()
-        raise QueryFailed('inotify query failed')
-
-    return decorated_function
-
-
-class client(object):
-    def __init__(self, ui, repo):
-        self.ui = ui
-        self.dirstate = repo.dirstate
-        self.root = repo.root
-        self.sock = socket.socket(socket.AF_UNIX)
-
-    def _connect(self):
-        sockpath = os.path.join(self.root, '.hg', 'inotify.sock')
-        try:
-            self.sock.connect(sockpath)
-        except socket.error, err:
-            if err.args[0] == "AF_UNIX path too long":
-                sockpath = os.readlink(sockpath)
-                self.sock.connect(sockpath)
-            else:
-                raise
-
-    def _send(self, type, data):
-        """Sends protocol version number, and the data"""
-        self.sock.sendall(chr(common.version) + type + data)
-
-        self.sock.shutdown(socket.SHUT_WR)
-
-    def _receive(self, type):
-        """
-        Read data, check version number, extract headers,
-        and returns a tuple (data descriptor, header)
-        Raises QueryFailed on error
-        """
-        cs = common.recvcs(self.sock)
-        try:
-            version = ord(cs.read(1))
-        except TypeError:
-            # empty answer, assume the server crashed
-            self.ui.warn(_('inotify-client: received empty answer from inotify '
-                           'server'))
-            raise QueryFailed('server crashed')
-
-        if version != common.version:
-            self.ui.warn(_('(inotify: received response from incompatible '
-                      'server version %d)\n') % version)
-            raise QueryFailed('incompatible server version')
-
-        readtype = cs.read(4)
-        if readtype != type:
-            self.ui.warn(_('(inotify: received \'%s\' response when expecting'
-                       ' \'%s\')\n') % (readtype, type))
-            raise QueryFailed('wrong response type')
-
-        hdrfmt = common.resphdrfmts[type]
-        hdrsize = common.resphdrsizes[type]
-        try:
-            resphdr = struct.unpack(hdrfmt, cs.read(hdrsize))
-        except struct.error:
-            raise QueryFailed('unable to retrieve query response headers')
-
-        return cs, resphdr
-
-    def query(self, type, req):
-        self._connect()
-
-        self._send(type, req)
-
-        return self._receive(type)
-
-    @start_server
-    def statusquery(self, names, match, ignored, clean, unknown=True):
-
-        def genquery():
-            for n in names:
-                yield n
-            states = 'almrx!'
-            if ignored:
-                raise ValueError('this is insanity')
-            if clean:
-                states += 'c'
-            if unknown:
-                states += '?'
-            yield states
-
-        req = '\0'.join(genquery())
-
-        cs, resphdr = self.query('STAT', req)
-
-        def readnames(nbytes):
-            if nbytes:
-                names = cs.read(nbytes)
-                if names:
-                    return filter(match, names.split('\0'))
-            return []
-        results = tuple(map(readnames, resphdr[:-1]))
-
-        if names:
-            nbytes = resphdr[-1]
-            vdirs = cs.read(nbytes)
-            if vdirs:
-                for vdir in vdirs.split('\0'):
-                    if match.explicitdir:
-                        match.explicitdir(vdir)
-
-        return results
-
-    @start_server
-    def debugquery(self):
-        cs, resphdr = self.query('DBUG', '')
-
-        nbytes = resphdr[0]
-        names = cs.read(nbytes)
-        return names.split('\0')
--- a/hgext/inotify/common.py	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-# server.py - inotify common protocol code
-#
-# Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
-# Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-import cStringIO, socket, struct
-
-"""
-  Protocol between inotify clients and server:
-
-  Client sending query:
-  1) send protocol version number
-  2) send query type (string, 4 letters long)
-  3) send query parameters:
-     - For STAT, N+1 \0-separated strings:
-        1) N different names that need checking
-        2) 1 string containing all the status types to match
-     - No parameter needed for DBUG
-
-  Server sending query answer:
-  1) send protocol version number
-  2) send query type
-  3) send struct.pack'ed headers describing the length of the content:
-      e.g. for STAT, receive 9 integers describing the length of the
-      9 \0-separated string lists to be read:
-       * one file list for each lmar!?ic status type
-       * one list containing the directories visited during lookup
-
-"""
-
-version = 3
-
-resphdrfmts = {
-    'STAT': '>lllllllll', # status requests
-    'DBUG': '>l'          # debugging queries
-}
-resphdrsizes = dict((k, struct.calcsize(v))
-                    for k, v in resphdrfmts.iteritems())
-
-def recvcs(sock):
-    cs = cStringIO.StringIO()
-    s = True
-    try:
-        while s:
-            s = sock.recv(65536)
-            cs.write(s)
-    finally:
-        sock.shutdown(socket.SHUT_RD)
-    cs.seek(0)
-    return cs
--- a/hgext/inotify/linux/__init__.py	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-# __init__.py - low-level interfaces to the Linux inotify subsystem
-
-# Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
-
-# This library is free software; you can redistribute it and/or modify
-# it under the terms of version 2.1 of the GNU Lesser General Public
-# License, or any later version.
-
-'''Low-level interface to the Linux inotify subsystem.
-
-The inotify subsystem provides an efficient mechanism for file status
-monitoring and change notification.
-
-This package provides the low-level inotify system call interface and
-associated constants and helper functions.
-
-For a higher-level interface that remains highly efficient, use the
-inotify.watcher package.'''
-
-__author__ = "Bryan O'Sullivan <bos@serpentine.com>"
-
-from _inotify import *
-
-procfs_path = '/proc/sys/fs/inotify'
-
-def _read_procfs_value(name):
-    def read_value():
-        try:
-            fp = open(procfs_path + '/' + name)
-            r = int(fp.read())
-            fp.close()
-            return r
-        except OSError:
-            return None
-
-    read_value.__doc__ = '''Return the value of the %s setting from /proc.
-
-    If inotify is not enabled on this system, return None.''' % name
-
-    return read_value
-
-max_queued_events = _read_procfs_value('max_queued_events')
-max_user_instances = _read_procfs_value('max_user_instances')
-max_user_watches = _read_procfs_value('max_user_watches')
--- a/hgext/inotify/linux/_inotify.c	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,649 +0,0 @@
-/*
- * _inotify.c - Python extension interfacing to the Linux inotify subsystem
- *
- * Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of version 2.1 of the GNU Lesser General
- * Public License or any later version.
- */
-
-#include <Python.h>
-#include <alloca.h>
-#include <sys/inotify.h>
-#include <stdint.h>
-#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;
-	int fd = -1;
-
-	if (!PyArg_ParseTuple(args, ":init"))
-		goto bail;
-
-	Py_BEGIN_ALLOW_THREADS;
-	fd = inotify_init();
-	Py_END_ALLOW_THREADS;
-
-	if (fd == -1) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		goto bail;
-	}
-
-	ret = PyInt_FromLong(fd);
-	if (ret == NULL)
-		goto bail;
-
-	goto done;
-
-bail:
-	if (fd != -1)
-		close(fd);
-
-	Py_CLEAR(ret);
-
-done:
-	return ret;
-}
-
-PyDoc_STRVAR(
-	init_doc,
-	"init() -> fd\n"
-	"\n"
-	"Initialize an inotify instance.\n"
-	"Return a file descriptor associated with a new inotify event queue.");
-
-static PyObject *add_watch(PyObject *self, PyObject *args)
-{
-	PyObject *ret = NULL;
-	uint32_t mask;
-	int wd = -1;
-	char *path;
-	int fd;
-
-	if (!PyArg_ParseTuple(args, "isI:add_watch", &fd, &path, &mask))
-		goto bail;
-
-	Py_BEGIN_ALLOW_THREADS;
-	wd = inotify_add_watch(fd, path, mask);
-	Py_END_ALLOW_THREADS;
-
-	if (wd == -1) {
-		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-		goto bail;
-	}
-
-	ret = PyInt_FromLong(wd);
-	if (ret == NULL)
-		goto bail;
-
-	goto done;
-
-bail:
-	if (wd != -1)
-		inotify_rm_watch(fd, wd);
-
-	Py_CLEAR(ret);
-
-done:
-	return ret;
-}
-
-PyDoc_STRVAR(
-	add_watch_doc,
-	"add_watch(fd, path, mask) -> wd\n"
-	"\n"
-	"Add a watch to an inotify instance, or modify an existing watch.\n"
-	"\n"
-	"        fd: file descriptor returned by init()\n"
-	"        path: path to watch\n"
-	"        mask: mask of events to watch for\n"
-	"\n"
-	"Return a unique numeric watch descriptor for the inotify instance\n"
-	"mapped by the file descriptor.");
-
-static PyObject *remove_watch(PyObject *self, PyObject *args)
-{
-	uint32_t wd;
-	int fd;
-	int r;
-
-	if (!PyArg_ParseTuple(args, "iI:remove_watch", &fd, &wd))
-		return NULL;
-
-	Py_BEGIN_ALLOW_THREADS;
-	r = inotify_rm_watch(fd, wd);
-	Py_END_ALLOW_THREADS;
-
-	if (r == -1) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		return NULL;
-	}
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-
-PyDoc_STRVAR(
-	remove_watch_doc,
-	"remove_watch(fd, wd)\n"
-	"\n"
-	"        fd: file descriptor returned by init()\n"
-	"        wd: watch descriptor returned by add_watch()\n"
-	"\n"
-	"Remove a watch associated with the watch descriptor wd from the\n"
-	"inotify instance associated with the file descriptor fd.\n"
-	"\n"
-	"Removing a watch causes an IN_IGNORED event to be generated for this\n"
-	"watch descriptor.");
-
-#define bit_name(x) {x, #x}
-
-static struct {
-	int bit;
-	const char *name;
-	PyObject *pyname;
-} bit_names[] = {
-	bit_name(IN_ACCESS),
-	bit_name(IN_MODIFY),
-	bit_name(IN_ATTRIB),
-	bit_name(IN_CLOSE_WRITE),
-	bit_name(IN_CLOSE_NOWRITE),
-	bit_name(IN_OPEN),
-	bit_name(IN_MOVED_FROM),
-	bit_name(IN_MOVED_TO),
-	bit_name(IN_CREATE),
-	bit_name(IN_DELETE),
-	bit_name(IN_DELETE_SELF),
-	bit_name(IN_MOVE_SELF),
-	bit_name(IN_UNMOUNT),
-	bit_name(IN_Q_OVERFLOW),
-	bit_name(IN_IGNORED),
-	bit_name(IN_ONLYDIR),
-	bit_name(IN_DONT_FOLLOW),
-	bit_name(IN_MASK_ADD),
-	bit_name(IN_ISDIR),
-	bit_name(IN_ONESHOT),
-	{0}
-};
-
-static PyObject *decode_mask(int mask)
-{
-	PyObject *ret = PyList_New(0);
-	int i;
-
-	if (ret == NULL)
-		goto bail;
-
-	for (i = 0; bit_names[i].bit; i++) {
-		if (mask & bit_names[i].bit) {
-			if (bit_names[i].pyname == NULL) {
-				bit_names[i].pyname = PyString_FromString(bit_names[i].name);
-				if (bit_names[i].pyname == NULL)
-					goto bail;
-			}
-			Py_INCREF(bit_names[i].pyname);
-			if (PyList_Append(ret, bit_names[i].pyname) == -1)
-				goto bail;
-		}
-	}
-
-	goto done;
-
-bail:
-	Py_CLEAR(ret);
-
-done:
-	return ret;
-}
-
-static PyObject *pydecode_mask(PyObject *self, PyObject *args)
-{
-	int mask;
-
-	if (!PyArg_ParseTuple(args, "i:decode_mask", &mask))
-		return NULL;
-
-	return decode_mask(mask);
-}
-
-PyDoc_STRVAR(
-	decode_mask_doc,
-	"decode_mask(mask) -> list_of_strings\n"
-	"\n"
-	"Decode an inotify mask value into a list of strings that give the\n"
-	"name of each bit set in the mask.");
-
-static char doc[] = "Low-level inotify interface wrappers.";
-
-static void define_const(PyObject *dict, const char *name, uint32_t val)
-{
-	PyObject *pyval = PyInt_FromLong(val);
-	PyObject *pyname = PyString_FromString(name);
-
-	if (!pyname || !pyval)
-		goto bail;
-
-	PyDict_SetItem(dict, pyname, pyval);
-
-bail:
-	Py_XDECREF(pyname);
-	Py_XDECREF(pyval);
-}
-
-static void define_consts(PyObject *dict)
-{
-	define_const(dict, "IN_ACCESS", IN_ACCESS);
-	define_const(dict, "IN_MODIFY", IN_MODIFY);
-	define_const(dict, "IN_ATTRIB", IN_ATTRIB);
-	define_const(dict, "IN_CLOSE_WRITE", IN_CLOSE_WRITE);
-	define_const(dict, "IN_CLOSE_NOWRITE", IN_CLOSE_NOWRITE);
-	define_const(dict, "IN_OPEN", IN_OPEN);
-	define_const(dict, "IN_MOVED_FROM", IN_MOVED_FROM);
-	define_const(dict, "IN_MOVED_TO", IN_MOVED_TO);
-
-	define_const(dict, "IN_CLOSE", IN_CLOSE);
-	define_const(dict, "IN_MOVE", IN_MOVE);
-
-	define_const(dict, "IN_CREATE", IN_CREATE);
-	define_const(dict, "IN_DELETE", IN_DELETE);
-	define_const(dict, "IN_DELETE_SELF", IN_DELETE_SELF);
-	define_const(dict, "IN_MOVE_SELF", IN_MOVE_SELF);
-	define_const(dict, "IN_UNMOUNT", IN_UNMOUNT);
-	define_const(dict, "IN_Q_OVERFLOW", IN_Q_OVERFLOW);
-	define_const(dict, "IN_IGNORED", IN_IGNORED);
-
-	define_const(dict, "IN_ONLYDIR", IN_ONLYDIR);
-	define_const(dict, "IN_DONT_FOLLOW", IN_DONT_FOLLOW);
-	define_const(dict, "IN_MASK_ADD", IN_MASK_ADD);
-	define_const(dict, "IN_ISDIR", IN_ISDIR);
-	define_const(dict, "IN_ONESHOT", IN_ONESHOT);
-	define_const(dict, "IN_ALL_EVENTS", IN_ALL_EVENTS);
-}
-
-struct event {
-	PyObject_HEAD
-	PyObject *wd;
-	PyObject *mask;
-	PyObject *cookie;
-	PyObject *name;
-};
-
-static PyObject *event_wd(PyObject *self, void *x)
-{
-	struct event *evt = (struct event *)self;
-	Py_INCREF(evt->wd);
-	return evt->wd;
-}
-
-static PyObject *event_mask(PyObject *self, void *x)
-{
-	struct event *evt = (struct event *)self;
-	Py_INCREF(evt->mask);
-	return evt->mask;
-}
-
-static PyObject *event_cookie(PyObject *self, void *x)
-{
-	struct event *evt = (struct event *)self;
-	Py_INCREF(evt->cookie);
-	return evt->cookie;
-}
-
-static PyObject *event_name(PyObject *self, void *x)
-{
-	struct event *evt = (struct event *)self;
-	Py_INCREF(evt->name);
-	return evt->name;
-}
-
-static struct PyGetSetDef event_getsets[] = {
-	{"wd", event_wd, NULL,
-	 "watch descriptor"},
-	{"mask", event_mask, NULL,
-	 "event mask"},
-	{"cookie", event_cookie, NULL,
-	 "rename cookie, if rename-related event"},
-	{"name", event_name, NULL,
-	 "file name"},
-	{NULL}
-};
-
-PyDoc_STRVAR(
-	event_doc,
-	"event: Structure describing an inotify event.");
-
-static PyObject *event_new(PyTypeObject *t, PyObject *a, PyObject *k)
-{
-	return (*t->tp_alloc)(t, 0);
-}
-
-static void event_dealloc(struct event *evt)
-{
-	Py_XDECREF(evt->wd);
-	Py_XDECREF(evt->mask);
-	Py_XDECREF(evt->cookie);
-	Py_XDECREF(evt->name);
-
-	Py_TYPE(evt)->tp_free(evt);
-}
-
-static PyObject *event_repr(struct event *evt)
-{
-	int cookie = evt->cookie == Py_None ? -1 : PyInt_AsLong(evt->cookie);
-	PyObject *ret = NULL, *pymasks = NULL, *pymask = NULL;
-	PyObject *tuple = NULL, *formatstr = NULL;
-
-	pymasks = decode_mask(PyInt_AsLong(evt->mask));
-	if (pymasks == NULL)
-		goto bail;
-
-	pymask = _PyString_Join(join, pymasks);
-	if (pymask == NULL)
-		goto bail;
-
-	if (evt->name != Py_None) {
-		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) {
-			formatstr = er_wm;
-			tuple = PyTuple_Pack(2, evt->wd, pymask);
-		}
-		else {
-			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);
-
-done:
-	Py_XDECREF(pymask);
-	Py_XDECREF(pymasks);
-	Py_XDECREF(tuple);
-
-	return ret;
-}
-
-static PyTypeObject event_type = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	"_inotify.event",             /*tp_name*/
-	sizeof(struct event), /*tp_basicsize*/
-	0,                         /*tp_itemsize*/
-	(destructor)event_dealloc, /*tp_dealloc*/
-	0,                         /*tp_print*/
-	0,                         /*tp_getattr*/
-	0,                         /*tp_setattr*/
-	0,                         /*tp_compare*/
-	(reprfunc)event_repr,      /*tp_repr*/
-	0,                         /*tp_as_number*/
-	0,                         /*tp_as_sequence*/
-	0,                         /*tp_as_mapping*/
-	0,                         /*tp_hash */
-	0,                         /*tp_call*/
-	0,                         /*tp_str*/
-	0,                         /*tp_getattro*/
-	0,                         /*tp_setattro*/
-	0,                         /*tp_as_buffer*/
-	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-	event_doc,           /* tp_doc */
-	0,                         /* tp_traverse */
-	0,                         /* tp_clear */
-	0,                         /* tp_richcompare */
-	0,                         /* tp_weaklistoffset */
-	0,                         /* tp_iter */
-	0,                         /* tp_iternext */
-	0,                         /* tp_methods */
-	0,                         /* tp_members */
-	event_getsets,      /* tp_getset */
-	0,                         /* tp_base */
-	0,                         /* tp_dict */
-	0,                         /* tp_descr_get */
-	0,                         /* tp_descr_set */
-	0,                         /* tp_dictoffset */
-	0,                         /* tp_init */
-	0,                         /* tp_alloc */
-	event_new,          /* tp_new */
-};
-
-PyObject *read_events(PyObject *self, PyObject *args)
-{
-	PyObject *ctor_args = NULL;
-	PyObject *pybufsize = NULL;
-	PyObject *ret = NULL;
-	int bufsize = 65536;
-	char *buf = NULL;
-	int nread, pos;
-	int fd;
-
-	if (!PyArg_ParseTuple(args, "i|O:read", &fd, &pybufsize))
-		goto bail;
-
-	if (pybufsize && pybufsize != Py_None)
-		bufsize = PyInt_AsLong(pybufsize);
-
-	ret = PyList_New(0);
-	if (ret == NULL)
-		goto bail;
-
-	if (bufsize <= 0) {
-		int r;
-
-		Py_BEGIN_ALLOW_THREADS;
-		r = ioctl(fd, FIONREAD, &bufsize);
-		Py_END_ALLOW_THREADS;
-
-		if (r == -1) {
-			PyErr_SetFromErrno(PyExc_OSError);
-			goto bail;
-		}
-		if (bufsize == 0)
-			goto done;
-	}
-	else {
-		static long name_max;
-		static long name_fd = -1;
-		long min;
-
-		if (name_fd != fd) {
-			name_fd = fd;
-			Py_BEGIN_ALLOW_THREADS;
-			name_max = fpathconf(fd, _PC_NAME_MAX);
-			Py_END_ALLOW_THREADS;
-		}
-
-		min = sizeof(struct inotify_event) + name_max + 1;
-
-		if (bufsize < min) {
-			PyErr_Format(PyExc_ValueError,
-				     "bufsize must be at least %d", (int)min);
-			goto bail;
-		}
-	}
-
-	buf = alloca(bufsize);
-
-	Py_BEGIN_ALLOW_THREADS;
-	nread = read(fd, buf, bufsize);
-	Py_END_ALLOW_THREADS;
-
-	if (nread == -1) {
-		PyErr_SetFromErrno(PyExc_OSError);
-		goto bail;
-	}
-
-	ctor_args = PyTuple_New(0);
-
-	if (ctor_args == NULL)
-		goto bail;
-
-	pos = 0;
-
-	while (pos < nread) {
-		struct inotify_event *in = (struct inotify_event *)(buf + pos);
-		struct event *evt;
-		PyObject *obj;
-
-		obj = PyObject_CallObject((PyObject *)&event_type, ctor_args);
-
-		if (obj == NULL)
-			goto bail;
-
-		evt = (struct event *)obj;
-
-		evt->wd = PyInt_FromLong(in->wd);
-		evt->mask = PyInt_FromLong(in->mask);
-		if (in->mask & IN_MOVE)
-			evt->cookie = PyInt_FromLong(in->cookie);
-		else {
-			Py_INCREF(Py_None);
-			evt->cookie = Py_None;
-		}
-		if (in->len)
-			evt->name = PyString_FromString(in->name);
-		else {
-			Py_INCREF(Py_None);
-			evt->name = Py_None;
-		}
-
-		if (!evt->wd || !evt->mask || !evt->cookie || !evt->name)
-			goto mybail;
-
-		if (PyList_Append(ret, obj) == -1)
-			goto mybail;
-
-		pos += sizeof(struct inotify_event) + in->len;
-		continue;
-
-	mybail:
-		Py_CLEAR(evt->wd);
-		Py_CLEAR(evt->mask);
-		Py_CLEAR(evt->cookie);
-		Py_CLEAR(evt->name);
-		Py_DECREF(obj);
-
-		goto bail;
-	}
-
-	goto done;
-
-bail:
-	Py_CLEAR(ret);
-
-done:
-	Py_XDECREF(ctor_args);
-
-	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"
-	"\n"
-	"\nRead inotify events from a file descriptor.\n"
-	"\n"
-	"        fd: file descriptor returned by init()\n"
-	"        bufsize: size of buffer to read into, in bytes\n"
-	"\n"
-	"Return a list of event objects.\n"
-	"\n"
-	"If bufsize is > 0, block until events are available to be read.\n"
-	"Otherwise, immediately return all events that can be read without\n"
-	"blocking.");
-
-static PyMethodDef methods[] = {
-	{"init", init, METH_VARARGS, init_doc},
-	{"add_watch", add_watch, METH_VARARGS, add_watch_doc},
-	{"remove_watch", remove_watch, METH_VARARGS, remove_watch_doc},
-	{"read", read_events, METH_VARARGS, read_doc},
-	{"decode_mask", pydecode_mask, METH_VARARGS, decode_mask_doc},
-	{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;
-
-	if (PyType_Ready(&event_type) == -1)
-		return;
-
-	if (!init_globals())
-		return;
-
-	mod = Py_InitModule3("_inotify", methods, doc);
-
-	dict = PyModule_GetDict(mod);
-
-	if (dict)
-		define_consts(dict);
-}
-#endif
--- a/hgext/inotify/linux/watcher.py	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,335 +0,0 @@
-# watcher.py - high-level interfaces to the Linux inotify subsystem
-
-# Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
-
-# This library is free software; you can redistribute it and/or modify
-# it under the terms of version 2.1 of the GNU Lesser General Public
-# License, or any later version.
-
-'''High-level interfaces to the Linux inotify subsystem.
-
-The inotify subsystem provides an efficient mechanism for file status
-monitoring and change notification.
-
-The watcher class hides the low-level details of the inotify
-interface, and provides a Pythonic wrapper around it.  It generates
-events that provide somewhat more information than raw inotify makes
-available.
-
-The autowatcher class is more useful, as it automatically watches
-newly-created directories on your behalf.'''
-
-__author__ = "Bryan O'Sullivan <bos@serpentine.com>"
-
-import _inotify as inotify
-import array
-import errno
-import fcntl
-import os
-import termios
-
-
-class event(object):
-    '''Derived inotify event class.
-
-    The following fields are available:
-
-        mask: event mask, indicating what kind of event this is
-
-        cookie: rename cookie, if a rename-related event
-
-        path: path of the directory in which the event occurred
-
-        name: name of the directory entry to which the event occurred
-        (may be None if the event happened to a watched directory)
-
-        fullpath: complete path at which the event occurred
-
-        wd: watch descriptor that triggered this event'''
-
-    __slots__ = (
-        'cookie',
-        'fullpath',
-        'mask',
-        'name',
-        'path',
-        'raw',
-        'wd',
-        )
-
-    def __init__(self, raw, path):
-        self.path = path
-        self.raw = raw
-        if raw.name:
-            self.fullpath = path + '/' + raw.name
-        else:
-            self.fullpath = path
-
-        self.wd = raw.wd
-        self.mask = raw.mask
-        self.cookie = raw.cookie
-        self.name = raw.name
-
-    def __repr__(self):
-        r = repr(self.raw)
-        return 'event(path=' + repr(self.path) + ', ' + r[r.find('(') + 1:]
-
-
-_event_props = {
-    'access': 'File was accessed',
-    'modify': 'File was modified',
-    'attrib': 'Attribute of a directory entry was changed',
-    'close_write': 'File was closed after being written to',
-    'close_nowrite': 'File was closed without being written to',
-    'open': 'File was opened',
-    'moved_from': 'Directory entry was renamed from this name',
-    'moved_to': 'Directory entry was renamed to this name',
-    'create': 'Directory entry was created',
-    'delete': 'Directory entry was deleted',
-    'delete_self': 'The watched directory entry was deleted',
-    'move_self': 'The watched directory entry was renamed',
-    'unmount': 'Directory was unmounted, and can no longer be watched',
-    'q_overflow': 'Kernel dropped events due to queue overflow',
-    'ignored': 'Directory entry is no longer being watched',
-    'isdir': 'Event occurred on a directory',
-    }
-
-for k, v in _event_props.iteritems():
-    mask = getattr(inotify, 'IN_' + k.upper())
-    def getter(self):
-        return self.mask & mask
-    getter.__name__ = k
-    getter.__doc__ = v
-    setattr(event, k, property(getter, doc=v))
-
-del _event_props
-
-
-class watcher(object):
-    '''Provide a Pythonic interface to the low-level inotify API.
-
-    Also adds derived information to each event that is not available
-    through the normal inotify API, such as directory name.'''
-
-    __slots__ = (
-        'fd',
-        '_paths',
-        '_wds',
-        )
-
-    def __init__(self):
-        '''Create a new inotify instance.'''
-
-        self.fd = inotify.init()
-        self._paths = {}
-        self._wds = {}
-
-    def fileno(self):
-        '''Return the file descriptor this watcher uses.
-
-        Useful for passing to select and poll.'''
-
-        return self.fd
-
-    def add(self, path, mask):
-        '''Add or modify a watch.
-
-        Return the watch descriptor added or modified.'''
-
-        path = os.path.normpath(path)
-        wd = inotify.add_watch(self.fd, path, mask)
-        self._paths[path] = wd, mask
-        self._wds[wd] = path, mask
-        return wd
-
-    def remove(self, wd):
-        '''Remove the given watch.'''
-
-        inotify.remove_watch(self.fd, wd)
-        self._remove(wd)
-
-    def _remove(self, wd):
-        path_mask = self._wds.pop(wd, None)
-        if path_mask is not None:
-            self._paths.pop(path_mask[0])
-
-    def path(self, path):
-        '''Return a (watch descriptor, event mask) pair for the given path.
-
-        If the path is not being watched, return None.'''
-
-        return self._paths.get(path)
-
-    def wd(self, wd):
-        '''Return a (path, event mask) pair for the given watch descriptor.
-
-        If the watch descriptor is not valid or not associated with
-        this watcher, return None.'''
-
-        return self._wds.get(wd)
-
-    def read(self, bufsize=None):
-        '''Read a list of queued inotify events.
-
-        If bufsize is zero, only return those events that can be read
-        immediately without blocking.  Otherwise, block until events are
-        available.'''
-
-        events = []
-        for evt in inotify.read(self.fd, bufsize):
-            events.append(event(evt, self._wds[evt.wd][0]))
-            if evt.mask & inotify.IN_IGNORED:
-                self._remove(evt.wd)
-            elif evt.mask & inotify.IN_UNMOUNT:
-                self.close()
-        return events
-
-    def close(self):
-        '''Shut down this watcher.
-
-        All subsequent method calls are likely to raise exceptions.'''
-
-        os.close(self.fd)
-        self.fd = None
-        self._paths = None
-        self._wds = None
-
-    def __len__(self):
-        '''Return the number of active watches.'''
-
-        return len(self._paths)
-
-    def __iter__(self):
-        '''Yield a (path, watch descriptor, event mask) tuple for each
-        entry being watched.'''
-
-        for path, (wd, mask) in self._paths.iteritems():
-            yield path, wd, mask
-
-    def __del__(self):
-        if self.fd is not None:
-            os.close(self.fd)
-
-    ignored_errors = [errno.ENOENT, errno.EPERM, errno.ENOTDIR]
-
-    def add_iter(self, path, mask, onerror=None):
-        '''Add or modify watches over path and its subdirectories.
-
-        Yield each added or modified watch descriptor.
-
-        To ensure that this method runs to completion, you must
-        iterate over all of its results, even if you do not care what
-        they are.  For example:
-
-            for wd in w.add_iter(path, mask):
-                pass
-
-        By default, errors are ignored.  If optional arg "onerror" is
-        specified, it should be a function; it will be called with one
-        argument, an OSError instance.  It can report the error to
-        continue with the walk, or raise the exception to abort the
-        walk.'''
-
-        # Add the IN_ONLYDIR flag to the event mask, to avoid a possible
-        # race when adding a subdirectory.  In the time between the
-        # event being queued by the kernel and us processing it, the
-        # directory may have been deleted, or replaced with a different
-        # kind of entry with the same name.
-
-        submask = mask | inotify.IN_ONLYDIR
-
-        try:
-            yield self.add(path, mask)
-        except OSError, err:
-            if onerror and err.errno not in self.ignored_errors:
-                onerror(err)
-        for root, dirs, names in os.walk(path, topdown=False, onerror=onerror):
-            for d in dirs:
-                try:
-                    yield self.add(root + '/' + d, submask)
-                except OSError, err:
-                    if onerror and err.errno not in self.ignored_errors:
-                        onerror(err)
-
-    def add_all(self, path, mask, onerror=None):
-        '''Add or modify watches over path and its subdirectories.
-
-        Return a list of added or modified watch descriptors.
-
-        By default, errors are ignored.  If optional arg "onerror" is
-        specified, it should be a function; it will be called with one
-        argument, an OSError instance.  It can report the error to
-        continue with the walk, or raise the exception to abort the
-        walk.'''
-
-        return [w for w in self.add_iter(path, mask, onerror)]
-
-
-class autowatcher(watcher):
-    '''watcher class that automatically watches newly created directories.'''
-
-    __slots__ = (
-        'addfilter',
-        )
-
-    def __init__(self, addfilter=None):
-        '''Create a new inotify instance.
-
-        This instance will automatically watch newly created
-        directories.
-
-        If the optional addfilter parameter is not None, it must be a
-        callable that takes one parameter.  It will be called each time
-        a directory is about to be automatically watched.  If it returns
-        True, the directory will be watched if it still exists,
-        otherwise, it will be skipped.'''
-
-        super(autowatcher, self).__init__()
-        self.addfilter = addfilter
-
-    _dir_create_mask = inotify.IN_ISDIR | inotify.IN_CREATE
-
-    def read(self, bufsize=None):
-        events = super(autowatcher, self).read(bufsize)
-        for evt in events:
-            if evt.mask & self._dir_create_mask == self._dir_create_mask:
-                if self.addfilter is None or self.addfilter(evt):
-                    parentmask = self._wds[evt.wd][1]
-                    # See note about race avoidance via IN_ONLYDIR above.
-                    mask = parentmask | inotify.IN_ONLYDIR
-                    try:
-                        self.add_all(evt.fullpath, mask)
-                    except OSError, err:
-                        if err.errno not in self.ignored_errors:
-                            raise
-        return events
-
-
-class threshold(object):
-    '''Class that indicates whether a file descriptor has reached a
-    threshold of readable bytes available.
-
-    This class is not thread-safe.'''
-
-    __slots__ = (
-        'fd',
-        'threshold',
-        '_iocbuf',
-        )
-
-    def __init__(self, fd, threshold=1024):
-        self.fd = fd
-        self.threshold = threshold
-        self._iocbuf = array.array('i', [0])
-
-    def readable(self):
-        '''Return the number of bytes readable on this file descriptor.'''
-
-        fcntl.ioctl(self.fd, termios.FIONREAD, self._iocbuf, True)
-        return self._iocbuf[0]
-
-    def __call__(self):
-        '''Indicate whether the number of readable bytes has met or
-        exceeded the threshold.'''
-
-        return self.readable() >= self.threshold
--- a/hgext/inotify/linuxserver.py	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,437 +0,0 @@
-# linuxserver.py - inotify status server for linux
-#
-# Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
-# Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from mercurial.i18n import _
-from mercurial import osutil, util, error
-import server
-import errno, os, select, stat, sys, time
-
-try:
-    import linux as inotify
-    from linux import watcher
-except ImportError:
-    raise
-
-def walkrepodirs(dirstate, absroot):
-    '''Iterate over all subdirectories of this repo.
-    Exclude the .hg directory, any nested repos, and ignored dirs.'''
-    def walkit(dirname, top):
-        fullpath = server.join(absroot, dirname)
-        try:
-            for name, kind in osutil.listdir(fullpath):
-                if kind == stat.S_IFDIR:
-                    if name == '.hg':
-                        if not top:
-                            return
-                    else:
-                        d = server.join(dirname, name)
-                        if dirstate._ignore(d):
-                            continue
-                        for subdir in walkit(d, False):
-                            yield subdir
-        except OSError, err:
-            if err.errno not in server.walk_ignored_errors:
-                raise
-        yield fullpath
-
-    return walkit('', True)
-
-def _explain_watch_limit(ui, dirstate, rootabs):
-    path = '/proc/sys/fs/inotify/max_user_watches'
-    try:
-        limit = int(util.readfile(path))
-    except IOError, err:
-        if err.errno != errno.ENOENT:
-            raise
-        raise util.Abort(_('this system does not seem to '
-                           'support inotify'))
-    ui.warn(_('*** the current per-user limit on the number '
-              'of inotify watches is %s\n') % limit)
-    ui.warn(_('*** this limit is too low to watch every '
-              'directory in this repository\n'))
-    ui.warn(_('*** counting directories: '))
-    ndirs = len(list(walkrepodirs(dirstate, rootabs)))
-    ui.warn(_('found %d\n') % ndirs)
-    newlimit = min(limit, 1024)
-    while newlimit < ((limit + ndirs) * 1.1):
-        newlimit *= 2
-    ui.warn(_('*** to raise the limit from %d to %d (run as root):\n') %
-            (limit, newlimit))
-    ui.warn(_('***  echo %d > %s\n') % (newlimit, path))
-    raise util.Abort(_('cannot watch %s until inotify watch limit is raised')
-                     % rootabs)
-
-class pollable(object):
-    """
-    Interface to support polling.
-    The file descriptor returned by fileno() is registered to a polling
-    object.
-    Usage:
-        Every tick, check if an event has happened since the last tick:
-        * If yes, call handle_events
-        * If no, call handle_timeout
-    """
-    poll_events = select.POLLIN
-    instances = {}
-    poll = select.poll()
-
-    def fileno(self):
-        raise NotImplementedError
-
-    def handle_events(self, events):
-        raise NotImplementedError
-
-    def handle_timeout(self):
-        raise NotImplementedError
-
-    def shutdown(self):
-        raise NotImplementedError
-
-    def register(self, timeout):
-        fd = self.fileno()
-
-        pollable.poll.register(fd, pollable.poll_events)
-        pollable.instances[fd] = self
-
-        self.registered = True
-        self.timeout = timeout
-
-    def unregister(self):
-        pollable.poll.unregister(self)
-        self.registered = False
-
-    @classmethod
-    def run(cls):
-        while True:
-            timeout = None
-            timeobj = None
-            for obj in cls.instances.itervalues():
-                if obj.timeout is not None and (timeout is None
-                                                or obj.timeout < timeout):
-                    timeout, timeobj = obj.timeout, obj
-            try:
-                events = cls.poll.poll(timeout)
-            except select.error, err:
-                if err.args[0] == errno.EINTR:
-                    continue
-                raise
-            if events:
-                by_fd = {}
-                for fd, event in events:
-                    by_fd.setdefault(fd, []).append(event)
-
-                for fd, events in by_fd.iteritems():
-                    cls.instances[fd].handle_pollevents(events)
-
-            elif timeobj:
-                timeobj.handle_timeout()
-
-def eventaction(code):
-    """
-    Decorator to help handle events in repowatcher
-    """
-    def decorator(f):
-        def wrapper(self, wpath):
-            if code == 'm' and wpath in self.lastevent and \
-                self.lastevent[wpath] in 'cm':
-                return
-            self.lastevent[wpath] = code
-            self.timeout = 250
-
-            f(self, wpath)
-
-        wrapper.func_name = f.func_name
-        return wrapper
-    return decorator
-
-class repowatcher(server.repowatcher, pollable):
-    """
-    Watches inotify events
-    """
-    mask = (
-        inotify.IN_ATTRIB |
-        inotify.IN_CREATE |
-        inotify.IN_DELETE |
-        inotify.IN_DELETE_SELF |
-        inotify.IN_MODIFY |
-        inotify.IN_MOVED_FROM |
-        inotify.IN_MOVED_TO |
-        inotify.IN_MOVE_SELF |
-        inotify.IN_ONLYDIR |
-        inotify.IN_UNMOUNT |
-        0)
-
-    def __init__(self, ui, dirstate, root):
-        server.repowatcher.__init__(self, ui, dirstate, root)
-
-        self.lastevent = {}
-        self.dirty = False
-        try:
-            self.watcher = watcher.watcher()
-        except OSError, err:
-            raise util.Abort(_('inotify service not available: %s') %
-                             err.strerror)
-        self.threshold = watcher.threshold(self.watcher)
-        self.fileno = self.watcher.fileno
-        self.register(timeout=None)
-
-        self.handle_timeout()
-        self.scan()
-
-    def event_time(self):
-        last = self.last_event
-        now = time.time()
-        self.last_event = now
-
-        if last is None:
-            return 'start'
-        delta = now - last
-        if delta < 5:
-            return '+%.3f' % delta
-        if delta < 50:
-            return '+%.2f' % delta
-        return '+%.1f' % delta
-
-    def add_watch(self, path, mask):
-        if not path:
-            return
-        if self.watcher.path(path) is None:
-            if self.ui.debugflag:
-                self.ui.note(_('watching %r\n') % path[self.prefixlen:])
-            try:
-                self.watcher.add(path, mask)
-            except OSError, err:
-                if err.errno in (errno.ENOENT, errno.ENOTDIR):
-                    return
-                if err.errno != errno.ENOSPC:
-                    raise
-                _explain_watch_limit(self.ui, self.dirstate, self.wprefix)
-
-    def setup(self):
-        self.ui.note(_('watching directories under %r\n') % self.wprefix)
-        self.add_watch(self.wprefix + '.hg', inotify.IN_DELETE)
-
-    def scan(self, topdir=''):
-        ds = self.dirstate._map.copy()
-        self.add_watch(server.join(self.wprefix, topdir), self.mask)
-        for root, dirs, files in server.walk(self.dirstate, self.wprefix,
-                                             topdir):
-            for d in dirs:
-                self.add_watch(server.join(root, d), self.mask)
-            wroot = root[self.prefixlen:]
-            for fn in files:
-                wfn = server.join(wroot, fn)
-                self.updatefile(wfn, self.getstat(wfn))
-                ds.pop(wfn, None)
-        wtopdir = topdir
-        if wtopdir and wtopdir[-1] != '/':
-            wtopdir += '/'
-        for wfn, state in ds.iteritems():
-            if not wfn.startswith(wtopdir):
-                continue
-            try:
-                st = self.stat(wfn)
-            except OSError:
-                status = state[0]
-                self.deletefile(wfn, status)
-            else:
-                self.updatefile(wfn, st)
-        self.check_deleted('!')
-        self.check_deleted('r')
-
-    @eventaction('c')
-    def created(self, wpath):
-        if wpath == '.hgignore':
-            self.update_hgignore()
-        try:
-            st = self.stat(wpath)
-            if stat.S_ISREG(st[0]) or stat.S_ISLNK(st[0]):
-                self.updatefile(wpath, st)
-        except OSError:
-            pass
-
-    @eventaction('m')
-    def modified(self, wpath):
-        if wpath == '.hgignore':
-            self.update_hgignore()
-        try:
-            st = self.stat(wpath)
-            if stat.S_ISREG(st[0]):
-                if self.dirstate[wpath] in 'lmn':
-                    self.updatefile(wpath, st)
-        except OSError:
-            pass
-
-    @eventaction('d')
-    def deleted(self, wpath):
-        if wpath == '.hgignore':
-            self.update_hgignore()
-        elif wpath.startswith('.hg/'):
-            return
-
-        self.deletefile(wpath, self.dirstate[wpath])
-
-    def process_create(self, wpath, evt):
-        if self.ui.debugflag:
-            self.ui.note(_('%s event: created %s\n') %
-                         (self.event_time(), wpath))
-
-        if evt.mask & inotify.IN_ISDIR:
-            self.scan(wpath)
-        else:
-            self.created(wpath)
-
-    def process_delete(self, wpath, evt):
-        if self.ui.debugflag:
-            self.ui.note(_('%s event: deleted %s\n') %
-                         (self.event_time(), wpath))
-
-        if evt.mask & inotify.IN_ISDIR:
-            tree = self.tree.dir(wpath)
-            todelete = [wfn for wfn, ignore in tree.walk('?')]
-            for fn in todelete:
-                self.deletefile(fn, '?')
-            self.scan(wpath)
-        else:
-            self.deleted(wpath)
-
-    def process_modify(self, wpath, evt):
-        if self.ui.debugflag:
-            self.ui.note(_('%s event: modified %s\n') %
-                         (self.event_time(), wpath))
-
-        if not (evt.mask & inotify.IN_ISDIR):
-            self.modified(wpath)
-
-    def process_unmount(self, evt):
-        self.ui.warn(_('filesystem containing %s was unmounted\n') %
-                     evt.fullpath)
-        sys.exit(0)
-
-    def handle_pollevents(self, events):
-        if self.ui.debugflag:
-            self.ui.note(_('%s readable: %d bytes\n') %
-                         (self.event_time(), self.threshold.readable()))
-        if not self.threshold():
-            if self.registered:
-                if self.ui.debugflag:
-                    self.ui.note(_('%s below threshold - unhooking\n') %
-                                 (self.event_time()))
-                self.unregister()
-                self.timeout = 250
-        else:
-            self.read_events()
-
-    def read_events(self, bufsize=None):
-        events = self.watcher.read(bufsize)
-        if self.ui.debugflag:
-            self.ui.note(_('%s reading %d events\n') %
-                         (self.event_time(), len(events)))
-        for evt in events:
-            if evt.fullpath == self.wprefix[:-1]:
-                # events on the root of the repository
-                # itself, e.g. permission changes or repository move
-                continue
-            assert evt.fullpath.startswith(self.wprefix)
-            wpath = evt.fullpath[self.prefixlen:]
-
-            # paths have been normalized, wpath never ends with a '/'
-
-            if wpath.startswith('.hg/') and evt.mask & inotify.IN_ISDIR:
-                # ignore subdirectories of .hg/ (merge, patches...)
-                continue
-            if wpath == ".hg/wlock":
-                if evt.mask & inotify.IN_DELETE:
-                    self.dirstate.invalidate()
-                    self.dirty = False
-                    self.scan()
-                elif evt.mask & inotify.IN_CREATE:
-                    self.dirty = True
-            else:
-                if self.dirty:
-                    continue
-
-                if evt.mask & inotify.IN_UNMOUNT:
-                    self.process_unmount(wpath, evt)
-                elif evt.mask & (inotify.IN_MODIFY | inotify.IN_ATTRIB):
-                    self.process_modify(wpath, evt)
-                elif evt.mask & (inotify.IN_DELETE | inotify.IN_DELETE_SELF |
-                                 inotify.IN_MOVED_FROM):
-                    self.process_delete(wpath, evt)
-                elif evt.mask & (inotify.IN_CREATE | inotify.IN_MOVED_TO):
-                    self.process_create(wpath, evt)
-
-        self.lastevent.clear()
-
-    def handle_timeout(self):
-        if not self.registered:
-            if self.ui.debugflag:
-                self.ui.note(_('%s hooking back up with %d bytes readable\n') %
-                             (self.event_time(), self.threshold.readable()))
-            self.read_events(0)
-            self.register(timeout=None)
-
-        self.timeout = None
-
-    def shutdown(self):
-        self.watcher.close()
-
-    def debug(self):
-        """
-        Returns a sorted list of relatives paths currently watched,
-        for debugging purposes.
-        """
-        return sorted(tuple[0][self.prefixlen:] for tuple in self.watcher)
-
-class socketlistener(server.socketlistener, pollable):
-    """
-    Listens for client queries on unix socket inotify.sock
-    """
-    def __init__(self, ui, root, repowatcher, timeout):
-        server.socketlistener.__init__(self, ui, root, repowatcher, timeout)
-        self.register(timeout=timeout)
-
-    def handle_timeout(self):
-        raise server.TimeoutException
-
-    def handle_pollevents(self, events):
-        for e in events:
-            self.accept_connection()
-
-    def shutdown(self):
-        self.sock.close()
-        self.sock.cleanup()
-
-    def answer_stat_query(self, cs):
-        if self.repowatcher.timeout:
-            # We got a query while a rescan is pending.  Make sure we
-            # rescan before responding, or we could give back a wrong
-            # answer.
-            self.repowatcher.handle_timeout()
-        return server.socketlistener.answer_stat_query(self, cs)
-
-class master(object):
-    def __init__(self, ui, dirstate, root, timeout=None):
-        self.ui = ui
-        self.repowatcher = repowatcher(ui, dirstate, root)
-        self.socketlistener = socketlistener(ui, root, self.repowatcher,
-                                             timeout)
-
-    def shutdown(self):
-        for obj in pollable.instances.itervalues():
-            try:
-                obj.shutdown()
-            except error.SignalInterrupt:
-                pass
-
-    def run(self):
-        self.repowatcher.setup()
-        self.ui.note(_('finished setup\n'))
-        if os.getenv('TIME_STARTUP'):
-            sys.exit(0)
-        pollable.run()
--- a/hgext/inotify/server.py	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,465 +0,0 @@
-# server.py - common entry point for inotify status server
-#
-# Copyright 2009 Nicolas Dumazet <nicdumz@gmail.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from mercurial.i18n import _
-from mercurial import cmdutil, posix, osutil, util
-import common
-
-import errno
-import os
-import socket
-import stat
-import struct
-import sys
-
-class AlreadyStartedException(Exception):
-    pass
-class TimeoutException(Exception):
-    pass
-
-def join(a, b):
-    if a:
-        if a[-1] == '/':
-            return a + b
-        return a + '/' + b
-    return b
-
-def split(path):
-    c = path.rfind('/')
-    if c == -1:
-        return '', path
-    return path[:c], path[c + 1:]
-
-walk_ignored_errors = (errno.ENOENT, errno.ENAMETOOLONG)
-
-def walk(dirstate, absroot, root):
-    '''Like os.walk, but only yields regular files.'''
-
-    # This function is critical to performance during startup.
-
-    def walkit(root, reporoot):
-        files, dirs = [], []
-
-        try:
-            fullpath = join(absroot, root)
-            for name, kind in osutil.listdir(fullpath):
-                if kind == stat.S_IFDIR:
-                    if name == '.hg':
-                        if not reporoot:
-                            return
-                    else:
-                        dirs.append(name)
-                        path = join(root, name)
-                        if dirstate._ignore(path):
-                            continue
-                        for result in walkit(path, False):
-                            yield result
-                elif kind in (stat.S_IFREG, stat.S_IFLNK):
-                    files.append(name)
-            yield fullpath, dirs, files
-
-        except OSError, err:
-            if err.errno == errno.ENOTDIR:
-                # fullpath was a directory, but has since been replaced
-                # by a file.
-                yield fullpath, dirs, files
-            elif err.errno not in walk_ignored_errors:
-                raise
-
-    return walkit(root, root == '')
-
-class directory(object):
-    """
-    Representing a directory
-
-    * path is the relative path from repo root to this directory
-    * files is a dict listing the files in this directory
-        - keys are file names
-        - values are file status
-    * dirs is a dict listing the subdirectories
-        - key are subdirectories names
-        - values are directory objects
-    """
-    def __init__(self, relpath=''):
-        self.path = relpath
-        self.files = {}
-        self.dirs = {}
-
-    def dir(self, relpath):
-        """
-        Returns the directory contained at the relative path relpath.
-        Creates the intermediate directories if necessary.
-        """
-        if not relpath:
-            return self
-        l = relpath.split('/')
-        ret = self
-        while l:
-            next = l.pop(0)
-            try:
-                ret = ret.dirs[next]
-            except KeyError:
-                d = directory(join(ret.path, next))
-                ret.dirs[next] = d
-                ret = d
-        return ret
-
-    def walk(self, states, visited=None):
-        """
-        yield (filename, status) pairs for items in the trees
-        that have status in states.
-        filenames are relative to the repo root
-        """
-        for file, st in self.files.iteritems():
-            if st in states:
-                yield join(self.path, file), st
-        for dir in self.dirs.itervalues():
-            if visited is not None:
-                visited.add(dir.path)
-            for e in dir.walk(states):
-                yield e
-
-    def lookup(self, states, path, visited):
-        """
-        yield root-relative filenames that match path, and whose
-        status are in states:
-        * if path is a file, yield path
-        * if path is a directory, yield directory files
-        * if path is not tracked, yield nothing
-        """
-        if path[-1] == '/':
-            path = path[:-1]
-
-        paths = path.split('/')
-
-        # we need to check separately for last node
-        last = paths.pop()
-
-        tree = self
-        try:
-            for dir in paths:
-                tree = tree.dirs[dir]
-        except KeyError:
-            # path is not tracked
-            visited.add(tree.path)
-            return
-
-        try:
-            # if path is a directory, walk it
-            target = tree.dirs[last]
-            visited.add(target.path)
-            for file, st in target.walk(states, visited):
-                yield file
-        except KeyError:
-            try:
-                if tree.files[last] in states:
-                    # path is a file
-                    visited.add(tree.path)
-                    yield path
-            except KeyError:
-                # path is not tracked
-                pass
-
-class repowatcher(object):
-    """
-    Watches inotify events
-    """
-    statuskeys = 'almr!?'
-
-    def __init__(self, ui, dirstate, root):
-        self.ui = ui
-        self.dirstate = dirstate
-
-        self.wprefix = join(root, '')
-        self.prefixlen = len(self.wprefix)
-
-        self.tree = directory()
-        self.statcache = {}
-        self.statustrees = dict([(s, directory()) for s in self.statuskeys])
-
-        self.ds_info = self.dirstate_info()
-
-        self.last_event = None
-
-
-    def handle_timeout(self):
-        pass
-
-    def dirstate_info(self):
-        try:
-            st = os.lstat(self.wprefix + '.hg/dirstate')
-            return st.st_mtime, st.st_ino
-        except OSError, err:
-            if err.errno != errno.ENOENT:
-                raise
-            return 0, 0
-
-    def filestatus(self, fn, st):
-        try:
-            type_, mode, size, time = self.dirstate._map[fn][:4]
-        except KeyError:
-            type_ = '?'
-        if type_ == 'n':
-            st_mode, st_size, st_mtime = st
-            if size == -1:
-                return 'l'
-            if size and (size != st_size or (mode ^ st_mode) & 0100):
-                return 'm'
-            if time != int(st_mtime):
-                return 'l'
-            return 'n'
-        if type_ == '?' and self.dirstate._dirignore(fn):
-            # we must check not only if the file is ignored, but if any part
-            # of its path match an ignore pattern
-            return 'i'
-        return type_
-
-    def updatefile(self, wfn, osstat):
-        '''
-        update the file entry of an existing file.
-
-        osstat: (mode, size, time) tuple, as returned by os.lstat(wfn)
-        '''
-
-        self._updatestatus(wfn, self.filestatus(wfn, osstat))
-
-    def deletefile(self, wfn, oldstatus):
-        '''
-        update the entry of a file which has been deleted.
-
-        oldstatus: char in statuskeys, status of the file before deletion
-        '''
-        if oldstatus == 'r':
-            newstatus = 'r'
-        elif oldstatus in 'almn':
-            newstatus = '!'
-        else:
-            newstatus = None
-
-        self.statcache.pop(wfn, None)
-        self._updatestatus(wfn, newstatus)
-
-    def _updatestatus(self, wfn, newstatus):
-        '''
-        Update the stored status of a file.
-
-        newstatus: - char in (statuskeys + 'ni'), new status to apply.
-                   - or None, to stop tracking wfn
-        '''
-        root, fn = split(wfn)
-        d = self.tree.dir(root)
-
-        oldstatus = d.files.get(fn)
-        # oldstatus can be either:
-        # - None : fn is new
-        # - a char in statuskeys: fn is a (tracked) file
-
-        if self.ui.debugflag and oldstatus != newstatus:
-            self.ui.note(_('status: %r %s -> %s\n') %
-                             (wfn, oldstatus, newstatus))
-
-        if oldstatus and oldstatus in self.statuskeys \
-            and oldstatus != newstatus:
-            del self.statustrees[oldstatus].dir(root).files[fn]
-
-        if newstatus in (None, 'i'):
-            d.files.pop(fn, None)
-        elif oldstatus != newstatus:
-            d.files[fn] = newstatus
-            if newstatus != 'n':
-                self.statustrees[newstatus].dir(root).files[fn] = newstatus
-
-    def check_deleted(self, key):
-        # Files that had been deleted but were present in the dirstate
-        # may have vanished from the dirstate; we must clean them up.
-        nuke = []
-        for wfn, ignore in self.statustrees[key].walk(key):
-            if wfn not in self.dirstate:
-                nuke.append(wfn)
-        for wfn in nuke:
-            root, fn = split(wfn)
-            del self.statustrees[key].dir(root).files[fn]
-            del self.tree.dir(root).files[fn]
-
-    def update_hgignore(self):
-        # An update of the ignore file can potentially change the
-        # states of all unknown and ignored files.
-
-        # XXX If the user has other ignore files outside the repo, or
-        # changes their list of ignore files at run time, we'll
-        # potentially never see changes to them.  We could get the
-        # client to report to us what ignore data they're using.
-        # But it's easier to do nothing than to open that can of
-        # worms.
-
-        if '_ignore' in self.dirstate.__dict__:
-            delattr(self.dirstate, '_ignore')
-            self.ui.note(_('rescanning due to .hgignore change\n'))
-            self.handle_timeout()
-            self.scan()
-
-    def getstat(self, wpath):
-        try:
-            return self.statcache[wpath]
-        except KeyError:
-            try:
-                return self.stat(wpath)
-            except OSError, err:
-                if err.errno != errno.ENOENT:
-                    raise
-
-    def stat(self, wpath):
-        try:
-            st = os.lstat(join(self.wprefix, wpath))
-            ret = st.st_mode, st.st_size, st.st_mtime
-            self.statcache[wpath] = ret
-            return ret
-        except OSError:
-            self.statcache.pop(wpath, None)
-            raise
-
-class socketlistener(object):
-    """
-    Listens for client queries on unix socket inotify.sock
-    """
-    def __init__(self, ui, root, repowatcher, timeout):
-        self.ui = ui
-        self.repowatcher = repowatcher
-        try:
-            self.sock = posix.unixdomainserver(
-                lambda p: os.path.join(root, '.hg', p),
-                'inotify')
-        except (OSError, socket.error), err:
-            if err.args[0] == errno.EADDRINUSE:
-                raise AlreadyStartedException(_('cannot start: '
-                                                'socket is already bound'))
-            raise
-        self.fileno = self.sock.fileno
-
-    def answer_stat_query(self, cs):
-        names = cs.read().split('\0')
-
-        states = names.pop()
-
-        self.ui.note(_('answering query for %r\n') % states)
-
-        visited = set()
-        if not names:
-            def genresult(states, tree):
-                for fn, state in tree.walk(states):
-                    yield fn
-        else:
-            def genresult(states, tree):
-                for fn in names:
-                    for f in tree.lookup(states, fn, visited):
-                        yield f
-
-        return ['\0'.join(r) for r in [
-            genresult('l', self.repowatcher.statustrees['l']),
-            genresult('m', self.repowatcher.statustrees['m']),
-            genresult('a', self.repowatcher.statustrees['a']),
-            genresult('r', self.repowatcher.statustrees['r']),
-            genresult('!', self.repowatcher.statustrees['!']),
-            '?' in states
-                and genresult('?', self.repowatcher.statustrees['?'])
-                or [],
-            [],
-            'c' in states and genresult('n', self.repowatcher.tree) or [],
-            visited
-            ]]
-
-    def answer_dbug_query(self):
-        return ['\0'.join(self.repowatcher.debug())]
-
-    def accept_connection(self):
-        sock, addr = self.sock.accept()
-
-        cs = common.recvcs(sock)
-        version = ord(cs.read(1))
-
-        if version != common.version:
-            self.ui.warn(_('received query from incompatible client '
-                           'version %d\n') % version)
-            try:
-                # try to send back our version to the client
-                # this way, the client too is informed of the mismatch
-                sock.sendall(chr(common.version))
-            except socket.error:
-                pass
-            return
-
-        type = cs.read(4)
-
-        if type == 'STAT':
-            results = self.answer_stat_query(cs)
-        elif type == 'DBUG':
-            results = self.answer_dbug_query()
-        else:
-            self.ui.warn(_('unrecognized query type: %s\n') % type)
-            return
-
-        try:
-            try:
-                v = chr(common.version)
-
-                sock.sendall(v + type + struct.pack(common.resphdrfmts[type],
-                                            *map(len, results)))
-                sock.sendall(''.join(results))
-            finally:
-                sock.shutdown(socket.SHUT_WR)
-        except socket.error, err:
-            if err.args[0] != errno.EPIPE:
-                raise
-
-if sys.platform.startswith('linux'):
-    import linuxserver as _server
-else:
-    raise ImportError
-
-master = _server.master
-
-def start(ui, dirstate, root, opts):
-    timeout = opts.get('idle_timeout')
-    if timeout:
-        timeout = float(timeout) * 60000
-    else:
-        timeout = None
-
-    class service(object):
-        def init(self):
-            try:
-                self.master = master(ui, dirstate, root, timeout)
-            except AlreadyStartedException, inst:
-                raise util.Abort("inotify-server: %s" % inst)
-
-        def run(self):
-            try:
-                try:
-                    self.master.run()
-                except TimeoutException:
-                    pass
-            finally:
-                self.master.shutdown()
-
-    if 'inserve' not in sys.argv:
-        runargs = util.hgcmd() + ['inserve', '-R', root]
-    else:
-        runargs = util.hgcmd() + sys.argv[1:]
-
-    pidfile = ui.config('inotify', 'pidfile')
-    opts.setdefault('pid_file', '')
-    if opts['daemon'] and pidfile is not None and not opts['pid_file']:
-        opts['pid_file'] = pidfile
-
-    service = service()
-    logfile = ui.config('inotify', 'log')
-
-    appendpid = ui.configbool('inotify', 'appendpid', False)
-
-    ui.debug('starting inotify server: %s\n' % ' '.join(runargs))
-    cmdutil.service(opts, initfn=service.init, runfn=service.run,
-                    logfile=logfile, runargs=runargs, appendpid=appendpid)
--- a/mercurial/extensions.py	Sat Mar 01 21:08:43 2014 -0500
+++ b/mercurial/extensions.py	Sat Mar 01 16:20:15 2014 -0600
@@ -11,7 +11,7 @@
 
 _extensions = {}
 _order = []
-_ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg']
+_ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg', 'inotify']
 
 def extensions(ui=None):
     if ui:
--- a/setup.py	Sat Mar 01 21:08:43 2014 -0500
+++ b/setup.py	Sat Mar 01 16:20:15 2014 -0600
@@ -467,20 +467,6 @@
 
 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
 
-if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
-    # The inotify extension is only usable with Linux 2.6 kernels.
-    # You also need a reasonably recent C library.
-    # In any case, if it fails to build the error will be skipped ('optional').
-    cc = new_compiler()
-    if hasfunction(cc, 'inotify_add_watch'):
-        inotify = Extension('hgext.inotify.linux._inotify',
-                            ['hgext/inotify/linux/_inotify.c'],
-                            ['mercurial'],
-                            depends=common_depends)
-        inotify.optional = True
-        extmodules.append(inotify)
-        packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
-
 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
                              'help/*.txt']}
 
--- a/tests/blacklists/inotify-failures	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-# When --inotify is activated, help output and config changes:
-test-debugcomplete
-test-empty
-test-fncache
-test-globalopts
-test-help
-test-hgrc
-test-inherit-mode
-test-qrecord
-test-strict
-
-# --inotify activates de facto the inotify extension. It does not play well
-# with inotify-specific tests, which activate/deactivate inotify at will:
-test-inotify
-test-inotify-debuginotify
-test-inotify-dirty-dirstate
-test-inotify-issue1208
-test-inotify-issue1371
-test-inotify-issue1542
-test-inotify-issue1556
-test-inotify-lookup
--- a/tests/blacklists/linux-vfat	Sat Mar 01 21:08:43 2014 -0500
+++ b/tests/blacklists/linux-vfat	Sat Mar 01 16:20:15 2014 -0600
@@ -8,14 +8,6 @@
 
 # no sockets or fifos
 test-hup.t
-test-inotify-debuginotify.t
-test-inotify-dirty-dirstate.t
-test-inotify-issue1208.t
-test-inotify-issue1371.t
-test-inotify-issue1542.t
-test-inotify-lookup.t
-test-inotify.t
-test-inotify-issue1556.t
 
 # no hardlinks
 test-hardlinks.t
--- a/tests/hghave.py	Sat Mar 01 21:08:43 2014 -0500
+++ b/tests/hghave.py	Sat Mar 01 16:20:15 2014 -0600
@@ -96,21 +96,6 @@
     finally:
         os.remove(path)
 
-def has_inotify():
-    try:
-        import hgext.inotify.linux.watcher
-    except ImportError:
-        return False
-    name = tempfile.mktemp(dir='.', prefix=tempprefix)
-    sock = socket.socket(socket.AF_UNIX)
-    try:
-        sock.bind(name)
-    except socket.error:
-        return False
-    sock.close()
-    os.unlink(name)
-    return True
-
 def has_fifo():
     if getattr(os, "mkfifo", None) is None:
         return False
@@ -315,7 +300,6 @@
     "gpg": (has_gpg, "gpg client"),
     "hardlink": (has_hardlink, "hardlinks"),
     "icasefs": (has_icasefs, "case insensitive file system"),
-    "inotify": (has_inotify, "inotify extension support"),
     "killdaemons": (has_killdaemons, 'killdaemons.py support'),
     "lsprof": (has_lsprof, "python lsprof module"),
     "mtn": (has_mtn, "monotone client (>= 1.0)"),
--- a/tests/run-tests.py	Sat Mar 01 21:08:43 2014 -0500
+++ b/tests/run-tests.py	Sat Mar 01 16:20:15 2014 -0600
@@ -152,8 +152,6 @@
         help="exit on the first test failure")
     parser.add_option("-H", "--htmlcov", action="store_true",
         help="create an HTML report of the coverage of the files")
-    parser.add_option("--inotify", action="store_true",
-        help="enable inotify extension when running tests")
     parser.add_option("-i", "--interactive", action="store_true",
         help="prompt to accept changed output")
     parser.add_option("-j", "--jobs", type="int",
@@ -344,12 +342,6 @@
     hgrc.write('commit = -d "0 0"\n')
     hgrc.write('shelve = --date "0 0"\n')
     hgrc.write('tag = -d "0 0"\n')
-    if options.inotify:
-        hgrc.write('[extensions]\n')
-        hgrc.write('inotify=\n')
-        hgrc.write('[inotify]\n')
-        hgrc.write('pidfile=daemon.pids')
-        hgrc.write('appendpid=True\n')
     if options.extra_config_opt:
         for opt in options.extra_config_opt:
             section, key = opt.split('.', 1)
--- a/tests/test-check-pyflakes.t	Sat Mar 01 21:08:43 2014 -0500
+++ b/tests/test-check-pyflakes.t	Sat Mar 01 16:20:15 2014 -0600
@@ -16,6 +16,5 @@
   tests/hghave.py:*: 'pygments' imported but unused (glob)
   tests/hghave.py:*: 'ssl' imported but unused (glob)
   contrib/win32/hgwebdir_wsgi.py:*: 'from isapi.install import *' used; unable to detect undefined names (glob)
-  hgext/inotify/linux/__init__.py:*: 'from _inotify import *' used; unable to detect undefined names (glob)
   
 
--- a/tests/test-duplicateoptions.py	Sat Mar 01 21:08:43 2014 -0500
+++ b/tests/test-duplicateoptions.py	Sat Mar 01 16:20:15 2014 -0600
@@ -1,7 +1,7 @@
 import os
 from mercurial import ui, commands, extensions
 
-ignore = set(['highlight', 'inotify', 'win32text', 'factotum'])
+ignore = set(['highlight', 'win32text', 'factotum'])
 
 if os.name != 'nt':
     ignore.add('win32mbcs')
--- a/tests/test-help.t	Sat Mar 01 21:08:43 2014 -0500
+++ b/tests/test-help.t	Sat Mar 01 16:20:15 2014 -0600
@@ -199,7 +199,7 @@
    urls          URL Paths
 
 Test extension help:
-  $ hg help extensions --config extensions.rebase= --config extensions.children= | grep -v inotify
+  $ hg help extensions --config extensions.rebase= --config extensions.children=
   Using Additional Features
   """""""""""""""""""""""""
   
--- a/tests/test-inotify-debuginotify.t	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-
-  $ "$TESTDIR/hghave" inotify || exit 80
-  $ hg init
-  $ echo "[extensions]" >> $HGRCPATH
-  $ echo "inotify=" >> $HGRCPATH
-
-inserve
-
-  $ hg inserve -d --pid-file=hg.pid
-  $ cat hg.pid >> "$DAEMON_PIDS"
-
-let the daemon finish its stuff
-
-  $ sleep 1
-
-empty
-
-  $ hg debuginotify
-  directories being watched:
-    /
-    .hg/
-  $ mkdir a
-  $ sleep 1
-
-only 'a
-
-  $ hg debuginotify
-  directories being watched:
-    /
-    .hg/
-    a/
-  $ rmdir a
-  $ sleep 1
-
-empty again
-
-  $ hg debuginotify
-  directories being watched:
-    /
-    .hg/
-  $ "$TESTDIR/killdaemons.py" hg.pid
--- a/tests/test-inotify-dirty-dirstate.t	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-issues when status queries are issued when dirstate is dirty
-
-  $ "$TESTDIR/hghave" inotify || exit 80
-  $ echo "[extensions]" >> $HGRCPATH
-  $ echo "inotify=" >> $HGRCPATH
-  $ echo "fetch=" >> $HGRCPATH
-
-issue1810: inotify and fetch
-
-  $ hg init test; cd test
-  $ hg inserve -d --pid-file=../hg.pid
-  $ cat ../hg.pid >> "$DAEMON_PIDS"
-  $ echo foo > foo
-  $ hg add
-  adding foo
-  $ hg ci -m foo
-  $ cd ..
-  $ hg --config "inotify.pidfile=../hg2.pid" clone test test2
-  updating to branch default
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ cat ../hg2.pid >> "$DAEMON_PIDS"
-  $ cd test2
-  $ echo bar > bar
-  $ hg add
-  adding bar
-  $ hg ci -m bar
-  $ cd ../test
-  $ echo spam > spam
-  $ hg add
-  adding spam
-  $ hg ci -m spam
-  $ cd ../test2
-  $ hg st
-
-abort, outstanding changes
-
-  $ hg fetch -q
-  $ hg st
-  $ cd ..
-
-issue1719: inotify and mq
-
-  $ echo "mq=" >> $HGRCPATH
-  $ hg init test-1719
-  $ cd test-1719
-
-inserve
-
-  $ hg inserve -d --pid-file=../hg-test-1719.pid
-  $ cat ../hg-test-1719.pid >> "$DAEMON_PIDS"
-  $ echo content > file
-  $ hg add file
-  $ hg qnew -f test.patch
-  $ hg status
-  $ hg qpop
-  popping test.patch
-  patch queue now empty
-
-st should not output anything
-
-  $ hg status
-  $ hg qpush
-  applying test.patch
-  now at: test.patch
-
-st should not output anything
-
-  $ hg status
-  $ hg qrefresh
-  $ hg status
-
-  $ cd ..
--- a/tests/test-inotify-issue1371.t	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-
-  $ "$TESTDIR/hghave" inotify || exit 80
-  $ hg init
-  $ touch a b c d e f
-  $ echo "[extensions]" >> $HGRCPATH
-  $ echo "inotify=" >> $HGRCPATH
-
-inserve
-
-  $ hg inserve -d --pid-file=hg.pid 2>&1
-  $ cat hg.pid >> "$DAEMON_PIDS"
-  $ hg ci -Am m
-  adding a
-  adding b
-  adding c
-  adding d
-  adding e
-  adding f
-  adding hg.pid
-
-let the daemon finish its stuff
-
-  $ sleep 1
-
-eed to test all file operations
-
-  $ hg rm a
-  $ rm b
-  $ echo c >> c
-  $ touch g
-  $ hg add g
-  $ hg mv e h
-  $ hg status
-  M c
-  A g
-  A h
-  R a
-  R e
-  ! b
-  $ sleep 1
-
-Are we able to kill the service? if not, the service died on some error
-
-  $ "$TESTDIR/killdaemons.py" hg.pid
--- a/tests/test-inotify-issue1542.t	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-
-  $ "$TESTDIR/hghave" inotify || exit 80
-  $ hg init
-  $ touch a
-  $ mkdir dir
-  $ touch dir/b
-  $ touch dir/c
-  $ echo "[extensions]" >> $HGRCPATH
-  $ echo "inotify=" >> $HGRCPATH
-  $ hg add dir/c
-
-inserve
-
-  $ hg inserve -d --pid-file=hg.pid 2>&1
-  $ cat hg.pid >> "$DAEMON_PIDS"
-  $ hg st
-  A dir/c
-  ? a
-  ? dir/b
-  ? hg.pid
-
-moving dir out
-
-  $ mv dir ../tmp-test-inotify-issue1542
-
-status
-
-  $ hg st
-  ! dir/c
-  ? a
-  ? hg.pid
-  $ sleep 1
-
-Are we able to kill the service? if not, the service died on some error
-
-  $ "$TESTDIR/killdaemons.py" hg.pid
--- a/tests/test-inotify-issue1556.t	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-
-  $ "$TESTDIR/hghave" inotify || exit 80
-  $ hg init
-  $ touch a b
-  $ hg add a b
-  $ rm b
-
-status without inotify
-
-  $ hg st
-  A a
-  ! b
-  $ echo "[extensions]" >> $HGRCPATH
-  $ echo "inotify=" >> $HGRCPATH
-
-inserve
-
-  $ hg inserve -d --pid-file=hg.pid 2>&1
-  $ cat hg.pid >> "$DAEMON_PIDS"
-
-status
-
-  $ hg st
-  A a
-  ! b
-  ? hg.pid
-  $ sleep 1
-
-Are we able to kill the service? if not, the service died on some error
-
-  $ "$TESTDIR/killdaemons.py" hg.pid
--- a/tests/test-inotify-lookup.t	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-
-  $ "$TESTDIR/hghave" inotify || exit 80
-  $ hg init
-  $ echo "[extensions]" > .hg/hgrc
-  $ echo "inotify=" >> .hg/hgrc
-  $ hg inserve -d --pid-file .hg/inotify.pid
-  $ echo a > a
-  $ hg ci -Aqm0
-  $ hg co -q null
-  $ hg co -q
-  $ hg st
-  $ cat a
-  a
-  $ "$TESTDIR/killdaemons.py" .hg/inotify.pid
--- a/tests/test-inotify.t	Sat Mar 01 21:08:43 2014 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-
-  $ "$TESTDIR/hghave" inotify || exit 80
-  $ hg init repo1
-  $ cd repo1
-  $ touch a b c d e
-  $ mkdir dir
-  $ mkdir dir/bar
-  $ touch dir/x dir/y dir/bar/foo
-  $ hg ci -Am m
-  adding a
-  adding b
-  adding c
-  adding d
-  adding dir/bar/foo
-  adding dir/x
-  adding dir/y
-  adding e
-  $ cd ..
-  $ hg clone repo1 repo2
-  updating to branch default
-  8 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ echo "[extensions]" >> $HGRCPATH
-  $ echo "inotify=" >> $HGRCPATH
-  $ cd repo2
-  $ echo b >> a
-
-check that daemon started automatically works correctly
-and make sure that inotify.pidfile works
-
-  $ hg --config "inotify.pidfile=../hg2.pid" status
-  M a
-
-make sure that pidfile worked. Output should be silent.
-
-  $ "$TESTDIR/killdaemons.py" ../hg2.pid
-  $ cd ../repo1
-
-inserve
-
-  $ hg inserve -d --pid-file=hg.pid
-  $ cat hg.pid >> "$DAEMON_PIDS"
-
-let the daemon finish its stuff
-
-  $ sleep 1
-
-cannot start, already bound
-
-  $ hg inserve
-  abort: inotify-server: cannot start: socket is already bound
-  [255]
-
-issue907
-
-  $ hg status
-  ? hg.pid
-
-clean
-
-  $ hg status -c
-  C a
-  C b
-  C c
-  C d
-  C dir/bar/foo
-  C dir/x
-  C dir/y
-  C e
-
-all
-
-  $ hg status -A
-  ? hg.pid
-  C a
-  C b
-  C c
-  C d
-  C dir/bar/foo
-  C dir/x
-  C dir/y
-  C e
-
-path patterns
-
-  $ echo x > dir/x
-  $ hg status .
-  M dir/x
-  ? hg.pid
-  $ hg status dir
-  M dir/x
-  $ cd dir
-  $ hg status .
-  M x
-  $ cd ..
-
-issue 1375
-testing that we can remove a folder and then add a file with the same name
-issue 1375
-
-  $ mkdir h
-  $ echo h > h/h
-  $ hg ci -Am t
-  adding h/h
-  adding hg.pid
-  $ hg rm h
-  removing h/h
-  $ echo h >h
-  $ hg add h
-  $ hg status
-  A h
-  R h/h
-  $ hg ci -m0
-
-Test for issue1735: inotify watches files in .hg/merge
-
-  $ hg st
-  $ echo a > a
-  $ hg ci -Am a
-  $ hg st
-  $ echo b >> a
-  $ hg ci -m ab
-  $ hg st
-  $ echo c >> a
-  $ hg st
-  M a
-  $ HGMERGE=internal:local hg up 0
-  1 files updated, 1 files merged, 2 files removed, 0 files unresolved
-  $ hg st
-  M a
-  $ HGMERGE=internal:local hg up
-  3 files updated, 1 files merged, 0 files removed, 0 files unresolved
-  $ hg st
-  M a
-
-Test for 1844: "hg ci folder" will not commit all changes beneath "folder"
-
-  $ mkdir 1844
-  $ echo a > 1844/foo
-  $ hg add 1844
-  adding 1844/foo
-  $ hg ci -m 'working'
-  $ echo b >> 1844/foo
-  $ hg ci 1844 -m 'broken'
-
-Test for issue884: "Build products not ignored until .hgignore is touched"
-
-  $ echo '^build$' > .hgignore
-  $ hg add .hgignore
-  $ hg ci .hgignore -m 'ignorelist'
-
-Now, lets add some build products...
-
-  $ mkdir build
-  $ touch build/x
-  $ touch build/y
-
-build/x & build/y shouldn't appear in "hg st"
-
-  $ hg st
-  $ "$TESTDIR/killdaemons.py" hg.pid
-
-  $ cd ..
-
-Ensure that if the repo is in a directory whose name is too long, the
-unix domain socket is reached through a symlink (issue1208).
-
-  $ mkdir 0_3456789_10_456789_20_456789_30_456789_40_456789_50_45678_
-  $ cd 0_3456789_10_456789_20_456789_30_456789_40_456789_50_45678_
-  $ mkdir 60_456789_70_456789_80_456789_90_456789_100_56789_
-  $ cd 60_456789_70_456789_80_456789_90_456789_100_56789_
-
-  $ hg --config inotify.pidfile=hg3.pid clone -q ../../repo1
-  $ readlink repo1/.hg/inotify.sock
-  */inotify.sock (glob)
-
-Trying to start the server a second time should fail as usual.
-
-  $ hg --cwd repo1 inserve
-  abort: inotify-server: cannot start: socket is already bound
-  [255]
-
-  $ "$TESTDIR/killdaemons.py" hg3.pid