##// END OF EJS Templates
inotify: make inotifydirstate.status() returns a tuple of lists....
Greg Ward -
r11628:68a30dae stable
parent child Browse files
Show More
@@ -1,174 +1,174
1 1 # client.py - inotify status client
2 2 #
3 3 # Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
4 4 # Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
5 5 # Copyright 2009 Nicolas Dumazet <nicdumz@gmail.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 from mercurial.i18n import _
11 11 import common, server
12 12 import errno, os, socket, struct
13 13
14 14 class QueryFailed(Exception):
15 15 pass
16 16
17 17 def start_server(function):
18 18 """
19 19 Decorator.
20 20 Tries to call function, if it fails, try to (re)start inotify server.
21 21 Raise QueryFailed if something went wrong
22 22 """
23 23 def decorated_function(self, *args):
24 24 result = None
25 25 try:
26 26 return function(self, *args)
27 27 except (OSError, socket.error), err:
28 28 autostart = self.ui.configbool('inotify', 'autostart', True)
29 29
30 30 if err[0] == errno.ECONNREFUSED:
31 31 self.ui.warn(_('inotify-client: found dead inotify server '
32 32 'socket; removing it\n'))
33 33 os.unlink(os.path.join(self.root, '.hg', 'inotify.sock'))
34 34 if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
35 35 self.ui.debug('(starting inotify server)\n')
36 36 try:
37 37 try:
38 38 server.start(self.ui, self.dirstate, self.root,
39 39 dict(daemon=True, daemon_pipefds=''))
40 40 except server.AlreadyStartedException, inst:
41 41 # another process may have started its own
42 42 # inotify server while this one was starting.
43 43 self.ui.debug(str(inst))
44 44 except Exception, inst:
45 45 self.ui.warn(_('inotify-client: could not start inotify '
46 46 'server: %s\n') % inst)
47 47 else:
48 48 try:
49 49 return function(self, *args)
50 50 except socket.error, err:
51 51 self.ui.warn(_('inotify-client: could not talk to new '
52 52 'inotify server: %s\n') % err[-1])
53 53 elif err[0] in (errno.ECONNREFUSED, errno.ENOENT):
54 54 # silently ignore normal errors if autostart is False
55 55 self.ui.debug('(inotify server not running)\n')
56 56 else:
57 57 self.ui.warn(_('inotify-client: failed to contact inotify '
58 58 'server: %s\n') % err[-1])
59 59
60 60 self.ui.traceback()
61 61 raise QueryFailed('inotify query failed')
62 62
63 63 return decorated_function
64 64
65 65
66 66 class client(object):
67 67 def __init__(self, ui, repo):
68 68 self.ui = ui
69 69 self.dirstate = repo.dirstate
70 70 self.root = repo.root
71 71 self.sock = socket.socket(socket.AF_UNIX)
72 72
73 73 def _connect(self):
74 74 sockpath = os.path.join(self.root, '.hg', 'inotify.sock')
75 75 try:
76 76 self.sock.connect(sockpath)
77 77 except socket.error, err:
78 78 if err[0] == "AF_UNIX path too long":
79 79 sockpath = os.readlink(sockpath)
80 80 self.sock.connect(sockpath)
81 81 else:
82 82 raise
83 83
84 84 def _send(self, type, data):
85 85 """Sends protocol version number, and the data"""
86 86 self.sock.sendall(chr(common.version) + type + data)
87 87
88 88 self.sock.shutdown(socket.SHUT_WR)
89 89
90 90 def _receive(self, type):
91 91 """
92 92 Read data, check version number, extract headers,
93 93 and returns a tuple (data descriptor, header)
94 94 Raises QueryFailed on error
95 95 """
96 96 cs = common.recvcs(self.sock)
97 97 try:
98 98 version = ord(cs.read(1))
99 99 except TypeError:
100 100 # empty answer, assume the server crashed
101 101 self.ui.warn(_('inotify-client: received empty answer from inotify '
102 102 'server'))
103 103 raise QueryFailed('server crashed')
104 104
105 105 if version != common.version:
106 106 self.ui.warn(_('(inotify: received response from incompatible '
107 107 'server version %d)\n') % version)
108 108 raise QueryFailed('incompatible server version')
109 109
110 110 readtype = cs.read(4)
111 111 if readtype != type:
112 112 self.ui.warn(_('(inotify: received \'%s\' response when expecting'
113 113 ' \'%s\')\n') % (readtype, type))
114 114 raise QueryFailed('wrong response type')
115 115
116 116 hdrfmt = common.resphdrfmts[type]
117 117 hdrsize = common.resphdrsizes[type]
118 118 try:
119 119 resphdr = struct.unpack(hdrfmt, cs.read(hdrsize))
120 120 except struct.error:
121 121 raise QueryFailed('unable to retrieve query response headers')
122 122
123 123 return cs, resphdr
124 124
125 125 def query(self, type, req):
126 126 self._connect()
127 127
128 128 self._send(type, req)
129 129
130 130 return self._receive(type)
131 131
132 132 @start_server
133 133 def statusquery(self, names, match, ignored, clean, unknown=True):
134 134
135 135 def genquery():
136 136 for n in names:
137 137 yield n
138 138 states = 'almrx!'
139 139 if ignored:
140 140 raise ValueError('this is insanity')
141 141 if clean:
142 142 states += 'c'
143 143 if unknown:
144 144 states += '?'
145 145 yield states
146 146
147 147 req = '\0'.join(genquery())
148 148
149 149 cs, resphdr = self.query('STAT', req)
150 150
151 151 def readnames(nbytes):
152 152 if nbytes:
153 153 names = cs.read(nbytes)
154 154 if names:
155 155 return filter(match, names.split('\0'))
156 156 return []
157 results = map(readnames, resphdr[:-1])
157 results = tuple(map(readnames, resphdr[:-1]))
158 158
159 159 if names:
160 160 nbytes = resphdr[-1]
161 161 vdirs = cs.read(nbytes)
162 162 if vdirs:
163 163 for vdir in vdirs.split('\0'):
164 164 match.dir(vdir)
165 165
166 166 return results
167 167
168 168 @start_server
169 169 def debugquery(self):
170 170 cs, resphdr = self.query('DBUG', '')
171 171
172 172 nbytes = resphdr[0]
173 173 names = cs.read(nbytes)
174 174 return names.split('\0')
General Comments 0
You need to be logged in to leave comments. Login now