##// END OF EJS Templates
inotify: deactivate inotify status on failure...
Benoit Boissinot -
r6996:fecf060f default
parent child Browse files
Show More
@@ -0,0 +1,15 b''
1 #!/bin/sh
2
3 "$TESTDIR/hghave" inotify || exit 80
4
5 echo "[extensions]" >> $HGRCPATH
6 echo "inotify=" >> $HGRCPATH
7
8 p="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
9 hg init $p
10 cd $p
11
12 echo % inserve
13 hg inserve
14 echo % status
15 hg status
@@ -0,0 +1,5 b''
1 % inserve
2 abort: AF_UNIX path too long
3 % status
4 failed to contact inotify server: AF_UNIX path too long
5 deactivating inotify
@@ -1,107 +1,110 b''
1 # __init__.py - inotify-based status acceleration for Linux
1 # __init__.py - inotify-based status acceleration for Linux
2 #
2 #
3 # Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
3 # Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
4 # Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
4 # Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 '''inotify-based status acceleration for Linux systems
9 '''inotify-based status acceleration for Linux systems
10 '''
10 '''
11
11
12 # todo: socket permissions
12 # todo: socket permissions
13
13
14 from mercurial.i18n import gettext as _
14 from mercurial.i18n import gettext as _
15 from mercurial import cmdutil, util
15 from mercurial import cmdutil, util
16 import client, errno, os, server, socket
16 import client, errno, os, server, socket
17 from weakref import proxy
17 from weakref import proxy
18
18
19 def serve(ui, repo, **opts):
19 def serve(ui, repo, **opts):
20 '''start an inotify server for this repository'''
20 '''start an inotify server for this repository'''
21 timeout = opts.get('timeout')
21 timeout = opts.get('timeout')
22 if timeout:
22 if timeout:
23 timeout = float(timeout) * 1e3
23 timeout = float(timeout) * 1e3
24
24
25 class service:
25 class service:
26 def init(self):
26 def init(self):
27 try:
27 try:
28 self.master = server.Master(ui, repo, timeout)
28 self.master = server.Master(ui, repo, timeout)
29 except server.AlreadyStartedException, inst:
29 except server.AlreadyStartedException, inst:
30 raise util.Abort(str(inst))
30 raise util.Abort(str(inst))
31
31
32 def run(self):
32 def run(self):
33 try:
33 try:
34 self.master.run()
34 self.master.run()
35 finally:
35 finally:
36 self.master.shutdown()
36 self.master.shutdown()
37
37
38 service = service()
38 service = service()
39 cmdutil.service(opts, initfn=service.init, runfn=service.run)
39 cmdutil.service(opts, initfn=service.init, runfn=service.run)
40
40
41 def reposetup(ui, repo):
41 def reposetup(ui, repo):
42 if not repo.local():
42 if not repo.local():
43 return
43 return
44
44
45 # XXX: weakref until hg stops relying on __del__
45 # XXX: weakref until hg stops relying on __del__
46 repo = proxy(repo)
46 repo = proxy(repo)
47
47
48 class inotifydirstate(repo.dirstate.__class__):
48 class inotifydirstate(repo.dirstate.__class__):
49 # Set to True if we're the inotify server, so we don't attempt
49 # Set to True if we're the inotify server, so we don't attempt
50 # to recurse.
50 # to recurse.
51 inotifyserver = False
51 inotifyserver = False
52
52
53 def status(self, files, match, list_ignored, list_clean,
53 def status(self, files, match, list_ignored, list_clean,
54 list_unknown=True):
54 list_unknown=True):
55 try:
55 try:
56 if not list_ignored and not self.inotifyserver:
56 if not list_ignored and not self.inotifyserver:
57 result = client.query(ui, repo, files, match, False,
57 result = client.query(ui, repo, files, match, False,
58 list_clean, list_unknown)
58 list_clean, list_unknown)
59 if result is not None:
59 if result is not None:
60 return result
60 return result
61 except socket.error, err:
61 except socket.error, err:
62 if err[0] == errno.ECONNREFUSED:
62 if err[0] == errno.ECONNREFUSED:
63 ui.warn(_('(found dead inotify server socket; '
63 ui.warn(_('(found dead inotify server socket; '
64 'removing it)\n'))
64 'removing it)\n'))
65 os.unlink(repo.join('inotify.sock'))
65 os.unlink(repo.join('inotify.sock'))
66 elif err[0] != errno.ENOENT:
66 if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and \
67 raise
67 ui.configbool('inotify', 'autostart'):
68 if ui.configbool('inotify', 'autostart'):
69 query = None
68 query = None
70 ui.debug(_('(starting inotify server)\n'))
69 ui.debug(_('(starting inotify server)\n'))
71 try:
70 try:
72 server.start(ui, repo)
71 server.start(ui, repo)
73 query = client.query
72 query = client.query
74 except server.AlreadyStartedException, inst:
73 except server.AlreadyStartedException, inst:
75 # another process may have started its own
74 # another process may have started its own
76 # inotify server while this one was starting.
75 # inotify server while this one was starting.
77 ui.debug(str(inst))
76 ui.debug(str(inst))
78 query = client.query
77 query = client.query
79 except Exception, inst:
78 except Exception, inst:
80 ui.warn(_('could not start inotify server: '
79 ui.warn(_('could not start inotify server: '
81 '%s\n') % inst)
80 '%s\n') % inst)
82 ui.print_exc()
83
84 if query:
81 if query:
85 try:
82 try:
86 return query(ui, repo, files or [], match,
83 return query(ui, repo, files or [], match,
87 list_ignored, list_clean, list_unknown)
84 list_ignored, list_clean, list_unknown)
88 except socket.error, err:
85 except socket.error, err:
89 ui.warn(_('could not talk to new inotify '
86 ui.warn(_('could not talk to new inotify '
90 'server: %s\n') % err[1])
87 'server: %s\n') % err[-1])
91 ui.print_exc()
88 else:
89 ui.warn(_('failed to contact inotify server: %s\n')
90 % err[-1])
91 ui.print_exc()
92 # replace by old status function
93 ui.warn(_('deactivating inotify\n'))
94 self.status = super(inotifydirstate, self).status
92
95
93 return super(inotifydirstate, self).status(
96 return super(inotifydirstate, self).status(
94 files, match or util.always, list_ignored, list_clean,
97 files, match or util.always, list_ignored, list_clean,
95 list_unknown)
98 list_unknown)
96
99
97 repo.dirstate.__class__ = inotifydirstate
100 repo.dirstate.__class__ = inotifydirstate
98
101
99 cmdtable = {
102 cmdtable = {
100 '^inserve':
103 '^inserve':
101 (serve,
104 (serve,
102 [('d', 'daemon', None, _('run server in background')),
105 [('d', 'daemon', None, _('run server in background')),
103 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
106 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
104 ('t', 'idle-timeout', '', _('minutes to sit idle before exiting')),
107 ('t', 'idle-timeout', '', _('minutes to sit idle before exiting')),
105 ('', 'pid-file', '', _('name of file to write process ID to'))],
108 ('', 'pid-file', '', _('name of file to write process ID to'))],
106 _('hg inserve [OPT]...')),
109 _('hg inserve [OPT]...')),
107 }
110 }
@@ -1,187 +1,195 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Test the running system for features availability. Exit with zero
2 """Test the running system for features availability. Exit with zero
3 if all features are there, non-zero otherwise. If a feature name is
3 if all features are there, non-zero otherwise. If a feature name is
4 prefixed with "no-", the absence of feature is tested.
4 prefixed with "no-", the absence of feature is tested.
5 """
5 """
6 import optparse
6 import optparse
7 import os
7 import os
8 import re
8 import re
9 import sys
9 import sys
10 import tempfile
10 import tempfile
11
11
12 tempprefix = 'hg-hghave-'
12 tempprefix = 'hg-hghave-'
13
13
14 def matchoutput(cmd, regexp, ignorestatus=False):
14 def matchoutput(cmd, regexp, ignorestatus=False):
15 """Return True if cmd executes successfully and its output
15 """Return True if cmd executes successfully and its output
16 is matched by the supplied regular expression.
16 is matched by the supplied regular expression.
17 """
17 """
18 r = re.compile(regexp)
18 r = re.compile(regexp)
19 fh = os.popen(cmd)
19 fh = os.popen(cmd)
20 s = fh.read()
20 s = fh.read()
21 ret = fh.close()
21 ret = fh.close()
22 return (ignorestatus or ret is None) and r.search(s)
22 return (ignorestatus or ret is None) and r.search(s)
23
23
24 def has_baz():
24 def has_baz():
25 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
25 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
26
26
27 def has_cvs():
27 def has_cvs():
28 re = r'Concurrent Versions System.*?server'
28 re = r'Concurrent Versions System.*?server'
29 return matchoutput('cvs --version 2>&1', re)
29 return matchoutput('cvs --version 2>&1', re)
30
30
31 def has_cvsps():
31 def has_cvsps():
32 return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
32 return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
33
33
34 def has_darcs():
34 def has_darcs():
35 return matchoutput('darcs', r'darcs version', True)
35 return matchoutput('darcs', r'darcs version', True)
36
36
37 def has_mtn():
37 def has_mtn():
38 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
38 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
39 'mtn --version', r'monotone 0\.(\d|[12]\d|3[01])[^\d]', True)
39 'mtn --version', r'monotone 0\.(\d|[12]\d|3[01])[^\d]', True)
40
40
41 def has_eol_in_paths():
41 def has_eol_in_paths():
42 try:
42 try:
43 fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
43 fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
44 os.close(fd)
44 os.close(fd)
45 os.remove(path)
45 os.remove(path)
46 return True
46 return True
47 except:
47 except:
48 return False
48 return False
49
49
50 def has_executablebit():
50 def has_executablebit():
51 fd, path = tempfile.mkstemp(prefix=tempprefix)
51 fd, path = tempfile.mkstemp(prefix=tempprefix)
52 os.close(fd)
52 os.close(fd)
53 try:
53 try:
54 s = os.lstat(path).st_mode
54 s = os.lstat(path).st_mode
55 os.chmod(path, s | 0100)
55 os.chmod(path, s | 0100)
56 return (os.lstat(path).st_mode & 0100 != 0)
56 return (os.lstat(path).st_mode & 0100 != 0)
57 finally:
57 finally:
58 os.remove(path)
58 os.remove(path)
59
59
60 def has_inotify():
61 try:
62 import hgext.inotify.linux.watcher
63 return True
64 except ImportError:
65 return False
66
60 def has_fifo():
67 def has_fifo():
61 return hasattr(os, "mkfifo")
68 return hasattr(os, "mkfifo")
62
69
63 def has_hotshot():
70 def has_hotshot():
64 try:
71 try:
65 # hotshot.stats tests hotshot and many problematic dependencies
72 # hotshot.stats tests hotshot and many problematic dependencies
66 # like profile.
73 # like profile.
67 import hotshot.stats
74 import hotshot.stats
68 return True
75 return True
69 except ImportError:
76 except ImportError:
70 return False
77 return False
71
78
72 def has_lsprof():
79 def has_lsprof():
73 try:
80 try:
74 import _lsprof
81 import _lsprof
75 return True
82 return True
76 except ImportError:
83 except ImportError:
77 return False
84 return False
78
85
79 def has_git():
86 def has_git():
80 return matchoutput('git --version 2>&1', r'^git version')
87 return matchoutput('git --version 2>&1', r'^git version')
81
88
82 def has_svn():
89 def has_svn():
83 return matchoutput('svn --version 2>&1', r'^svn, version') and \
90 return matchoutput('svn --version 2>&1', r'^svn, version') and \
84 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
91 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
85
92
86 def has_svn_bindings():
93 def has_svn_bindings():
87 try:
94 try:
88 import svn.core
95 import svn.core
89 return True
96 return True
90 except ImportError:
97 except ImportError:
91 return False
98 return False
92
99
93 def has_symlink():
100 def has_symlink():
94 return hasattr(os, "symlink")
101 return hasattr(os, "symlink")
95
102
96 def has_tla():
103 def has_tla():
97 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
104 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
98
105
99 def has_unix_permissions():
106 def has_unix_permissions():
100 d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
107 d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
101 try:
108 try:
102 fname = os.path.join(d, 'foo')
109 fname = os.path.join(d, 'foo')
103 for umask in (077, 007, 022):
110 for umask in (077, 007, 022):
104 os.umask(umask)
111 os.umask(umask)
105 f = open(fname, 'w')
112 f = open(fname, 'w')
106 f.close()
113 f.close()
107 mode = os.stat(fname).st_mode
114 mode = os.stat(fname).st_mode
108 os.unlink(fname)
115 os.unlink(fname)
109 if mode & 0777 != ~umask & 0666:
116 if mode & 0777 != ~umask & 0666:
110 return False
117 return False
111 return True
118 return True
112 finally:
119 finally:
113 os.rmdir(d)
120 os.rmdir(d)
114
121
115 def has_pygments():
122 def has_pygments():
116 try:
123 try:
117 import pygments
124 import pygments
118 return True
125 return True
119 except ImportError:
126 except ImportError:
120 return False
127 return False
121
128
122 checks = {
129 checks = {
123 "baz": (has_baz, "GNU Arch baz client"),
130 "baz": (has_baz, "GNU Arch baz client"),
124 "cvs": (has_cvs, "cvs client/server"),
131 "cvs": (has_cvs, "cvs client/server"),
125 "cvsps": (has_cvsps, "cvsps utility"),
132 "cvsps": (has_cvsps, "cvsps utility"),
126 "darcs": (has_darcs, "darcs client"),
133 "darcs": (has_darcs, "darcs client"),
127 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
134 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
128 "execbit": (has_executablebit, "executable bit"),
135 "execbit": (has_executablebit, "executable bit"),
129 "fifo": (has_fifo, "named pipes"),
136 "fifo": (has_fifo, "named pipes"),
130 "git": (has_git, "git command line client"),
137 "git": (has_git, "git command line client"),
131 "hotshot": (has_hotshot, "python hotshot module"),
138 "hotshot": (has_hotshot, "python hotshot module"),
139 "inotify": (has_inotify, "inotify extension support"),
132 "lsprof": (has_lsprof, "python lsprof module"),
140 "lsprof": (has_lsprof, "python lsprof module"),
133 "mtn": (has_mtn, "monotone client (> 0.31)"),
141 "mtn": (has_mtn, "monotone client (> 0.31)"),
142 "pygments": (has_pygments, "Pygments source highlighting library"),
134 "svn": (has_svn, "subversion client and admin tools"),
143 "svn": (has_svn, "subversion client and admin tools"),
135 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
144 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
136 "symlink": (has_symlink, "symbolic links"),
145 "symlink": (has_symlink, "symbolic links"),
137 "tla": (has_tla, "GNU Arch tla client"),
146 "tla": (has_tla, "GNU Arch tla client"),
138 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
147 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
139 "pygments": (has_pygments, "Pygments source highlighting library"),
140 }
148 }
141
149
142 def list_features():
150 def list_features():
143 for name, feature in checks.iteritems():
151 for name, feature in checks.iteritems():
144 desc = feature[1]
152 desc = feature[1]
145 print name + ':', desc
153 print name + ':', desc
146
154
147 parser = optparse.OptionParser("%prog [options] [features]")
155 parser = optparse.OptionParser("%prog [options] [features]")
148 parser.add_option("--list-features", action="store_true",
156 parser.add_option("--list-features", action="store_true",
149 help="list available features")
157 help="list available features")
150 parser.add_option("-q", "--quiet", action="store_true",
158 parser.add_option("-q", "--quiet", action="store_true",
151 help="check features silently")
159 help="check features silently")
152
160
153 if __name__ == '__main__':
161 if __name__ == '__main__':
154 options, args = parser.parse_args()
162 options, args = parser.parse_args()
155 if options.list_features:
163 if options.list_features:
156 list_features()
164 list_features()
157 sys.exit(0)
165 sys.exit(0)
158
166
159 quiet = options.quiet
167 quiet = options.quiet
160
168
161 failures = 0
169 failures = 0
162
170
163 def error(msg):
171 def error(msg):
164 global failures
172 global failures
165 if not quiet:
173 if not quiet:
166 sys.stderr.write(msg + '\n')
174 sys.stderr.write(msg + '\n')
167 failures += 1
175 failures += 1
168
176
169 for feature in args:
177 for feature in args:
170 negate = feature.startswith('no-')
178 negate = feature.startswith('no-')
171 if negate:
179 if negate:
172 feature = feature[3:]
180 feature = feature[3:]
173
181
174 if feature not in checks:
182 if feature not in checks:
175 error('skipped: unknown feature: ' + feature)
183 error('skipped: unknown feature: ' + feature)
176 continue
184 continue
177
185
178 check, desc = checks[feature]
186 check, desc = checks[feature]
179 if not negate and not check():
187 if not negate and not check():
180 error('skipped: missing feature: ' + desc)
188 error('skipped: missing feature: ' + desc)
181 elif negate and check():
189 elif negate and check():
182 error('skipped: system supports %s' % desc)
190 error('skipped: system supports %s' % desc)
183
191
184 if failures != 0:
192 if failures != 0:
185 sys.exit(1)
193 sys.exit(1)
186
194
187
195
General Comments 0
You need to be logged in to leave comments. Login now