##// END OF EJS Templates
inotify: files is always a list: 'files or []' is redundant...
Nicolas Dumazet -
r8067:b084d6d6 default
parent child Browse files
Show More
@@ -1,127 +1,127 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 _
14 from mercurial.i18n import _
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 hasattr(repo, 'dirstate'):
42 if not hasattr(repo, 'dirstate'):
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, match, ignored, clean, unknown=True):
53 def status(self, match, ignored, clean, unknown=True):
54 files = match.files()
54 files = match.files()
55 if '.' in files:
55 if '.' in files:
56 files = []
56 files = []
57 try:
57 try:
58 if not ignored and not self.inotifyserver:
58 if not ignored and not self.inotifyserver:
59 result = client.query(ui, repo, files, match, False,
59 result = client.query(ui, repo, files, match, False,
60 clean, unknown)
60 clean, unknown)
61 if ui.config('inotify', 'debug'):
61 if ui.config('inotify', 'debug'):
62 r2 = super(inotifydirstate, self).status(
62 r2 = super(inotifydirstate, self).status(
63 match, False, clean, unknown)
63 match, False, clean, unknown)
64 for c,a,b in zip('LMARDUIC', result, r2):
64 for c,a,b in zip('LMARDUIC', result, r2):
65 for f in a:
65 for f in a:
66 if f not in b:
66 if f not in b:
67 ui.warn('*** inotify: %s +%s\n' % (c, f))
67 ui.warn('*** inotify: %s +%s\n' % (c, f))
68 for f in b:
68 for f in b:
69 if f not in a:
69 if f not in a:
70 ui.warn('*** inotify: %s -%s\n' % (c, f))
70 ui.warn('*** inotify: %s -%s\n' % (c, f))
71 result = r2
71 result = r2
72
72
73 if result is not None:
73 if result is not None:
74 return result
74 return result
75 except (OSError, socket.error), err:
75 except (OSError, socket.error), err:
76 autostart = ui.configbool('inotify', 'autostart', True)
76 autostart = ui.configbool('inotify', 'autostart', True)
77
77
78 if err[0] == errno.ECONNREFUSED:
78 if err[0] == errno.ECONNREFUSED:
79 ui.warn(_('(found dead inotify server socket; '
79 ui.warn(_('(found dead inotify server socket; '
80 'removing it)\n'))
80 'removing it)\n'))
81 os.unlink(repo.join('inotify.sock'))
81 os.unlink(repo.join('inotify.sock'))
82 if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
82 if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
83 query = None
83 query = None
84 ui.debug(_('(starting inotify server)\n'))
84 ui.debug(_('(starting inotify server)\n'))
85 try:
85 try:
86 try:
86 try:
87 server.start(ui, repo)
87 server.start(ui, repo)
88 query = client.query
88 query = client.query
89 except server.AlreadyStartedException, inst:
89 except server.AlreadyStartedException, inst:
90 # another process may have started its own
90 # another process may have started its own
91 # inotify server while this one was starting.
91 # inotify server while this one was starting.
92 ui.debug(str(inst))
92 ui.debug(str(inst))
93 query = client.query
93 query = client.query
94 except Exception, inst:
94 except Exception, inst:
95 ui.warn(_('could not start inotify server: '
95 ui.warn(_('could not start inotify server: '
96 '%s\n') % inst)
96 '%s\n') % inst)
97 if query:
97 if query:
98 try:
98 try:
99 return query(ui, repo, files or [], match,
99 return query(ui, repo, files, match,
100 ignored, clean, unknown)
100 ignored, clean, unknown)
101 except socket.error, err:
101 except socket.error, err:
102 ui.warn(_('could not talk to new inotify '
102 ui.warn(_('could not talk to new inotify '
103 'server: %s\n') % err[-1])
103 'server: %s\n') % err[-1])
104 elif err[0] in (errno.ECONNREFUSED, errno.ENOENT):
104 elif err[0] in (errno.ECONNREFUSED, errno.ENOENT):
105 # silently ignore normal errors if autostart is False
105 # silently ignore normal errors if autostart is False
106 ui.debug(_('(inotify server not running)\n'))
106 ui.debug(_('(inotify server not running)\n'))
107 else:
107 else:
108 ui.warn(_('failed to contact inotify server: %s\n')
108 ui.warn(_('failed to contact inotify server: %s\n')
109 % err[-1])
109 % err[-1])
110 ui.print_exc()
110 ui.print_exc()
111 # replace by old status function
111 # replace by old status function
112 self.status = super(inotifydirstate, self).status
112 self.status = super(inotifydirstate, self).status
113
113
114 return super(inotifydirstate, self).status(
114 return super(inotifydirstate, self).status(
115 match, ignored, clean, unknown)
115 match, ignored, clean, unknown)
116
116
117 repo.dirstate.__class__ = inotifydirstate
117 repo.dirstate.__class__ = inotifydirstate
118
118
119 cmdtable = {
119 cmdtable = {
120 '^inserve':
120 '^inserve':
121 (serve,
121 (serve,
122 [('d', 'daemon', None, _('run server in background')),
122 [('d', 'daemon', None, _('run server in background')),
123 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
123 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
124 ('t', 'idle-timeout', '', _('minutes to sit idle before exiting')),
124 ('t', 'idle-timeout', '', _('minutes to sit idle before exiting')),
125 ('', 'pid-file', '', _('name of file to write process ID to'))],
125 ('', 'pid-file', '', _('name of file to write process ID to'))],
126 _('hg inserve [OPT]...')),
126 _('hg inserve [OPT]...')),
127 }
127 }
@@ -1,61 +1,61 b''
1 # client.py - inotify status client
1 # client.py - inotify status client
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 from mercurial.i18n import _
9 from mercurial.i18n import _
10 import common
10 import common
11 import os, socket, struct
11 import os, socket, struct
12
12
13 def query(ui, repo, names, match, ignored, clean, unknown=True):
13 def query(ui, repo, names, match, ignored, clean, unknown=True):
14 sock = socket.socket(socket.AF_UNIX)
14 sock = socket.socket(socket.AF_UNIX)
15 sockpath = repo.join('inotify.sock')
15 sockpath = repo.join('inotify.sock')
16 try:
16 try:
17 sock.connect(sockpath)
17 sock.connect(sockpath)
18 except socket.error, err:
18 except socket.error, err:
19 if err[0] == "AF_UNIX path too long":
19 if err[0] == "AF_UNIX path too long":
20 sockpath = os.readlink(sockpath)
20 sockpath = os.readlink(sockpath)
21 sock.connect(sockpath)
21 sock.connect(sockpath)
22 else:
22 else:
23 raise
23 raise
24
24
25 def genquery():
25 def genquery():
26 for n in names or []:
26 for n in names:
27 yield n
27 yield n
28 states = 'almrx!'
28 states = 'almrx!'
29 if ignored:
29 if ignored:
30 raise ValueError('this is insanity')
30 raise ValueError('this is insanity')
31 if clean: states += 'c'
31 if clean: states += 'c'
32 if unknown: states += '?'
32 if unknown: states += '?'
33 yield states
33 yield states
34
34
35 req = '\0'.join(genquery())
35 req = '\0'.join(genquery())
36
36
37 sock.sendall(chr(common.version))
37 sock.sendall(chr(common.version))
38 sock.sendall(req)
38 sock.sendall(req)
39 sock.shutdown(socket.SHUT_WR)
39 sock.shutdown(socket.SHUT_WR)
40
40
41 cs = common.recvcs(sock)
41 cs = common.recvcs(sock)
42 version = ord(cs.read(1))
42 version = ord(cs.read(1))
43
43
44 if version != common.version:
44 if version != common.version:
45 ui.warn(_('(inotify: received response from incompatible server '
45 ui.warn(_('(inotify: received response from incompatible server '
46 'version %d)\n') % version)
46 'version %d)\n') % version)
47 return None
47 return None
48
48
49 try:
49 try:
50 resphdr = struct.unpack(common.resphdrfmt, cs.read(common.resphdrsize))
50 resphdr = struct.unpack(common.resphdrfmt, cs.read(common.resphdrsize))
51 except struct.error:
51 except struct.error:
52 return None
52 return None
53
53
54 def readnames(nbytes):
54 def readnames(nbytes):
55 if nbytes:
55 if nbytes:
56 names = cs.read(nbytes)
56 names = cs.read(nbytes)
57 if names:
57 if names:
58 return filter(match, names.split('\0'))
58 return filter(match, names.split('\0'))
59 return []
59 return []
60
60
61 return map(readnames, resphdr)
61 return map(readnames, resphdr)
General Comments 0
You need to be logged in to leave comments. Login now