diff options
| -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. |
