Mercurial > hg
annotate hgext/inotify/server.py @ 8599:1f706b1b62f3
inotify: server: refactor updatestatus()
* Instead of one entry point, use two entry points, updatefile()
and deletefile(), both internally calling the helper function _updatestatus
* Do not rely on TypeError to detect the type of oldstatus: use isinstance
* The call updatestatus(wpath, None) in deleted() was a bit particular:
because no osstat and no newstatus was given, the newstatus was determined
using the data stored internally. To replace this exact behavior with the
new code, one would use:
root, fn = self.split(wpath)
d = self.dir(self.tree, root)
self.filedeleted(wpath, d.get(fn))
This, however, duplicates code with _updatestatus(), which led us to an
interesting question: why are we basing ourselves on repowatcher data to
update the status, where everywhere else, we are comparing against dirsate?
There is no reason to do this, which is why the new code is:
self.filedeleted(wpath, self.repo.dirstate[wpath])
Incidentally, after this, the test for issue1371 passes again.
author | Nicolas Dumazet <nicdumz.commits@gmail.com> |
---|---|
date | Sun, 24 May 2009 18:43:05 +0900 |
parents | 67f76a4463ef |
children | d46cdfcecaf1 |
rev | line source |
---|---|
6239 | 1 # server.py - inotify status server |
2 # | |
3 # Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com> | |
4 # Copyright 2007, 2008 Brendan Cully <brendan@kublai.com> | |
5 # | |
8225
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8209
diff
changeset
|
6 # This software may be used and distributed according to the terms of the |
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8209
diff
changeset
|
7 # GNU General Public License version 2, incorporated herein by reference. |
6239 | 8 |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
9 from mercurial.i18n import _ |
7420
b4ac1e2cd38c
inotify: remove unused imports (thanks pyflakes)
Brendan Cully <brendan@kublai.com>
parents:
7351
diff
changeset
|
10 from mercurial import osutil, util |
6239 | 11 import common |
6997
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
12 import errno, os, select, socket, stat, struct, sys, tempfile, time |
6239 | 13 |
14 try: | |
6994
bf727bab38b9
Use relative imports in inotify.server.
Brendan Cully <brendan@kublai.com>
parents:
6287
diff
changeset
|
15 import linux as inotify |
bf727bab38b9
Use relative imports in inotify.server.
Brendan Cully <brendan@kublai.com>
parents:
6287
diff
changeset
|
16 from linux import watcher |
6239 | 17 except ImportError: |
18 raise | |
19 | |
20 class AlreadyStartedException(Exception): pass | |
21 | |
22 def join(a, b): | |
23 if a: | |
24 if a[-1] == '/': | |
25 return a + b | |
26 return a + '/' + b | |
27 return b | |
28 | |
29 walk_ignored_errors = (errno.ENOENT, errno.ENAMETOOLONG) | |
30 | |
31 def walkrepodirs(repo): | |
32 '''Iterate over all subdirectories of this repo. | |
33 Exclude the .hg directory, any nested repos, and ignored dirs.''' | |
34 rootslash = repo.root + os.sep | |
8322
3c6c21eb3416
inotify: inotify.server.walkrepodirs() simplify walking
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8321
diff
changeset
|
35 |
6239 | 36 def walkit(dirname, top): |
8321
ec985dcfd7da
inotify: inotify.server.walkrepodirs() simplify
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8320
diff
changeset
|
37 fullpath = rootslash + dirname |
6239 | 38 try: |
8321
ec985dcfd7da
inotify: inotify.server.walkrepodirs() simplify
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8320
diff
changeset
|
39 for name, kind in osutil.listdir(fullpath): |
6239 | 40 if kind == stat.S_IFDIR: |
41 if name == '.hg': | |
8323
589a82fb02a2
inotify: inotify.server.walk*() cleanup
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8322
diff
changeset
|
42 if not top: |
589a82fb02a2
inotify: inotify.server.walk*() cleanup
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8322
diff
changeset
|
43 return |
6239 | 44 else: |
45 d = join(dirname, name) | |
46 if repo.dirstate._ignore(d): | |
47 continue | |
8322
3c6c21eb3416
inotify: inotify.server.walkrepodirs() simplify walking
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8321
diff
changeset
|
48 for subdir in walkit(d, False): |
3c6c21eb3416
inotify: inotify.server.walkrepodirs() simplify walking
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8321
diff
changeset
|
49 yield subdir |
6239 | 50 except OSError, err: |
51 if err.errno not in walk_ignored_errors: | |
52 raise | |
8324
b923d599c309
inotify: inotify.server.walk*() remove unnecessary var
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8323
diff
changeset
|
53 yield fullpath |
8322
3c6c21eb3416
inotify: inotify.server.walkrepodirs() simplify walking
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8321
diff
changeset
|
54 |
3c6c21eb3416
inotify: inotify.server.walkrepodirs() simplify walking
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8321
diff
changeset
|
55 return walkit('', True) |
6239 | 56 |
57 def walk(repo, root): | |
58 '''Like os.walk, but only yields regular files.''' | |
59 | |
60 # This function is critical to performance during startup. | |
61 | |
62 rootslash = repo.root + os.sep | |
63 | |
64 def walkit(root, reporoot): | |
65 files, dirs = [], [] | |
66 | |
67 try: | |
68 fullpath = rootslash + root | |
69 for name, kind in osutil.listdir(fullpath): | |
70 if kind == stat.S_IFDIR: | |
71 if name == '.hg': | |
8325
f2559645643a
inotify: inotify.server.walk() simplify control flow
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8324
diff
changeset
|
72 if not reporoot: |
8323
589a82fb02a2
inotify: inotify.server.walk*() cleanup
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8322
diff
changeset
|
73 return |
8325
f2559645643a
inotify: inotify.server.walk() simplify control flow
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8324
diff
changeset
|
74 else: |
f2559645643a
inotify: inotify.server.walk() simplify control flow
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8324
diff
changeset
|
75 dirs.append(name) |
8381
f52fcc864df4
inotify: server.walk(): use yield instead of for
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8336
diff
changeset
|
76 path = join(root, name) |
f52fcc864df4
inotify: server.walk(): use yield instead of for
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8336
diff
changeset
|
77 if repo.dirstate._ignore(path): |
f52fcc864df4
inotify: server.walk(): use yield instead of for
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8336
diff
changeset
|
78 continue |
f52fcc864df4
inotify: server.walk(): use yield instead of for
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8336
diff
changeset
|
79 for result in walkit(path, False): |
f52fcc864df4
inotify: server.walk(): use yield instead of for
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8336
diff
changeset
|
80 yield result |
6239 | 81 elif kind in (stat.S_IFREG, stat.S_IFLNK): |
8334
0695288e8c37
inotify: inotify.server.walk() filetype is never used, do not yield it
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8325
diff
changeset
|
82 files.append(name) |
8324
b923d599c309
inotify: inotify.server.walk*() remove unnecessary var
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8323
diff
changeset
|
83 yield fullpath, dirs, files |
6239 | 84 |
85 except OSError, err: | |
86 if err.errno not in walk_ignored_errors: | |
87 raise | |
8320
a1305c1c8d8e
inotify: inotify.server.walk() simplify algorithm
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8319
diff
changeset
|
88 |
a1305c1c8d8e
inotify: inotify.server.walk() simplify algorithm
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8319
diff
changeset
|
89 return walkit(root, root == '') |
6239 | 90 |
91 def _explain_watch_limit(ui, repo, count): | |
92 path = '/proc/sys/fs/inotify/max_user_watches' | |
93 try: | |
94 limit = int(file(path).read()) | |
95 except IOError, err: | |
96 if err.errno != errno.ENOENT: | |
97 raise | |
98 raise util.Abort(_('this system does not seem to ' | |
99 'support inotify')) | |
100 ui.warn(_('*** the current per-user limit on the number ' | |
101 'of inotify watches is %s\n') % limit) | |
102 ui.warn(_('*** this limit is too low to watch every ' | |
103 'directory in this repository\n')) | |
104 ui.warn(_('*** counting directories: ')) | |
105 ndirs = len(list(walkrepodirs(repo))) | |
106 ui.warn(_('found %d\n') % ndirs) | |
107 newlimit = min(limit, 1024) | |
108 while newlimit < ((limit + ndirs) * 1.1): | |
109 newlimit *= 2 | |
110 ui.warn(_('*** to raise the limit from %d to %d (run as root):\n') % | |
111 (limit, newlimit)) | |
112 ui.warn(_('*** echo %d > %s\n') % (newlimit, path)) | |
113 raise util.Abort(_('cannot watch %s until inotify watch limit is raised') | |
114 % repo.root) | |
115 | |
8385
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
116 class repowatcher(object): |
6239 | 117 poll_events = select.POLLIN |
118 statuskeys = 'almr!?' | |
8383
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
119 mask = ( |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
120 inotify.IN_ATTRIB | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
121 inotify.IN_CREATE | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
122 inotify.IN_DELETE | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
123 inotify.IN_DELETE_SELF | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
124 inotify.IN_MODIFY | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
125 inotify.IN_MOVED_FROM | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
126 inotify.IN_MOVED_TO | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
127 inotify.IN_MOVE_SELF | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
128 inotify.IN_ONLYDIR | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
129 inotify.IN_UNMOUNT | |
dcfdcb51ac5c
inotify: make mask a class variable since it's instance-independant
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8382
diff
changeset
|
130 0) |
6239 | 131 |
132 def __init__(self, ui, repo, master): | |
133 self.ui = ui | |
134 self.repo = repo | |
135 self.wprefix = self.repo.wjoin('') | |
136 self.timeout = None | |
137 self.master = master | |
138 try: | |
8385
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
139 self.watcher = watcher.watcher() |
6239 | 140 except OSError, err: |
141 raise util.Abort(_('inotify service not available: %s') % | |
142 err.strerror) | |
8385
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
143 self.threshold = watcher.threshold(self.watcher) |
6239 | 144 self.registered = True |
145 self.fileno = self.watcher.fileno | |
146 | |
147 self.tree = {} | |
148 self.statcache = {} | |
149 self.statustrees = dict([(s, {}) for s in self.statuskeys]) | |
150 | |
151 self.watches = 0 | |
152 self.last_event = None | |
153 | |
154 self.eventq = {} | |
155 self.deferred = 0 | |
156 | |
157 self.ds_info = self.dirstate_info() | |
158 self.scan() | |
159 | |
160 def event_time(self): | |
161 last = self.last_event | |
162 now = time.time() | |
163 self.last_event = now | |
164 | |
165 if last is None: | |
166 return 'start' | |
167 delta = now - last | |
168 if delta < 5: | |
169 return '+%.3f' % delta | |
170 if delta < 50: | |
171 return '+%.2f' % delta | |
172 return '+%.1f' % delta | |
173 | |
174 def dirstate_info(self): | |
175 try: | |
176 st = os.lstat(self.repo.join('dirstate')) | |
177 return st.st_mtime, st.st_ino | |
178 except OSError, err: | |
179 if err.errno != errno.ENOENT: | |
180 raise | |
181 return 0, 0 | |
182 | |
183 def add_watch(self, path, mask): | |
184 if not path: | |
185 return | |
186 if self.watcher.path(path) is None: | |
187 if self.ui.debugflag: | |
188 self.ui.note(_('watching %r\n') % path[len(self.wprefix):]) | |
189 try: | |
190 self.watcher.add(path, mask) | |
191 self.watches += 1 | |
192 except OSError, err: | |
193 if err.errno in (errno.ENOENT, errno.ENOTDIR): | |
194 return | |
195 if err.errno != errno.ENOSPC: | |
196 raise | |
197 _explain_watch_limit(self.ui, self.repo, self.watches) | |
198 | |
199 def setup(self): | |
200 self.ui.note(_('watching directories under %r\n') % self.repo.root) | |
201 self.add_watch(self.repo.path, inotify.IN_DELETE) | |
202 self.check_dirstate() | |
203 | |
204 def wpath(self, evt): | |
205 path = evt.fullpath | |
206 if path == self.repo.root: | |
207 return '' | |
208 if path.startswith(self.wprefix): | |
209 return path[len(self.wprefix):] | |
210 raise 'wtf? ' + path | |
211 | |
212 def dir(self, tree, path): | |
213 if path: | |
214 for name in path.split('/'): | |
8384
483d9b2103da
inotify: dic.setdefault(k, d) ; v = dic[k] --> v = dic.setdefault(k, d)
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8383
diff
changeset
|
215 tree = tree.setdefault(name, {}) |
6239 | 216 return tree |
217 | |
218 def lookup(self, path, tree): | |
219 if path: | |
220 try: | |
221 for name in path.split('/'): | |
222 tree = tree[name] | |
223 except KeyError: | |
7351
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
224 return 'x' |
6239 | 225 except TypeError: |
7351
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
226 return 'd' |
6239 | 227 return tree |
228 | |
229 def split(self, path): | |
230 c = path.rfind('/') | |
231 if c == -1: | |
232 return '', path | |
233 return path[:c], path[c+1:] | |
234 | |
235 def filestatus(self, fn, st): | |
236 try: | |
237 type_, mode, size, time = self.repo.dirstate._map[fn][:4] | |
238 except KeyError: | |
239 type_ = '?' | |
240 if type_ == 'n': | |
241 st_mode, st_size, st_mtime = st | |
7082
be81b4788115
inotify: fix confusion on files in lookup state
Matt Mackall <mpm@selenic.com>
parents:
6998
diff
changeset
|
242 if size == -1: |
be81b4788115
inotify: fix confusion on files in lookup state
Matt Mackall <mpm@selenic.com>
parents:
6998
diff
changeset
|
243 return 'l' |
6239 | 244 if size and (size != st_size or (mode ^ st_mode) & 0100): |
245 return 'm' | |
246 if time != int(st_mtime): | |
247 return 'l' | |
248 return 'n' | |
249 if type_ == '?' and self.repo.dirstate._ignore(fn): | |
250 return 'i' | |
251 return type_ | |
252 | |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
253 def updatefile(self, wfn, osstat): |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
254 ''' |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
255 update the file entry of an existing file. |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
256 |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
257 osstat: (mode, size, time) tuple, as returned by os.lstat(wfn) |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
258 ''' |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
259 |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
260 self._updatestatus(wfn, self.filestatus(wfn, osstat)) |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
261 |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
262 def deletefile(self, wfn, oldstatus): |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
263 ''' |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
264 update the entry of a file which has been deleted. |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
265 |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
266 oldstatus: char in statuskeys, status of the file before deletion |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
267 ''' |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
268 if oldstatus == 'r': |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
269 newstatus = 'r' |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
270 elif oldstatus in 'almn': |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
271 newstatus = '!' |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
272 else: |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
273 newstatus = None |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
274 |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
275 self.statcache.pop(wfn, None) |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
276 self._updatestatus(wfn, newstatus) |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
277 |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
278 def _updatestatus(self, wfn, newstatus): |
8382
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
279 ''' |
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
280 Update the stored status of a file or directory. |
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
281 |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
282 newstatus: - char in (statuskeys + 'ni'), new status to apply. |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
283 - or None, to stop tracking wfn |
8382
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
284 ''' |
6239 | 285 root, fn = self.split(wfn) |
286 d = self.dir(self.tree, root) | |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
287 |
7351
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
288 oldstatus = d.get(fn) |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
289 # oldstatus can be either: |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
290 # - None : fn is new |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
291 # - a char in statuskeys: fn is a (tracked) file |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
292 # - a dict: fn is a directory |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
293 isdir = isinstance(oldstatus, dict) |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
294 |
8382
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
295 if self.ui.debugflag and oldstatus != newstatus: |
6239 | 296 if isdir: |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
297 self.ui.note(_('status: %r dir(%d) -> %s\n') % |
8382
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
298 (wfn, len(oldstatus), newstatus)) |
6239 | 299 else: |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
300 self.ui.note(_('status: %r %s -> %s\n') % |
8382
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
301 (wfn, oldstatus, newstatus)) |
6239 | 302 if not isdir: |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
303 if oldstatus and oldstatus in self.statuskeys \ |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
304 and oldstatus != newstatus: |
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
305 del self.dir(self.statustrees[oldstatus], root)[fn] |
8382
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
306 if newstatus and newstatus != 'i': |
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
307 d[fn] = newstatus |
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
308 if newstatus in self.statuskeys: |
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
309 dd = self.dir(self.statustrees[newstatus], root) |
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
310 if oldstatus != newstatus or fn not in dd: |
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
311 dd[fn] = newstatus |
6239 | 312 else: |
313 d.pop(fn, None) | |
8382
6f44b1adc948
inotify: RepoWatcher.updatestatus: document & use meaningful parameter names
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8381
diff
changeset
|
314 elif not newstatus: |
7892
67e59a9886d5
Fixing issue1542, adding a relevant test
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
7451
diff
changeset
|
315 # a directory is being removed, check its contents |
67e59a9886d5
Fixing issue1542, adding a relevant test
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
7451
diff
changeset
|
316 for subfile, b in oldstatus.copy().iteritems(): |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
317 self._updatestatus(wfn + '/' + subfile, None) |
7892
67e59a9886d5
Fixing issue1542, adding a relevant test
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
7451
diff
changeset
|
318 |
6239 | 319 |
320 def check_deleted(self, key): | |
321 # Files that had been deleted but were present in the dirstate | |
322 # may have vanished from the dirstate; we must clean them up. | |
323 nuke = [] | |
324 for wfn, ignore in self.walk(key, self.statustrees[key]): | |
325 if wfn not in self.repo.dirstate: | |
326 nuke.append(wfn) | |
327 for wfn in nuke: | |
328 root, fn = self.split(wfn) | |
329 del self.dir(self.statustrees[key], root)[fn] | |
330 del self.dir(self.tree, root)[fn] | |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
331 |
6239 | 332 def scan(self, topdir=''): |
333 self.handle_timeout() | |
334 ds = self.repo.dirstate._map.copy() | |
335 self.add_watch(join(self.repo.root, topdir), self.mask) | |
8334
0695288e8c37
inotify: inotify.server.walk() filetype is never used, do not yield it
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8325
diff
changeset
|
336 for root, dirs, files in walk(self.repo, topdir): |
6239 | 337 for d in dirs: |
338 self.add_watch(join(root, d), self.mask) | |
339 wroot = root[len(self.wprefix):] | |
340 d = self.dir(self.tree, wroot) | |
8334
0695288e8c37
inotify: inotify.server.walk() filetype is never used, do not yield it
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8325
diff
changeset
|
341 for fn in files: |
6239 | 342 wfn = join(wroot, fn) |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
343 self.updatefile(wfn, self.getstat(wfn)) |
6239 | 344 ds.pop(wfn, None) |
345 wtopdir = topdir | |
346 if wtopdir and wtopdir[-1] != '/': | |
347 wtopdir += '/' | |
348 for wfn, state in ds.iteritems(): | |
349 if not wfn.startswith(wtopdir): | |
350 continue | |
7302
972737252d05
inotify: server raising an error when removing a file (issue1371)
Gerard Korsten <soonkia77@gmail.com>
parents:
7280
diff
changeset
|
351 try: |
972737252d05
inotify: server raising an error when removing a file (issue1371)
Gerard Korsten <soonkia77@gmail.com>
parents:
7280
diff
changeset
|
352 st = self.stat(wfn) |
972737252d05
inotify: server raising an error when removing a file (issue1371)
Gerard Korsten <soonkia77@gmail.com>
parents:
7280
diff
changeset
|
353 except OSError: |
972737252d05
inotify: server raising an error when removing a file (issue1371)
Gerard Korsten <soonkia77@gmail.com>
parents:
7280
diff
changeset
|
354 status = state[0] |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
355 self.deletefile(wfn, status) |
6239 | 356 else: |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
357 self.updatefile(wfn, st) |
6239 | 358 self.check_deleted('!') |
359 self.check_deleted('r') | |
360 | |
361 def check_dirstate(self): | |
362 ds_info = self.dirstate_info() | |
363 if ds_info == self.ds_info: | |
364 return | |
365 self.ds_info = ds_info | |
366 if not self.ui.debugflag: | |
367 self.last_event = None | |
368 self.ui.note(_('%s dirstate reload\n') % self.event_time()) | |
369 self.repo.dirstate.invalidate() | |
370 self.scan() | |
371 self.ui.note(_('%s end dirstate reload\n') % self.event_time()) | |
372 | |
373 def walk(self, states, tree, prefix=''): | |
374 # This is the "inner loop" when talking to the client. | |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
375 |
6239 | 376 for name, val in tree.iteritems(): |
377 path = join(prefix, name) | |
7351
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
378 try: |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
379 if val in states: |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
380 yield path, val |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
381 except TypeError: |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
382 for p in self.walk(states, val, path): |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
383 yield p |
6239 | 384 |
385 def update_hgignore(self): | |
386 # An update of the ignore file can potentially change the | |
387 # states of all unknown and ignored files. | |
388 | |
389 # XXX If the user has other ignore files outside the repo, or | |
390 # changes their list of ignore files at run time, we'll | |
391 # potentially never see changes to them. We could get the | |
392 # client to report to us what ignore data they're using. | |
393 # But it's easier to do nothing than to open that can of | |
394 # worms. | |
395 | |
7085
1fcc282e2c43
inotify: fixup rebuilding ignore
Matt Mackall <mpm@selenic.com>
parents:
7082
diff
changeset
|
396 if '_ignore' in self.repo.dirstate.__dict__: |
1fcc282e2c43
inotify: fixup rebuilding ignore
Matt Mackall <mpm@selenic.com>
parents:
7082
diff
changeset
|
397 delattr(self.repo.dirstate, '_ignore') |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
398 self.ui.note(_('rescanning due to .hgignore change\n')) |
6239 | 399 self.scan() |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
400 |
6239 | 401 def getstat(self, wpath): |
402 try: | |
403 return self.statcache[wpath] | |
404 except KeyError: | |
405 try: | |
406 return self.stat(wpath) | |
407 except OSError, err: | |
408 if err.errno != errno.ENOENT: | |
409 raise | |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
410 |
6239 | 411 def stat(self, wpath): |
412 try: | |
413 st = os.lstat(join(self.wprefix, wpath)) | |
414 ret = st.st_mode, st.st_size, st.st_mtime | |
415 self.statcache[wpath] = ret | |
416 return ret | |
7280
810ca383da9c
remove unused variables
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7220
diff
changeset
|
417 except OSError: |
6239 | 418 self.statcache.pop(wpath, None) |
419 raise | |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
420 |
6239 | 421 def created(self, wpath): |
422 if wpath == '.hgignore': | |
423 self.update_hgignore() | |
424 try: | |
425 st = self.stat(wpath) | |
426 if stat.S_ISREG(st[0]): | |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
427 self.updatefile(wpath, st) |
7280
810ca383da9c
remove unused variables
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7220
diff
changeset
|
428 except OSError: |
6239 | 429 pass |
430 | |
431 def modified(self, wpath): | |
432 if wpath == '.hgignore': | |
433 self.update_hgignore() | |
434 try: | |
435 st = self.stat(wpath) | |
436 if stat.S_ISREG(st[0]): | |
437 if self.repo.dirstate[wpath] in 'lmn': | |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
438 self.updatefile(wpath, st) |
6239 | 439 except OSError: |
440 pass | |
441 | |
442 def deleted(self, wpath): | |
443 if wpath == '.hgignore': | |
444 self.update_hgignore() | |
445 elif wpath.startswith('.hg/'): | |
446 if wpath == '.hg/wlock': | |
447 self.check_dirstate() | |
448 return | |
449 | |
8599
1f706b1b62f3
inotify: server: refactor updatestatus()
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8557
diff
changeset
|
450 self.deletefile(wpath, self.repo.dirstate[wpath]) |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
451 |
6239 | 452 def schedule_work(self, wpath, evt): |
8384
483d9b2103da
inotify: dic.setdefault(k, d) ; v = dic[k] --> v = dic.setdefault(k, d)
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8383
diff
changeset
|
453 prev = self.eventq.setdefault(wpath, []) |
6239 | 454 try: |
455 if prev and evt == 'm' and prev[-1] in 'cm': | |
456 return | |
457 self.eventq[wpath].append(evt) | |
458 finally: | |
459 self.deferred += 1 | |
460 self.timeout = 250 | |
461 | |
462 def deferred_event(self, wpath, evt): | |
463 if evt == 'c': | |
464 self.created(wpath) | |
465 elif evt == 'm': | |
466 self.modified(wpath) | |
467 elif evt == 'd': | |
468 self.deleted(wpath) | |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
469 |
6239 | 470 def process_create(self, wpath, evt): |
471 if self.ui.debugflag: | |
472 self.ui.note(_('%s event: created %s\n') % | |
473 (self.event_time(), wpath)) | |
474 | |
475 if evt.mask & inotify.IN_ISDIR: | |
476 self.scan(wpath) | |
477 else: | |
478 self.schedule_work(wpath, 'c') | |
479 | |
480 def process_delete(self, wpath, evt): | |
481 if self.ui.debugflag: | |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
482 self.ui.note(_('%s event: deleted %s\n') % |
6239 | 483 (self.event_time(), wpath)) |
484 | |
485 if evt.mask & inotify.IN_ISDIR: | |
486 self.scan(wpath) | |
7892
67e59a9886d5
Fixing issue1542, adding a relevant test
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
7451
diff
changeset
|
487 self.schedule_work(wpath, 'd') |
6239 | 488 |
489 def process_modify(self, wpath, evt): | |
490 if self.ui.debugflag: | |
491 self.ui.note(_('%s event: modified %s\n') % | |
492 (self.event_time(), wpath)) | |
493 | |
494 if not (evt.mask & inotify.IN_ISDIR): | |
495 self.schedule_work(wpath, 'm') | |
496 | |
497 def process_unmount(self, evt): | |
498 self.ui.warn(_('filesystem containing %s was unmounted\n') % | |
499 evt.fullpath) | |
500 sys.exit(0) | |
501 | |
502 def handle_event(self, fd, event): | |
503 if self.ui.debugflag: | |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
504 self.ui.note(_('%s readable: %d bytes\n') % |
6239 | 505 (self.event_time(), self.threshold.readable())) |
506 if not self.threshold(): | |
507 if self.registered: | |
508 if self.ui.debugflag: | |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
509 self.ui.note(_('%s below threshold - unhooking\n') % |
6239 | 510 (self.event_time())) |
511 self.master.poll.unregister(fd) | |
512 self.registered = False | |
513 self.timeout = 250 | |
514 else: | |
515 self.read_events() | |
516 | |
517 def read_events(self, bufsize=None): | |
518 events = self.watcher.read(bufsize) | |
519 if self.ui.debugflag: | |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
520 self.ui.note(_('%s reading %d events\n') % |
6239 | 521 (self.event_time(), len(events))) |
522 for evt in events: | |
523 wpath = self.wpath(evt) | |
524 if evt.mask & inotify.IN_UNMOUNT: | |
525 self.process_unmount(wpath, evt) | |
526 elif evt.mask & (inotify.IN_MODIFY | inotify.IN_ATTRIB): | |
527 self.process_modify(wpath, evt) | |
528 elif evt.mask & (inotify.IN_DELETE | inotify.IN_DELETE_SELF | | |
529 inotify.IN_MOVED_FROM): | |
530 self.process_delete(wpath, evt) | |
531 elif evt.mask & (inotify.IN_CREATE | inotify.IN_MOVED_TO): | |
532 self.process_create(wpath, evt) | |
533 | |
534 def handle_timeout(self): | |
535 if not self.registered: | |
536 if self.ui.debugflag: | |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
537 self.ui.note(_('%s hooking back up with %d bytes readable\n') % |
6239 | 538 (self.event_time(), self.threshold.readable())) |
539 self.read_events(0) | |
540 self.master.poll.register(self, select.POLLIN) | |
541 self.registered = True | |
542 | |
543 if self.eventq: | |
544 if self.ui.debugflag: | |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
545 self.ui.note(_('%s processing %d deferred events as %d\n') % |
6239 | 546 (self.event_time(), self.deferred, |
547 len(self.eventq))) | |
8209
a1a5a57efe90
replace util.sort with sorted built-in
Matt Mackall <mpm@selenic.com>
parents:
7892
diff
changeset
|
548 for wpath, evts in sorted(self.eventq.iteritems()): |
6239 | 549 for evt in evts: |
550 self.deferred_event(wpath, evt) | |
551 self.eventq.clear() | |
552 self.deferred = 0 | |
553 self.timeout = None | |
554 | |
555 def shutdown(self): | |
556 self.watcher.close() | |
557 | |
8555
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
558 def debug(self): |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
559 """ |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
560 Returns a sorted list of relatives paths currently watched, |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
561 for debugging purposes. |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
562 """ |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
563 return sorted(tuple[0][len(self.wprefix):] for tuple in self.watcher) |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
564 |
8385
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
565 class server(object): |
6239 | 566 poll_events = select.POLLIN |
567 | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
568 def __init__(self, ui, repo, repowatcher, timeout): |
6239 | 569 self.ui = ui |
570 self.repo = repo | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
571 self.repowatcher = repowatcher |
6239 | 572 self.timeout = timeout |
573 self.sock = socket.socket(socket.AF_UNIX) | |
574 self.sockpath = self.repo.join('inotify.sock') | |
6997
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
575 self.realsockpath = None |
6239 | 576 try: |
577 self.sock.bind(self.sockpath) | |
578 except socket.error, err: | |
579 if err[0] == errno.EADDRINUSE: | |
6997
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
580 raise AlreadyStartedException(_('could not start server: %s') |
6239 | 581 % err[1]) |
6997
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
582 if err[0] == "AF_UNIX path too long": |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
583 tempdir = tempfile.mkdtemp(prefix="hg-inotify-") |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
584 self.realsockpath = os.path.join(tempdir, "inotify.sock") |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
585 try: |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
586 self.sock.bind(self.realsockpath) |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
587 os.symlink(self.realsockpath, self.sockpath) |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
588 except (OSError, socket.error), inst: |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
589 try: |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
590 os.unlink(self.realsockpath) |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
591 except: |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
592 pass |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
593 os.rmdir(tempdir) |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
594 if inst.errno == errno.EEXIST: |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
595 raise AlreadyStartedException(_('could not start server: %s') |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
596 % inst.strerror) |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
597 raise |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
598 else: |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
599 raise |
6239 | 600 self.sock.listen(5) |
601 self.fileno = self.sock.fileno | |
602 | |
603 def handle_timeout(self): | |
604 pass | |
605 | |
8554
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
606 def answer_stat_query(self, cs): |
6239 | 607 names = cs.read().split('\0') |
6287
c86207d41512
Spacing cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
6239
diff
changeset
|
608 |
6239 | 609 states = names.pop() |
610 | |
611 self.ui.note(_('answering query for %r\n') % states) | |
612 | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
613 if self.repowatcher.timeout: |
6239 | 614 # We got a query while a rescan is pending. Make sure we |
615 # rescan before responding, or we could give back a wrong | |
616 # answer. | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
617 self.repowatcher.handle_timeout() |
6239 | 618 |
619 if not names: | |
620 def genresult(states, tree): | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
621 for fn, state in self.repowatcher.walk(states, tree): |
6239 | 622 yield fn |
623 else: | |
624 def genresult(states, tree): | |
625 for fn in names: | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
626 l = self.repowatcher.lookup(fn, tree) |
7351
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
627 try: |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
628 if l in states: |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
629 yield fn |
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
630 except TypeError: |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
631 for f, s in self.repowatcher.walk(states, l, fn): |
7351
5ab0abf27dd9
Backed out changeset c5dbe86b0fee (issue1375)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7350
diff
changeset
|
632 yield f |
6239 | 633 |
8554
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
634 return ['\0'.join(r) for r in [ |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
635 genresult('l', self.repowatcher.statustrees['l']), |
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
636 genresult('m', self.repowatcher.statustrees['m']), |
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
637 genresult('a', self.repowatcher.statustrees['a']), |
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
638 genresult('r', self.repowatcher.statustrees['r']), |
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
639 genresult('!', self.repowatcher.statustrees['!']), |
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
640 '?' in states |
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
641 and genresult('?', self.repowatcher.statustrees['?']) |
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
642 or [], |
6239 | 643 [], |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
644 'c' in states and genresult('n', self.repowatcher.tree) or [], |
6239 | 645 ]] |
646 | |
8555
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
647 def answer_dbug_query(self): |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
648 return ['\0'.join(self.repowatcher.debug())] |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
649 |
8554
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
650 def handle_event(self, fd, event): |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
651 sock, addr = self.sock.accept() |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
652 |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
653 cs = common.recvcs(sock) |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
654 version = ord(cs.read(1)) |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
655 |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
656 if version != common.version: |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
657 self.ui.warn(_('received query from incompatible client ' |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
658 'version %d\n') % version) |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
659 return |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
660 |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
661 type = cs.read(4) |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
662 |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
663 if type == 'STAT': |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
664 results = self.answer_stat_query(cs) |
8555
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
665 elif type == 'DBUG': |
3e09bc5fee12
inotify: introduce debuginotify, which lists which paths are under watch
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8554
diff
changeset
|
666 results = self.answer_dbug_query() |
8554
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
667 else: |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
668 self.ui.warn(_('unrecognized query type: %s\n') % type) |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
669 return |
47d7347484f5
inotify: put STAT-specific query answer generation part in its own method
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8553
diff
changeset
|
670 |
6239 | 671 try: |
672 try: | |
8386
4aad982111b6
inotify: Abstract the layer format and sizes to a inotify.common dictionary
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8385
diff
changeset
|
673 v = chr(common.version) |
4aad982111b6
inotify: Abstract the layer format and sizes to a inotify.common dictionary
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8385
diff
changeset
|
674 |
8553
e387ecd7a6ed
inotify: change protocol so that different query types can be supported.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8386
diff
changeset
|
675 sock.sendall(v + type + struct.pack(common.resphdrfmts[type], |
e387ecd7a6ed
inotify: change protocol so that different query types can be supported.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8386
diff
changeset
|
676 *map(len, results))) |
6239 | 677 sock.sendall(''.join(results)) |
678 finally: | |
679 sock.shutdown(socket.SHUT_WR) | |
680 except socket.error, err: | |
681 if err[0] != errno.EPIPE: | |
682 raise | |
683 | |
684 def shutdown(self): | |
685 self.sock.close() | |
686 try: | |
687 os.unlink(self.sockpath) | |
6997
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
688 if self.realsockpath: |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
689 os.unlink(self.realsockpath) |
9c4e488f105e
inotify: workaround ENAMETOOLONG by using symlinks
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
6994
diff
changeset
|
690 os.rmdir(os.path.dirname(self.realsockpath)) |
6239 | 691 except OSError, err: |
692 if err.errno != errno.ENOENT: | |
693 raise | |
694 | |
8385
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
695 class master(object): |
6239 | 696 def __init__(self, ui, repo, timeout=None): |
697 self.ui = ui | |
698 self.repo = repo | |
699 self.poll = select.poll() | |
8385
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
700 self.repowatcher = repowatcher(ui, repo, self) |
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
701 self.server = server(ui, repo, self.repowatcher, timeout) |
6239 | 702 self.table = {} |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
703 for obj in (self.repowatcher, self.server): |
6239 | 704 fd = obj.fileno() |
705 self.table[fd] = obj | |
706 self.poll.register(fd, obj.poll_events) | |
707 | |
708 def register(self, fd, mask): | |
709 self.poll.register(fd, mask) | |
710 | |
711 def shutdown(self): | |
712 for obj in self.table.itervalues(): | |
713 obj.shutdown() | |
714 | |
715 def run(self): | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
716 self.repowatcher.setup() |
6239 | 717 self.ui.note(_('finished setup\n')) |
718 if os.getenv('TIME_STARTUP'): | |
719 sys.exit(0) | |
720 while True: | |
721 timeout = None | |
722 timeobj = None | |
723 for obj in self.table.itervalues(): | |
724 if obj.timeout is not None and (timeout is None or obj.timeout < timeout): | |
725 timeout, timeobj = obj.timeout, obj | |
726 try: | |
727 if self.ui.debugflag: | |
728 if timeout is None: | |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
729 self.ui.note(_('polling: no timeout\n')) |
6239 | 730 else: |
6961
12163fb21fce
i18n: mark strings for translation in inotify extension
Martin Geisler <mg@daimi.au.dk>
parents:
6909
diff
changeset
|
731 self.ui.note(_('polling: %sms timeout\n') % timeout) |
6239 | 732 events = self.poll.poll(timeout) |
733 except select.error, err: | |
734 if err[0] == errno.EINTR: | |
735 continue | |
736 raise | |
737 if events: | |
738 for fd, event in events: | |
739 self.table[fd].handle_event(fd, event) | |
740 elif timeobj: | |
741 timeobj.handle_timeout() | |
742 | |
743 def start(ui, repo): | |
7451
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
744 def closefds(ignore): |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
745 # (from python bug #1177468) |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
746 # close all inherited file descriptors |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
747 # Python 2.4.1 and later use /dev/urandom to seed the random module's RNG |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
748 # a file descriptor is kept internally as os._urandomfd (created on demand |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
749 # the first time os.urandom() is called), and should not be closed |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
750 try: |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
751 os.urandom(4) |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
752 urandom_fd = getattr(os, '_urandomfd', None) |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
753 except AttributeError: |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
754 urandom_fd = None |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
755 ignore.append(urandom_fd) |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
756 for fd in range(3, 256): |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
757 if fd in ignore: |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
758 continue |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
759 try: |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
760 os.close(fd) |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
761 except OSError: |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
762 pass |
fca9947652ce
inotify: close most file descriptors when autostarting
Brendan Cully <brendan@kublai.com>
parents:
7420
diff
changeset
|
763 |
8385
1536501ade62
inotify: Coding Style: name classes in lowercase.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8384
diff
changeset
|
764 m = master(ui, repo) |
6239 | 765 sys.stdout.flush() |
766 sys.stderr.flush() | |
767 | |
768 pid = os.fork() | |
769 if pid: | |
770 return pid | |
771 | |
8335
713ec3f9c9de
inotify: Clarify the use of "watcher" name.
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents:
8334
diff
changeset
|
772 closefds([m.server.fileno(), m.repowatcher.fileno()]) |
6239 | 773 os.setsid() |
774 | |
775 fd = os.open('/dev/null', os.O_RDONLY) | |
776 os.dup2(fd, 0) | |
777 if fd > 0: | |
778 os.close(fd) | |
779 | |
780 fd = os.open(ui.config('inotify', 'log', '/dev/null'), | |
781 os.O_RDWR | os.O_CREAT | os.O_TRUNC) | |
782 os.dup2(fd, 1) | |
783 os.dup2(fd, 2) | |
784 if fd > 2: | |
785 os.close(fd) | |
786 | |
787 try: | |
788 m.run() | |
789 finally: | |
790 m.shutdown() | |
791 os._exit(0) |