diff options
Diffstat (limited to 'bitbake')
-rw-r--r-- | bitbake/lib/pyinotify.py | 256 |
1 files changed, 101 insertions, 155 deletions
diff --git a/bitbake/lib/pyinotify.py b/bitbake/lib/pyinotify.py index 2dae002118..4eb03b092d 100644 --- a/bitbake/lib/pyinotify.py +++ b/bitbake/lib/pyinotify.py | |||
@@ -42,13 +42,14 @@ class UnsupportedPythonVersionError(PyinotifyError): | |||
42 | @param version: Current Python version | 42 | @param version: Current Python version |
43 | @type version: string | 43 | @type version: string |
44 | """ | 44 | """ |
45 | err = 'Python %s is unsupported, requires at least Python 2.4' | 45 | PyinotifyError.__init__(self, |
46 | PyinotifyError.__init__(self, err % version) | 46 | ('Python %s is unsupported, requires ' |
47 | 'at least Python 3.0') % version) | ||
47 | 48 | ||
48 | 49 | ||
49 | # Check Python version | 50 | # Check Python version |
50 | import sys | 51 | import sys |
51 | if sys.version_info < (2, 4): | 52 | if sys.version_info < (3, 0): |
52 | raise UnsupportedPythonVersionError(sys.version) | 53 | raise UnsupportedPythonVersionError(sys.version) |
53 | 54 | ||
54 | 55 | ||
@@ -68,6 +69,8 @@ from datetime import datetime, timedelta | |||
68 | import time | 69 | import time |
69 | import re | 70 | import re |
70 | import asyncore | 71 | import asyncore |
72 | import glob | ||
73 | import locale | ||
71 | import subprocess | 74 | import subprocess |
72 | 75 | ||
73 | try: | 76 | try: |
@@ -76,12 +79,6 @@ except ImportError: | |||
76 | pass # Will fail on Python 2.4 which has reduce() builtin anyway. | 79 | pass # Will fail on Python 2.4 which has reduce() builtin anyway. |
77 | 80 | ||
78 | try: | 81 | try: |
79 | from glob import iglob as glob | ||
80 | except ImportError: | ||
81 | # Python 2.4 does not have glob.iglob(). | ||
82 | from glob import glob as glob | ||
83 | |||
84 | try: | ||
85 | import ctypes | 82 | import ctypes |
86 | import ctypes.util | 83 | import ctypes.util |
87 | except ImportError: | 84 | except ImportError: |
@@ -95,9 +92,7 @@ except ImportError: | |||
95 | 92 | ||
96 | __author__ = "seb@dbzteam.org (Sebastien Martini)" | 93 | __author__ = "seb@dbzteam.org (Sebastien Martini)" |
97 | 94 | ||
98 | __version__ = "0.9.5" | 95 | __version__ = "0.9.6" |
99 | |||
100 | __metaclass__ = type # Use new-style classes by default | ||
101 | 96 | ||
102 | 97 | ||
103 | # Compatibity mode: set to True to improve compatibility with | 98 | # Compatibity mode: set to True to improve compatibility with |
@@ -122,6 +117,9 @@ class INotifyWrapper: | |||
122 | """ | 117 | """ |
123 | @staticmethod | 118 | @staticmethod |
124 | def create(): | 119 | def create(): |
120 | """ | ||
121 | Factory method instanciating and returning the right wrapper. | ||
122 | """ | ||
125 | # First, try to use ctypes. | 123 | # First, try to use ctypes. |
126 | if ctypes: | 124 | if ctypes: |
127 | inotify = _CtypesLibcINotifyWrapper() | 125 | inotify = _CtypesLibcINotifyWrapper() |
@@ -173,7 +171,7 @@ class _INotifySyscallsWrapper(INotifyWrapper): | |||
173 | def _inotify_init(self): | 171 | def _inotify_init(self): |
174 | try: | 172 | try: |
175 | fd = inotify_syscalls.inotify_init() | 173 | fd = inotify_syscalls.inotify_init() |
176 | except IOError, err: | 174 | except IOError as err: |
177 | self._last_errno = err.errno | 175 | self._last_errno = err.errno |
178 | return -1 | 176 | return -1 |
179 | return fd | 177 | return fd |
@@ -181,7 +179,7 @@ class _INotifySyscallsWrapper(INotifyWrapper): | |||
181 | def _inotify_add_watch(self, fd, pathname, mask): | 179 | def _inotify_add_watch(self, fd, pathname, mask): |
182 | try: | 180 | try: |
183 | wd = inotify_syscalls.inotify_add_watch(fd, pathname, mask) | 181 | wd = inotify_syscalls.inotify_add_watch(fd, pathname, mask) |
184 | except IOError, err: | 182 | except IOError as err: |
185 | self._last_errno = err.errno | 183 | self._last_errno = err.errno |
186 | return -1 | 184 | return -1 |
187 | return wd | 185 | return wd |
@@ -189,7 +187,7 @@ class _INotifySyscallsWrapper(INotifyWrapper): | |||
189 | def _inotify_rm_watch(self, fd, wd): | 187 | def _inotify_rm_watch(self, fd, wd): |
190 | try: | 188 | try: |
191 | ret = inotify_syscalls.inotify_rm_watch(fd, wd) | 189 | ret = inotify_syscalls.inotify_rm_watch(fd, wd) |
192 | except IOError, err: | 190 | except IOError as err: |
193 | self._last_errno = err.errno | 191 | self._last_errno = err.errno |
194 | return -1 | 192 | return -1 |
195 | return ret | 193 | return ret |
@@ -213,17 +211,8 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper): | |||
213 | except (OSError, IOError): | 211 | except (OSError, IOError): |
214 | pass # Will attemp to load it with None anyway. | 212 | pass # Will attemp to load it with None anyway. |
215 | 213 | ||
216 | if sys.version_info >= (2, 6): | 214 | self._libc = ctypes.CDLL(libc_name, use_errno=True) |
217 | self._libc = ctypes.CDLL(libc_name, use_errno=True) | 215 | self._get_errno_func = ctypes.get_errno |
218 | self._get_errno_func = ctypes.get_errno | ||
219 | else: | ||
220 | self._libc = ctypes.CDLL(libc_name) | ||
221 | try: | ||
222 | location = self._libc.__errno_location | ||
223 | location.restype = ctypes.POINTER(ctypes.c_int) | ||
224 | self._get_errno_func = lambda: location().contents.value | ||
225 | except AttributeError: | ||
226 | pass | ||
227 | 216 | ||
228 | # Eventually check that libc has needed inotify bindings. | 217 | # Eventually check that libc has needed inotify bindings. |
229 | if (not hasattr(self._libc, 'inotify_init') or | 218 | if (not hasattr(self._libc, 'inotify_init') or |
@@ -241,9 +230,8 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper): | |||
241 | return True | 230 | return True |
242 | 231 | ||
243 | def _get_errno(self): | 232 | def _get_errno(self): |
244 | if self._get_errno_func is not None: | 233 | assert self._get_errno_func |
245 | return self._get_errno_func() | 234 | return self._get_errno_func() |
246 | return None | ||
247 | 235 | ||
248 | def _inotify_init(self): | 236 | def _inotify_init(self): |
249 | assert self._libc is not None | 237 | assert self._libc is not None |
@@ -251,6 +239,11 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper): | |||
251 | 239 | ||
252 | def _inotify_add_watch(self, fd, pathname, mask): | 240 | def _inotify_add_watch(self, fd, pathname, mask): |
253 | assert self._libc is not None | 241 | assert self._libc is not None |
242 | # Encodes path to a bytes string. This conversion seems required because | ||
243 | # ctypes.create_string_buffer seems to manipulate bytes internally. | ||
244 | # Moreover it seems that inotify_add_watch does not work very well when | ||
245 | # it receives an ctypes.create_unicode_buffer instance as argument. | ||
246 | pathname = pathname.encode(sys.getfilesystemencoding()) | ||
254 | pathname = ctypes.create_string_buffer(pathname) | 247 | pathname = ctypes.create_string_buffer(pathname) |
255 | return self._libc.inotify_add_watch(fd, pathname, mask) | 248 | return self._libc.inotify_add_watch(fd, pathname, mask) |
256 | 249 | ||
@@ -258,10 +251,6 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper): | |||
258 | assert self._libc is not None | 251 | assert self._libc is not None |
259 | return self._libc.inotify_rm_watch(fd, wd) | 252 | return self._libc.inotify_rm_watch(fd, wd) |
260 | 253 | ||
261 | def _sysctl(self, *args): | ||
262 | assert self._libc is not None | ||
263 | return self._libc.sysctl(*args) | ||
264 | |||
265 | 254 | ||
266 | # Logging | 255 | # Logging |
267 | def logger_init(): | 256 | def logger_init(): |
@@ -278,97 +267,58 @@ log = logger_init() | |||
278 | 267 | ||
279 | 268 | ||
280 | # inotify's variables | 269 | # inotify's variables |
281 | class SysCtlINotify: | 270 | class ProcINotify: |
282 | """ | 271 | """ |
283 | Access (read, write) inotify's variables through sysctl. Usually it | 272 | Access (read, write) inotify's variables through /proc/sys/. Note that |
284 | requires administrator rights to update them. | 273 | usually it requires administrator rights to update them. |
285 | 274 | ||
286 | Examples: | 275 | Examples: |
287 | - Read max_queued_events attribute: myvar = max_queued_events.value | 276 | - Read max_queued_events attribute: myvar = max_queued_events.value |
288 | - Update max_queued_events attribute: max_queued_events.value = 42 | 277 | - Update max_queued_events attribute: max_queued_events.value = 42 |
289 | """ | 278 | """ |
290 | 279 | def __init__(self, attr): | |
291 | inotify_attrs = {'max_user_instances': 1, | 280 | self._base = "/proc/sys/fs/inotify" |
292 | 'max_user_watches': 2, | 281 | self._attr = attr |
293 | 'max_queued_events': 3} | ||
294 | |||
295 | def __init__(self, attrname, inotify_wrapper): | ||
296 | # FIXME: right now only supporting ctypes | ||
297 | assert ctypes | ||
298 | self._attrname = attrname | ||
299 | self._inotify_wrapper = inotify_wrapper | ||
300 | sino = ctypes.c_int * 3 | ||
301 | self._attr = sino(5, 20, SysCtlINotify.inotify_attrs[attrname]) | ||
302 | |||
303 | @staticmethod | ||
304 | def create(attrname): | ||
305 | """ | ||
306 | Factory method instanciating and returning the right wrapper. | ||
307 | """ | ||
308 | # FIXME: right now only supporting ctypes | ||
309 | if ctypes is None: | ||
310 | return None | ||
311 | inotify_wrapper = _CtypesLibcINotifyWrapper() | ||
312 | if not inotify_wrapper.init(): | ||
313 | return None | ||
314 | return SysCtlINotify(attrname, inotify_wrapper) | ||
315 | 282 | ||
316 | def get_val(self): | 283 | def get_val(self): |
317 | """ | 284 | """ |
318 | Gets attribute's value. Raises OSError if the operation failed. | 285 | Gets attribute's value. |
319 | 286 | ||
320 | @return: stored value. | 287 | @return: stored value. |
321 | @rtype: int | 288 | @rtype: int |
289 | @raise IOError: if corresponding file in /proc/sys cannot be read. | ||
322 | """ | 290 | """ |
323 | oldv = ctypes.c_int(0) | 291 | with open(os.path.join(self._base, self._attr), 'r') as file_obj: |
324 | size = ctypes.c_int(ctypes.sizeof(oldv)) | 292 | return int(file_obj.readline()) |
325 | sysctl = self._inotify_wrapper._sysctl | ||
326 | res = sysctl(self._attr, 3, | ||
327 | ctypes.c_voidp(ctypes.addressof(oldv)), | ||
328 | ctypes.addressof(size), | ||
329 | None, 0) | ||
330 | if res == -1: | ||
331 | raise OSError(self._inotify_wrapper.get_errno(), | ||
332 | self._inotify_wrapper.str_errno()) | ||
333 | return oldv.value | ||
334 | 293 | ||
335 | def set_val(self, nval): | 294 | def set_val(self, nval): |
336 | """ | 295 | """ |
337 | Sets new attribute's value. Raises OSError if the operation failed. | 296 | Sets new attribute's value. |
338 | 297 | ||
339 | @param nval: replaces current value by nval. | 298 | @param nval: replaces current value by nval. |
340 | @type nval: int | 299 | @type nval: int |
300 | @raise IOError: if corresponding file in /proc/sys cannot be written. | ||
341 | """ | 301 | """ |
342 | oldv = ctypes.c_int(0) | 302 | with open(os.path.join(self._base, self._attr), 'w') as file_obj: |
343 | sizeo = ctypes.c_int(ctypes.sizeof(oldv)) | 303 | file_obj.write(str(nval) + '\n') |
344 | newv = ctypes.c_int(nval) | ||
345 | sizen = ctypes.c_int(ctypes.sizeof(newv)) | ||
346 | sysctl = self._inotify_wrapper._sysctl | ||
347 | res = sysctl(self._attr, 3, | ||
348 | ctypes.c_voidp(ctypes.addressof(oldv)), | ||
349 | ctypes.addressof(sizeo), | ||
350 | ctypes.c_voidp(ctypes.addressof(newv)), | ||
351 | sizen) | ||
352 | if res == -1: | ||
353 | raise OSError(self._inotify_wrapper.get_errno(), | ||
354 | self._inotify_wrapper.str_errno()) | ||
355 | 304 | ||
356 | value = property(get_val, set_val) | 305 | value = property(get_val, set_val) |
357 | 306 | ||
358 | def __repr__(self): | 307 | def __repr__(self): |
359 | return '<%s=%d>' % (self._attrname, self.get_val()) | 308 | return '<%s=%d>' % (self._attr, self.get_val()) |
360 | 309 | ||
361 | 310 | ||
362 | # Inotify's variables | 311 | # Inotify's variables |
363 | # | 312 | # |
364 | # FIXME: currently these variables are only accessible when ctypes is used, | 313 | # Note: may raise IOError if the corresponding value in /proc/sys |
365 | # otherwise there are set to None. | 314 | # cannot be accessed. |
366 | # | 315 | # |
367 | # read: myvar = max_queued_events.value | 316 | # Examples: |
368 | # update: max_queued_events.value = 42 | 317 | # - read: myvar = max_queued_events.value |
318 | # - update: max_queued_events.value = 42 | ||
369 | # | 319 | # |
370 | for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'): | 320 | for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'): |
371 | globals()[attrname] = SysCtlINotify.create(attrname) | 321 | globals()[attrname] = ProcINotify(attrname) |
372 | 322 | ||
373 | 323 | ||
374 | class EventsCodes: | 324 | class EventsCodes: |
@@ -536,7 +486,7 @@ class _Event: | |||
536 | continue | 486 | continue |
537 | if attr == 'mask': | 487 | if attr == 'mask': |
538 | value = hex(getattr(self, attr)) | 488 | value = hex(getattr(self, attr)) |
539 | elif isinstance(value, basestring) and not value: | 489 | elif isinstance(value, str) and not value: |
540 | value = "''" | 490 | value = "''" |
541 | s += ' %s%s%s' % (output_format.field_name(attr), | 491 | s += ' %s%s%s' % (output_format.field_name(attr), |
542 | output_format.punctuation('='), | 492 | output_format.punctuation('='), |
@@ -628,7 +578,7 @@ class Event(_Event): | |||
628 | self.name)) | 578 | self.name)) |
629 | else: | 579 | else: |
630 | self.pathname = os.path.abspath(self.path) | 580 | self.pathname = os.path.abspath(self.path) |
631 | except AttributeError, err: | 581 | except AttributeError as err: |
632 | # Usually it is not an error some events are perfectly valids | 582 | # Usually it is not an error some events are perfectly valids |
633 | # despite the lack of these attributes. | 583 | # despite the lack of these attributes. |
634 | log.debug(err) | 584 | log.debug(err) |
@@ -718,8 +668,8 @@ class _SysProcessEvent(_ProcessEvent): | |||
718 | and self._mv. | 668 | and self._mv. |
719 | """ | 669 | """ |
720 | date_cur_ = datetime.now() | 670 | date_cur_ = datetime.now() |
721 | for seq in [self._mv_cookie, self._mv]: | 671 | for seq in (self._mv_cookie, self._mv): |
722 | for k in seq.keys(): | 672 | for k in list(seq.keys()): |
723 | if (date_cur_ - seq[k][1]) > timedelta(minutes=1): | 673 | if (date_cur_ - seq[k][1]) > timedelta(minutes=1): |
724 | log.debug('Cleanup: deleting entry %s', seq[k][0]) | 674 | log.debug('Cleanup: deleting entry %s', seq[k][0]) |
725 | del seq[k] | 675 | del seq[k] |
@@ -767,9 +717,9 @@ class _SysProcessEvent(_ProcessEvent): | |||
767 | continue | 717 | continue |
768 | rawevent = _RawEvent(created_dir_wd, flags, 0, name) | 718 | rawevent = _RawEvent(created_dir_wd, flags, 0, name) |
769 | self._notifier.append_event(rawevent) | 719 | self._notifier.append_event(rawevent) |
770 | except OSError, err: | 720 | except OSError as err: |
771 | msg = "process_IN_CREATE, invalid directory %s: %s" | 721 | msg = "process_IN_CREATE, invalid directory: %s" |
772 | log.debug(msg % (created_dir, str(err))) | 722 | log.debug(msg % str(err)) |
773 | return self.process_default(raw_event) | 723 | return self.process_default(raw_event) |
774 | 724 | ||
775 | def process_IN_MOVED_FROM(self, raw_event): | 725 | def process_IN_MOVED_FROM(self, raw_event): |
@@ -1097,8 +1047,8 @@ class Stats(ProcessEvent): | |||
1097 | @type filename: string | 1047 | @type filename: string |
1098 | """ | 1048 | """ |
1099 | flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL | 1049 | flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL |
1100 | fd = os.open(filename, flags, 0600) | 1050 | fd = os.open(filename, flags, 0o0600) |
1101 | os.write(fd, str(self)) | 1051 | os.write(fd, bytes(self.__str__(), locale.getpreferredencoding())) |
1102 | os.close(fd) | 1052 | os.close(fd) |
1103 | 1053 | ||
1104 | def __str__(self, scale=45): | 1054 | def __str__(self, scale=45): |
@@ -1107,7 +1057,7 @@ class Stats(ProcessEvent): | |||
1107 | return '' | 1057 | return '' |
1108 | 1058 | ||
1109 | m = max(stats.values()) | 1059 | m = max(stats.values()) |
1110 | unity = float(scale) / m | 1060 | unity = scale / m |
1111 | fmt = '%%-26s%%-%ds%%s' % (len(output_format.field_value('@' * scale)) | 1061 | fmt = '%%-26s%%-%ds%%s' % (len(output_format.field_value('@' * scale)) |
1112 | + 1) | 1062 | + 1) |
1113 | def func(x): | 1063 | def func(x): |
@@ -1149,7 +1099,7 @@ class Notifier: | |||
1149 | @type default_proc_fun: instance of ProcessEvent | 1099 | @type default_proc_fun: instance of ProcessEvent |
1150 | @param read_freq: if read_freq == 0, events are read asap, | 1100 | @param read_freq: if read_freq == 0, events are read asap, |
1151 | if read_freq is > 0, this thread sleeps | 1101 | if read_freq is > 0, this thread sleeps |
1152 | max(0, read_freq - timeout) seconds. But if | 1102 | max(0, read_freq - (timeout / 1000)) seconds. But if |
1153 | timeout is None it may be different because | 1103 | timeout is None it may be different because |
1154 | poll is blocking waiting for something to read. | 1104 | poll is blocking waiting for something to read. |
1155 | @type read_freq: int | 1105 | @type read_freq: int |
@@ -1161,8 +1111,9 @@ class Notifier: | |||
1161 | until the amount of events to read is >= threshold. | 1111 | until the amount of events to read is >= threshold. |
1162 | At least with read_freq set you might sleep. | 1112 | At least with read_freq set you might sleep. |
1163 | @type threshold: int | 1113 | @type threshold: int |
1164 | @param timeout: | 1114 | @param timeout: see read_freq above. If provided, it must be set in |
1165 | https://docs.python.org/3/library/select.html#polling-objects | 1115 | milliseconds. See |
1116 | https://docs.python.org/3/library/select.html#select.poll.poll | ||
1166 | @type timeout: int | 1117 | @type timeout: int |
1167 | """ | 1118 | """ |
1168 | # Watch Manager instance | 1119 | # Watch Manager instance |
@@ -1228,7 +1179,8 @@ class Notifier: | |||
1228 | milliseconds. | 1179 | milliseconds. |
1229 | 1180 | ||
1230 | @param timeout: If specified it overrides the corresponding instance | 1181 | @param timeout: If specified it overrides the corresponding instance |
1231 | attribute _timeout. | 1182 | attribute _timeout. timeout must be sepcified in |
1183 | milliseconds. | ||
1232 | @type timeout: int | 1184 | @type timeout: int |
1233 | 1185 | ||
1234 | @return: New events to read. | 1186 | @return: New events to read. |
@@ -1240,8 +1192,8 @@ class Notifier: | |||
1240 | if timeout is None: | 1192 | if timeout is None: |
1241 | timeout = self._timeout | 1193 | timeout = self._timeout |
1242 | ret = self._pollobj.poll(timeout) | 1194 | ret = self._pollobj.poll(timeout) |
1243 | except select.error, err: | 1195 | except select.error as err: |
1244 | if err[0] == errno.EINTR: | 1196 | if err.args[0] == errno.EINTR: |
1245 | continue # interrupted, retry | 1197 | continue # interrupted, retry |
1246 | else: | 1198 | else: |
1247 | raise | 1199 | raise |
@@ -1271,7 +1223,7 @@ class Notifier: | |||
1271 | try: | 1223 | try: |
1272 | # Read content from file | 1224 | # Read content from file |
1273 | r = os.read(self._fd, queue_size) | 1225 | r = os.read(self._fd, queue_size) |
1274 | except Exception, msg: | 1226 | except Exception as msg: |
1275 | raise NotifierError(msg) | 1227 | raise NotifierError(msg) |
1276 | log.debug('Event queue size: %d', queue_size) | 1228 | log.debug('Event queue size: %d', queue_size) |
1277 | rsum = 0 # counter | 1229 | rsum = 0 # counter |
@@ -1281,9 +1233,11 @@ class Notifier: | |||
1281 | wd, mask, cookie, fname_len = struct.unpack('iIII', | 1233 | wd, mask, cookie, fname_len = struct.unpack('iIII', |
1282 | r[rsum:rsum+s_size]) | 1234 | r[rsum:rsum+s_size]) |
1283 | # Retrieve name | 1235 | # Retrieve name |
1284 | fname, = struct.unpack('%ds' % fname_len, | 1236 | bname, = struct.unpack('%ds' % fname_len, |
1285 | r[rsum + s_size:rsum + s_size + fname_len]) | 1237 | r[rsum + s_size:rsum + s_size + fname_len]) |
1286 | rawevent = _RawEvent(wd, mask, cookie, fname) | 1238 | # FIXME: should we explictly call sys.getdefaultencoding() here ?? |
1239 | uname = bname.decode() | ||
1240 | rawevent = _RawEvent(wd, mask, cookie, uname) | ||
1287 | if self._coalesce: | 1241 | if self._coalesce: |
1288 | # Only enqueue new (unique) events. | 1242 | # Only enqueue new (unique) events. |
1289 | raweventstr = str(rawevent) | 1243 | raweventstr = str(rawevent) |
@@ -1326,13 +1280,10 @@ class Notifier: | |||
1326 | def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull, | 1280 | def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull, |
1327 | stderr=os.devnull): | 1281 | stderr=os.devnull): |
1328 | """ | 1282 | """ |
1329 | @param pid_file: file where the pid will be written. If pid_file=None | 1283 | pid_file: file where the pid will be written. If pid_file=None the pid |
1330 | the pid is written to | 1284 | is written to /var/run/<sys.argv[0]|pyinotify>.pid, if |
1331 | /var/run/<sys.argv[0]|pyinotify>.pid, if pid_file=False | 1285 | pid_file=False no pid_file is written. |
1332 | no pid_file is written. | 1286 | stdin, stdout, stderr: files associated to common streams. |
1333 | @param stdin: | ||
1334 | @param stdout: | ||
1335 | @param stderr: files associated to common streams. | ||
1336 | """ | 1287 | """ |
1337 | if pid_file is None: | 1288 | if pid_file is None: |
1338 | dirname = '/var/run/' | 1289 | dirname = '/var/run/' |
@@ -1354,7 +1305,7 @@ class Notifier: | |||
1354 | if (pid == 0): | 1305 | if (pid == 0): |
1355 | # child | 1306 | # child |
1356 | os.chdir('/') | 1307 | os.chdir('/') |
1357 | os.umask(022) | 1308 | os.umask(0o022) |
1358 | else: | 1309 | else: |
1359 | # parent 2 | 1310 | # parent 2 |
1360 | os._exit(0) | 1311 | os._exit(0) |
@@ -1364,9 +1315,9 @@ class Notifier: | |||
1364 | 1315 | ||
1365 | fd_inp = os.open(stdin, os.O_RDONLY) | 1316 | fd_inp = os.open(stdin, os.O_RDONLY) |
1366 | os.dup2(fd_inp, 0) | 1317 | os.dup2(fd_inp, 0) |
1367 | fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0600) | 1318 | fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0o0600) |
1368 | os.dup2(fd_out, 1) | 1319 | os.dup2(fd_out, 1) |
1369 | fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0600) | 1320 | fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0o0600) |
1370 | os.dup2(fd_err, 2) | 1321 | os.dup2(fd_err, 2) |
1371 | 1322 | ||
1372 | # Detach task | 1323 | # Detach task |
@@ -1375,8 +1326,9 @@ class Notifier: | |||
1375 | # Write pid | 1326 | # Write pid |
1376 | if pid_file != False: | 1327 | if pid_file != False: |
1377 | flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL | 1328 | flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL |
1378 | fd_pid = os.open(pid_file, flags, 0600) | 1329 | fd_pid = os.open(pid_file, flags, 0o0600) |
1379 | os.write(fd_pid, str(os.getpid()) + '\n') | 1330 | os.write(fd_pid, bytes(str(os.getpid()) + '\n', |
1331 | locale.getpreferredencoding())) | ||
1380 | os.close(fd_pid) | 1332 | os.close(fd_pid) |
1381 | # Register unlink function | 1333 | # Register unlink function |
1382 | atexit.register(lambda : os.unlink(pid_file)) | 1334 | atexit.register(lambda : os.unlink(pid_file)) |
@@ -1441,9 +1393,12 @@ class Notifier: | |||
1441 | Close inotify's instance (close its file descriptor). | 1393 | Close inotify's instance (close its file descriptor). |
1442 | It destroys all existing watches, pending events,... | 1394 | It destroys all existing watches, pending events,... |
1443 | This method is automatically called at the end of loop(). | 1395 | This method is automatically called at the end of loop(). |
1396 | Afterward it is invalid to access this instance. | ||
1444 | """ | 1397 | """ |
1445 | self._pollobj.unregister(self._fd) | 1398 | if self._fd is not None: |
1446 | os.close(self._fd) | 1399 | self._pollobj.unregister(self._fd) |
1400 | os.close(self._fd) | ||
1401 | self._fd = None | ||
1447 | self._sys_proc_fun = None | 1402 | self._sys_proc_fun = None |
1448 | 1403 | ||
1449 | 1404 | ||
@@ -1468,7 +1423,7 @@ class ThreadedNotifier(threading.Thread, Notifier): | |||
1468 | @type default_proc_fun: instance of ProcessEvent | 1423 | @type default_proc_fun: instance of ProcessEvent |
1469 | @param read_freq: if read_freq == 0, events are read asap, | 1424 | @param read_freq: if read_freq == 0, events are read asap, |
1470 | if read_freq is > 0, this thread sleeps | 1425 | if read_freq is > 0, this thread sleeps |
1471 | max(0, read_freq - timeout) seconds. | 1426 | max(0, read_freq - (timeout / 1000)) seconds. |
1472 | @type read_freq: int | 1427 | @type read_freq: int |
1473 | @param threshold: File descriptor will be read only if the accumulated | 1428 | @param threshold: File descriptor will be read only if the accumulated |
1474 | size to read becomes >= threshold. If != 0, you likely | 1429 | size to read becomes >= threshold. If != 0, you likely |
@@ -1478,8 +1433,9 @@ class ThreadedNotifier(threading.Thread, Notifier): | |||
1478 | until the amount of events to read is >= threshold. At | 1433 | until the amount of events to read is >= threshold. At |
1479 | least with read_freq you might sleep. | 1434 | least with read_freq you might sleep. |
1480 | @type threshold: int | 1435 | @type threshold: int |
1481 | @param timeout: | 1436 | @param timeout: see read_freq above. If provided, it must be set in |
1482 | https://docs.python.org/3/library/select.html#polling-objects | 1437 | milliseconds. See |
1438 | https://docs.python.org/3/library/select.html#select.poll.poll | ||
1483 | @type timeout: int | 1439 | @type timeout: int |
1484 | """ | 1440 | """ |
1485 | # Init threading base class | 1441 | # Init threading base class |
@@ -1498,7 +1454,7 @@ class ThreadedNotifier(threading.Thread, Notifier): | |||
1498 | Stop notifier's loop. Stop notification. Join the thread. | 1454 | Stop notifier's loop. Stop notification. Join the thread. |
1499 | """ | 1455 | """ |
1500 | self._stop_event.set() | 1456 | self._stop_event.set() |
1501 | os.write(self._pipe[1], 'stop') | 1457 | os.write(self._pipe[1], b'stop') |
1502 | threading.Thread.join(self) | 1458 | threading.Thread.join(self) |
1503 | Notifier.stop(self) | 1459 | Notifier.stop(self) |
1504 | self._pollobj.unregister(self._pipe[0]) | 1460 | self._pollobj.unregister(self._pipe[0]) |
@@ -1699,7 +1655,6 @@ class Watch: | |||
1699 | class ExcludeFilter: | 1655 | class ExcludeFilter: |
1700 | """ | 1656 | """ |
1701 | ExcludeFilter is an exclusion filter. | 1657 | ExcludeFilter is an exclusion filter. |
1702 | |||
1703 | """ | 1658 | """ |
1704 | def __init__(self, arg_lst): | 1659 | def __init__(self, arg_lst): |
1705 | """ | 1660 | """ |
@@ -1731,16 +1686,13 @@ class ExcludeFilter: | |||
1731 | 1686 | ||
1732 | def _load_patterns_from_file(self, filename): | 1687 | def _load_patterns_from_file(self, filename): |
1733 | lst = [] | 1688 | lst = [] |
1734 | file_obj = file(filename, 'r') | 1689 | with open(filename, 'r') as file_obj: |
1735 | try: | ||
1736 | for line in file_obj.readlines(): | 1690 | for line in file_obj.readlines(): |
1737 | # Trim leading an trailing whitespaces | 1691 | # Trim leading an trailing whitespaces |
1738 | pattern = line.strip() | 1692 | pattern = line.strip() |
1739 | if not pattern or pattern.startswith('#'): | 1693 | if not pattern or pattern.startswith('#'): |
1740 | continue | 1694 | continue |
1741 | lst.append(pattern) | 1695 | lst.append(pattern) |
1742 | finally: | ||
1743 | file_obj.close() | ||
1744 | return lst | 1696 | return lst |
1745 | 1697 | ||
1746 | def _match(self, regex, path): | 1698 | def _match(self, regex, path): |
@@ -1764,7 +1716,6 @@ class WatchManagerError(Exception): | |||
1764 | """ | 1716 | """ |
1765 | WatchManager Exception. Raised on error encountered on watches | 1717 | WatchManager Exception. Raised on error encountered on watches |
1766 | operations. | 1718 | operations. |
1767 | |||
1768 | """ | 1719 | """ |
1769 | def __init__(self, msg, wmd): | 1720 | def __init__(self, msg, wmd): |
1770 | """ | 1721 | """ |
@@ -1851,7 +1802,7 @@ class WatchManager: | |||
1851 | """ | 1802 | """ |
1852 | try: | 1803 | try: |
1853 | del self._wmd[wd] | 1804 | del self._wmd[wd] |
1854 | except KeyError, err: | 1805 | except KeyError as err: |
1855 | log.error('Cannot delete unknown watch descriptor %s' % str(err)) | 1806 | log.error('Cannot delete unknown watch descriptor %s' % str(err)) |
1856 | 1807 | ||
1857 | @property | 1808 | @property |
@@ -1868,13 +1819,7 @@ class WatchManager: | |||
1868 | """ | 1819 | """ |
1869 | Format path to its internal (stored in watch manager) representation. | 1820 | Format path to its internal (stored in watch manager) representation. |
1870 | """ | 1821 | """ |
1871 | # Unicode strings are converted back to strings, because it seems | 1822 | # path must be a unicode string (str) and is just normalized. |
1872 | # that inotify_add_watch from ctypes does not work well when | ||
1873 | # it receives an ctypes.create_unicode_buffer instance as argument. | ||
1874 | # Therefore even wd are indexed with bytes string and not with | ||
1875 | # unicode paths. | ||
1876 | if isinstance(path, unicode): | ||
1877 | path = path.encode(sys.getfilesystemencoding()) | ||
1878 | return os.path.normpath(path) | 1823 | return os.path.normpath(path) |
1879 | 1824 | ||
1880 | def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter): | 1825 | def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter): |
@@ -1890,13 +1835,14 @@ class WatchManager: | |||
1890 | return wd | 1835 | return wd |
1891 | watch = Watch(wd=wd, path=path, mask=mask, proc_fun=proc_fun, | 1836 | watch = Watch(wd=wd, path=path, mask=mask, proc_fun=proc_fun, |
1892 | auto_add=auto_add, exclude_filter=exclude_filter) | 1837 | auto_add=auto_add, exclude_filter=exclude_filter) |
1838 | # wd are _always_ indexed with their original unicode paths in wmd. | ||
1893 | self._wmd[wd] = watch | 1839 | self._wmd[wd] = watch |
1894 | log.debug('New %s', watch) | 1840 | log.debug('New %s', watch) |
1895 | return wd | 1841 | return wd |
1896 | 1842 | ||
1897 | def __glob(self, path, do_glob): | 1843 | def __glob(self, path, do_glob): |
1898 | if do_glob: | 1844 | if do_glob: |
1899 | return glob(path) | 1845 | return glob.iglob(path) |
1900 | else: | 1846 | else: |
1901 | return [path] | 1847 | return [path] |
1902 | 1848 | ||
@@ -1907,11 +1853,8 @@ class WatchManager: | |||
1907 | Add watch(s) on the provided |path|(s) with associated |mask| flag | 1853 | Add watch(s) on the provided |path|(s) with associated |mask| flag |
1908 | value and optionally with a processing |proc_fun| function and | 1854 | value and optionally with a processing |proc_fun| function and |
1909 | recursive flag |rec| set to True. | 1855 | recursive flag |rec| set to True. |
1910 | Ideally |path| components should not be unicode objects. Note that | 1856 | All |path| components _must_ be str (i.e. unicode) objects. |
1911 | although unicode paths are accepted there are converted to byte | 1857 | If |path| is already watched it is ignored, but if it is called with |
1912 | strings before a watch is put on that path. The encoding used for | ||
1913 | converting the unicode object is given by sys.getfilesystemencoding(). | ||
1914 | If |path| si already watched it is ignored, but if it is called with | ||
1915 | option rec=True a watch is put on each one of its not-watched | 1858 | option rec=True a watch is put on each one of its not-watched |
1916 | subdirectory. | 1859 | subdirectory. |
1917 | 1860 | ||
@@ -1945,10 +1888,9 @@ class WatchManager: | |||
1945 | the class' constructor. | 1888 | the class' constructor. |
1946 | @type exclude_filter: callable object | 1889 | @type exclude_filter: callable object |
1947 | @return: dict of paths associated to watch descriptors. A wd value | 1890 | @return: dict of paths associated to watch descriptors. A wd value |
1948 | is positive if the watch was added sucessfully, | 1891 | is positive if the watch was added sucessfully, otherwise |
1949 | otherwise the value is negative. If the path was invalid | 1892 | the value is negative. If the path was invalid or was already |
1950 | or was already watched it is not included into this returned | 1893 | watched it is not included into this returned dictionary. |
1951 | dictionary. | ||
1952 | @rtype: dict of {str: int} | 1894 | @rtype: dict of {str: int} |
1953 | """ | 1895 | """ |
1954 | ret_ = {} # return {path: wd, ...} | 1896 | ret_ = {} # return {path: wd, ...} |
@@ -1958,6 +1900,11 @@ class WatchManager: | |||
1958 | 1900 | ||
1959 | # normalize args as list elements | 1901 | # normalize args as list elements |
1960 | for npath in self.__format_param(path): | 1902 | for npath in self.__format_param(path): |
1903 | # Require that path be a unicode string | ||
1904 | if not isinstance(npath, str): | ||
1905 | ret_[path] = -3 | ||
1906 | continue | ||
1907 | |||
1961 | # unix pathname pattern expansion | 1908 | # unix pathname pattern expansion |
1962 | for apath in self.__glob(npath, do_glob): | 1909 | for apath in self.__glob(npath, do_glob): |
1963 | # recursively list subdirs according to rec param | 1910 | # recursively list subdirs according to rec param |
@@ -2242,7 +2189,6 @@ class WatchManager: | |||
2242 | "Make watch manager ignoring new events.") | 2189 | "Make watch manager ignoring new events.") |
2243 | 2190 | ||
2244 | 2191 | ||
2245 | |||
2246 | class RawOutputFormat: | 2192 | class RawOutputFormat: |
2247 | """ | 2193 | """ |
2248 | Format string representations. | 2194 | Format string representations. |