bitbake: bitbake/pyinotify.py: Upgrade to py3 version
(Bitbake rev: 5ee80d77bc278758e411048ed09551ab65b9e72d) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
parent
822eabf32d
commit
deca147645
|
@ -42,13 +42,14 @@ class UnsupportedPythonVersionError(PyinotifyError):
|
||||||
@param version: Current Python version
|
@param version: Current Python version
|
||||||
@type version: string
|
@type version: string
|
||||||
"""
|
"""
|
||||||
err = 'Python %s is unsupported, requires at least Python 2.4'
|
PyinotifyError.__init__(self,
|
||||||
PyinotifyError.__init__(self, err % version)
|
('Python %s is unsupported, requires '
|
||||||
|
'at least Python 3.0') % version)
|
||||||
|
|
||||||
|
|
||||||
# Check Python version
|
# Check Python version
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info < (2, 4):
|
if sys.version_info < (3, 0):
|
||||||
raise UnsupportedPythonVersionError(sys.version)
|
raise UnsupportedPythonVersionError(sys.version)
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,6 +69,8 @@ from datetime import datetime, timedelta
|
||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
import asyncore
|
import asyncore
|
||||||
|
import glob
|
||||||
|
import locale
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -75,12 +78,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass # Will fail on Python 2.4 which has reduce() builtin anyway.
|
pass # Will fail on Python 2.4 which has reduce() builtin anyway.
|
||||||
|
|
||||||
try:
|
|
||||||
from glob import iglob as glob
|
|
||||||
except ImportError:
|
|
||||||
# Python 2.4 does not have glob.iglob().
|
|
||||||
from glob import glob as glob
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ctypes
|
import ctypes
|
||||||
import ctypes.util
|
import ctypes.util
|
||||||
|
@ -95,9 +92,7 @@ except ImportError:
|
||||||
|
|
||||||
__author__ = "seb@dbzteam.org (Sebastien Martini)"
|
__author__ = "seb@dbzteam.org (Sebastien Martini)"
|
||||||
|
|
||||||
__version__ = "0.9.5"
|
__version__ = "0.9.6"
|
||||||
|
|
||||||
__metaclass__ = type # Use new-style classes by default
|
|
||||||
|
|
||||||
|
|
||||||
# Compatibity mode: set to True to improve compatibility with
|
# Compatibity mode: set to True to improve compatibility with
|
||||||
|
@ -122,6 +117,9 @@ class INotifyWrapper:
|
||||||
"""
|
"""
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create():
|
def create():
|
||||||
|
"""
|
||||||
|
Factory method instanciating and returning the right wrapper.
|
||||||
|
"""
|
||||||
# First, try to use ctypes.
|
# First, try to use ctypes.
|
||||||
if ctypes:
|
if ctypes:
|
||||||
inotify = _CtypesLibcINotifyWrapper()
|
inotify = _CtypesLibcINotifyWrapper()
|
||||||
|
@ -173,7 +171,7 @@ class _INotifySyscallsWrapper(INotifyWrapper):
|
||||||
def _inotify_init(self):
|
def _inotify_init(self):
|
||||||
try:
|
try:
|
||||||
fd = inotify_syscalls.inotify_init()
|
fd = inotify_syscalls.inotify_init()
|
||||||
except IOError, err:
|
except IOError as err:
|
||||||
self._last_errno = err.errno
|
self._last_errno = err.errno
|
||||||
return -1
|
return -1
|
||||||
return fd
|
return fd
|
||||||
|
@ -181,7 +179,7 @@ class _INotifySyscallsWrapper(INotifyWrapper):
|
||||||
def _inotify_add_watch(self, fd, pathname, mask):
|
def _inotify_add_watch(self, fd, pathname, mask):
|
||||||
try:
|
try:
|
||||||
wd = inotify_syscalls.inotify_add_watch(fd, pathname, mask)
|
wd = inotify_syscalls.inotify_add_watch(fd, pathname, mask)
|
||||||
except IOError, err:
|
except IOError as err:
|
||||||
self._last_errno = err.errno
|
self._last_errno = err.errno
|
||||||
return -1
|
return -1
|
||||||
return wd
|
return wd
|
||||||
|
@ -189,7 +187,7 @@ class _INotifySyscallsWrapper(INotifyWrapper):
|
||||||
def _inotify_rm_watch(self, fd, wd):
|
def _inotify_rm_watch(self, fd, wd):
|
||||||
try:
|
try:
|
||||||
ret = inotify_syscalls.inotify_rm_watch(fd, wd)
|
ret = inotify_syscalls.inotify_rm_watch(fd, wd)
|
||||||
except IOError, err:
|
except IOError as err:
|
||||||
self._last_errno = err.errno
|
self._last_errno = err.errno
|
||||||
return -1
|
return -1
|
||||||
return ret
|
return ret
|
||||||
|
@ -213,17 +211,8 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
|
||||||
except (OSError, IOError):
|
except (OSError, IOError):
|
||||||
pass # Will attemp to load it with None anyway.
|
pass # Will attemp to load it with None anyway.
|
||||||
|
|
||||||
if sys.version_info >= (2, 6):
|
|
||||||
self._libc = ctypes.CDLL(libc_name, use_errno=True)
|
self._libc = ctypes.CDLL(libc_name, use_errno=True)
|
||||||
self._get_errno_func = ctypes.get_errno
|
self._get_errno_func = ctypes.get_errno
|
||||||
else:
|
|
||||||
self._libc = ctypes.CDLL(libc_name)
|
|
||||||
try:
|
|
||||||
location = self._libc.__errno_location
|
|
||||||
location.restype = ctypes.POINTER(ctypes.c_int)
|
|
||||||
self._get_errno_func = lambda: location().contents.value
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Eventually check that libc has needed inotify bindings.
|
# Eventually check that libc has needed inotify bindings.
|
||||||
if (not hasattr(self._libc, 'inotify_init') or
|
if (not hasattr(self._libc, 'inotify_init') or
|
||||||
|
@ -241,9 +230,8 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _get_errno(self):
|
def _get_errno(self):
|
||||||
if self._get_errno_func is not None:
|
assert self._get_errno_func
|
||||||
return self._get_errno_func()
|
return self._get_errno_func()
|
||||||
return None
|
|
||||||
|
|
||||||
def _inotify_init(self):
|
def _inotify_init(self):
|
||||||
assert self._libc is not None
|
assert self._libc is not None
|
||||||
|
@ -251,6 +239,11 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
|
||||||
|
|
||||||
def _inotify_add_watch(self, fd, pathname, mask):
|
def _inotify_add_watch(self, fd, pathname, mask):
|
||||||
assert self._libc is not None
|
assert self._libc is not None
|
||||||
|
# Encodes path to a bytes string. This conversion seems required because
|
||||||
|
# ctypes.create_string_buffer seems to manipulate bytes internally.
|
||||||
|
# Moreover it seems that inotify_add_watch does not work very well when
|
||||||
|
# it receives an ctypes.create_unicode_buffer instance as argument.
|
||||||
|
pathname = pathname.encode(sys.getfilesystemencoding())
|
||||||
pathname = ctypes.create_string_buffer(pathname)
|
pathname = ctypes.create_string_buffer(pathname)
|
||||||
return self._libc.inotify_add_watch(fd, pathname, mask)
|
return self._libc.inotify_add_watch(fd, pathname, mask)
|
||||||
|
|
||||||
|
@ -258,10 +251,6 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
|
||||||
assert self._libc is not None
|
assert self._libc is not None
|
||||||
return self._libc.inotify_rm_watch(fd, wd)
|
return self._libc.inotify_rm_watch(fd, wd)
|
||||||
|
|
||||||
def _sysctl(self, *args):
|
|
||||||
assert self._libc is not None
|
|
||||||
return self._libc.sysctl(*args)
|
|
||||||
|
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
def logger_init():
|
def logger_init():
|
||||||
|
@ -278,97 +267,58 @@ log = logger_init()
|
||||||
|
|
||||||
|
|
||||||
# inotify's variables
|
# inotify's variables
|
||||||
class SysCtlINotify:
|
class ProcINotify:
|
||||||
"""
|
"""
|
||||||
Access (read, write) inotify's variables through sysctl. Usually it
|
Access (read, write) inotify's variables through /proc/sys/. Note that
|
||||||
requires administrator rights to update them.
|
usually it requires administrator rights to update them.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
- Read max_queued_events attribute: myvar = max_queued_events.value
|
- Read max_queued_events attribute: myvar = max_queued_events.value
|
||||||
- Update max_queued_events attribute: max_queued_events.value = 42
|
- Update max_queued_events attribute: max_queued_events.value = 42
|
||||||
"""
|
"""
|
||||||
|
def __init__(self, attr):
|
||||||
inotify_attrs = {'max_user_instances': 1,
|
self._base = "/proc/sys/fs/inotify"
|
||||||
'max_user_watches': 2,
|
self._attr = attr
|
||||||
'max_queued_events': 3}
|
|
||||||
|
|
||||||
def __init__(self, attrname, inotify_wrapper):
|
|
||||||
# FIXME: right now only supporting ctypes
|
|
||||||
assert ctypes
|
|
||||||
self._attrname = attrname
|
|
||||||
self._inotify_wrapper = inotify_wrapper
|
|
||||||
sino = ctypes.c_int * 3
|
|
||||||
self._attr = sino(5, 20, SysCtlINotify.inotify_attrs[attrname])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def create(attrname):
|
|
||||||
"""
|
|
||||||
Factory method instanciating and returning the right wrapper.
|
|
||||||
"""
|
|
||||||
# FIXME: right now only supporting ctypes
|
|
||||||
if ctypes is None:
|
|
||||||
return None
|
|
||||||
inotify_wrapper = _CtypesLibcINotifyWrapper()
|
|
||||||
if not inotify_wrapper.init():
|
|
||||||
return None
|
|
||||||
return SysCtlINotify(attrname, inotify_wrapper)
|
|
||||||
|
|
||||||
def get_val(self):
|
def get_val(self):
|
||||||
"""
|
"""
|
||||||
Gets attribute's value. Raises OSError if the operation failed.
|
Gets attribute's value.
|
||||||
|
|
||||||
@return: stored value.
|
@return: stored value.
|
||||||
@rtype: int
|
@rtype: int
|
||||||
|
@raise IOError: if corresponding file in /proc/sys cannot be read.
|
||||||
"""
|
"""
|
||||||
oldv = ctypes.c_int(0)
|
with open(os.path.join(self._base, self._attr), 'r') as file_obj:
|
||||||
size = ctypes.c_int(ctypes.sizeof(oldv))
|
return int(file_obj.readline())
|
||||||
sysctl = self._inotify_wrapper._sysctl
|
|
||||||
res = sysctl(self._attr, 3,
|
|
||||||
ctypes.c_voidp(ctypes.addressof(oldv)),
|
|
||||||
ctypes.addressof(size),
|
|
||||||
None, 0)
|
|
||||||
if res == -1:
|
|
||||||
raise OSError(self._inotify_wrapper.get_errno(),
|
|
||||||
self._inotify_wrapper.str_errno())
|
|
||||||
return oldv.value
|
|
||||||
|
|
||||||
def set_val(self, nval):
|
def set_val(self, nval):
|
||||||
"""
|
"""
|
||||||
Sets new attribute's value. Raises OSError if the operation failed.
|
Sets new attribute's value.
|
||||||
|
|
||||||
@param nval: replaces current value by nval.
|
@param nval: replaces current value by nval.
|
||||||
@type nval: int
|
@type nval: int
|
||||||
|
@raise IOError: if corresponding file in /proc/sys cannot be written.
|
||||||
"""
|
"""
|
||||||
oldv = ctypes.c_int(0)
|
with open(os.path.join(self._base, self._attr), 'w') as file_obj:
|
||||||
sizeo = ctypes.c_int(ctypes.sizeof(oldv))
|
file_obj.write(str(nval) + '\n')
|
||||||
newv = ctypes.c_int(nval)
|
|
||||||
sizen = ctypes.c_int(ctypes.sizeof(newv))
|
|
||||||
sysctl = self._inotify_wrapper._sysctl
|
|
||||||
res = sysctl(self._attr, 3,
|
|
||||||
ctypes.c_voidp(ctypes.addressof(oldv)),
|
|
||||||
ctypes.addressof(sizeo),
|
|
||||||
ctypes.c_voidp(ctypes.addressof(newv)),
|
|
||||||
sizen)
|
|
||||||
if res == -1:
|
|
||||||
raise OSError(self._inotify_wrapper.get_errno(),
|
|
||||||
self._inotify_wrapper.str_errno())
|
|
||||||
|
|
||||||
value = property(get_val, set_val)
|
value = property(get_val, set_val)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s=%d>' % (self._attrname, self.get_val())
|
return '<%s=%d>' % (self._attr, self.get_val())
|
||||||
|
|
||||||
|
|
||||||
# Inotify's variables
|
# Inotify's variables
|
||||||
#
|
#
|
||||||
# FIXME: currently these variables are only accessible when ctypes is used,
|
# Note: may raise IOError if the corresponding value in /proc/sys
|
||||||
# otherwise there are set to None.
|
# cannot be accessed.
|
||||||
#
|
#
|
||||||
# read: myvar = max_queued_events.value
|
# Examples:
|
||||||
# update: max_queued_events.value = 42
|
# - read: myvar = max_queued_events.value
|
||||||
|
# - update: max_queued_events.value = 42
|
||||||
#
|
#
|
||||||
for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'):
|
for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'):
|
||||||
globals()[attrname] = SysCtlINotify.create(attrname)
|
globals()[attrname] = ProcINotify(attrname)
|
||||||
|
|
||||||
|
|
||||||
class EventsCodes:
|
class EventsCodes:
|
||||||
|
@ -536,7 +486,7 @@ class _Event:
|
||||||
continue
|
continue
|
||||||
if attr == 'mask':
|
if attr == 'mask':
|
||||||
value = hex(getattr(self, attr))
|
value = hex(getattr(self, attr))
|
||||||
elif isinstance(value, basestring) and not value:
|
elif isinstance(value, str) and not value:
|
||||||
value = "''"
|
value = "''"
|
||||||
s += ' %s%s%s' % (output_format.field_name(attr),
|
s += ' %s%s%s' % (output_format.field_name(attr),
|
||||||
output_format.punctuation('='),
|
output_format.punctuation('='),
|
||||||
|
@ -628,7 +578,7 @@ class Event(_Event):
|
||||||
self.name))
|
self.name))
|
||||||
else:
|
else:
|
||||||
self.pathname = os.path.abspath(self.path)
|
self.pathname = os.path.abspath(self.path)
|
||||||
except AttributeError, err:
|
except AttributeError as err:
|
||||||
# Usually it is not an error some events are perfectly valids
|
# Usually it is not an error some events are perfectly valids
|
||||||
# despite the lack of these attributes.
|
# despite the lack of these attributes.
|
||||||
log.debug(err)
|
log.debug(err)
|
||||||
|
@ -718,8 +668,8 @@ class _SysProcessEvent(_ProcessEvent):
|
||||||
and self._mv.
|
and self._mv.
|
||||||
"""
|
"""
|
||||||
date_cur_ = datetime.now()
|
date_cur_ = datetime.now()
|
||||||
for seq in [self._mv_cookie, self._mv]:
|
for seq in (self._mv_cookie, self._mv):
|
||||||
for k in seq.keys():
|
for k in list(seq.keys()):
|
||||||
if (date_cur_ - seq[k][1]) > timedelta(minutes=1):
|
if (date_cur_ - seq[k][1]) > timedelta(minutes=1):
|
||||||
log.debug('Cleanup: deleting entry %s', seq[k][0])
|
log.debug('Cleanup: deleting entry %s', seq[k][0])
|
||||||
del seq[k]
|
del seq[k]
|
||||||
|
@ -767,9 +717,9 @@ class _SysProcessEvent(_ProcessEvent):
|
||||||
continue
|
continue
|
||||||
rawevent = _RawEvent(created_dir_wd, flags, 0, name)
|
rawevent = _RawEvent(created_dir_wd, flags, 0, name)
|
||||||
self._notifier.append_event(rawevent)
|
self._notifier.append_event(rawevent)
|
||||||
except OSError, err:
|
except OSError as err:
|
||||||
msg = "process_IN_CREATE, invalid directory %s: %s"
|
msg = "process_IN_CREATE, invalid directory: %s"
|
||||||
log.debug(msg % (created_dir, str(err)))
|
log.debug(msg % str(err))
|
||||||
return self.process_default(raw_event)
|
return self.process_default(raw_event)
|
||||||
|
|
||||||
def process_IN_MOVED_FROM(self, raw_event):
|
def process_IN_MOVED_FROM(self, raw_event):
|
||||||
|
@ -1097,8 +1047,8 @@ class Stats(ProcessEvent):
|
||||||
@type filename: string
|
@type filename: string
|
||||||
"""
|
"""
|
||||||
flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
|
flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
|
||||||
fd = os.open(filename, flags, 0600)
|
fd = os.open(filename, flags, 0o0600)
|
||||||
os.write(fd, str(self))
|
os.write(fd, bytes(self.__str__(), locale.getpreferredencoding()))
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
|
|
||||||
def __str__(self, scale=45):
|
def __str__(self, scale=45):
|
||||||
|
@ -1107,7 +1057,7 @@ class Stats(ProcessEvent):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
m = max(stats.values())
|
m = max(stats.values())
|
||||||
unity = float(scale) / m
|
unity = scale / m
|
||||||
fmt = '%%-26s%%-%ds%%s' % (len(output_format.field_value('@' * scale))
|
fmt = '%%-26s%%-%ds%%s' % (len(output_format.field_value('@' * scale))
|
||||||
+ 1)
|
+ 1)
|
||||||
def func(x):
|
def func(x):
|
||||||
|
@ -1149,7 +1099,7 @@ class Notifier:
|
||||||
@type default_proc_fun: instance of ProcessEvent
|
@type default_proc_fun: instance of ProcessEvent
|
||||||
@param read_freq: if read_freq == 0, events are read asap,
|
@param read_freq: if read_freq == 0, events are read asap,
|
||||||
if read_freq is > 0, this thread sleeps
|
if read_freq is > 0, this thread sleeps
|
||||||
max(0, read_freq - timeout) seconds. But if
|
max(0, read_freq - (timeout / 1000)) seconds. But if
|
||||||
timeout is None it may be different because
|
timeout is None it may be different because
|
||||||
poll is blocking waiting for something to read.
|
poll is blocking waiting for something to read.
|
||||||
@type read_freq: int
|
@type read_freq: int
|
||||||
|
@ -1161,8 +1111,9 @@ class Notifier:
|
||||||
until the amount of events to read is >= threshold.
|
until the amount of events to read is >= threshold.
|
||||||
At least with read_freq set you might sleep.
|
At least with read_freq set you might sleep.
|
||||||
@type threshold: int
|
@type threshold: int
|
||||||
@param timeout:
|
@param timeout: see read_freq above. If provided, it must be set in
|
||||||
https://docs.python.org/3/library/select.html#polling-objects
|
milliseconds. See
|
||||||
|
https://docs.python.org/3/library/select.html#select.poll.poll
|
||||||
@type timeout: int
|
@type timeout: int
|
||||||
"""
|
"""
|
||||||
# Watch Manager instance
|
# Watch Manager instance
|
||||||
|
@ -1228,7 +1179,8 @@ class Notifier:
|
||||||
milliseconds.
|
milliseconds.
|
||||||
|
|
||||||
@param timeout: If specified it overrides the corresponding instance
|
@param timeout: If specified it overrides the corresponding instance
|
||||||
attribute _timeout.
|
attribute _timeout. timeout must be sepcified in
|
||||||
|
milliseconds.
|
||||||
@type timeout: int
|
@type timeout: int
|
||||||
|
|
||||||
@return: New events to read.
|
@return: New events to read.
|
||||||
|
@ -1240,8 +1192,8 @@ class Notifier:
|
||||||
if timeout is None:
|
if timeout is None:
|
||||||
timeout = self._timeout
|
timeout = self._timeout
|
||||||
ret = self._pollobj.poll(timeout)
|
ret = self._pollobj.poll(timeout)
|
||||||
except select.error, err:
|
except select.error as err:
|
||||||
if err[0] == errno.EINTR:
|
if err.args[0] == errno.EINTR:
|
||||||
continue # interrupted, retry
|
continue # interrupted, retry
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
@ -1271,7 +1223,7 @@ class Notifier:
|
||||||
try:
|
try:
|
||||||
# Read content from file
|
# Read content from file
|
||||||
r = os.read(self._fd, queue_size)
|
r = os.read(self._fd, queue_size)
|
||||||
except Exception, msg:
|
except Exception as msg:
|
||||||
raise NotifierError(msg)
|
raise NotifierError(msg)
|
||||||
log.debug('Event queue size: %d', queue_size)
|
log.debug('Event queue size: %d', queue_size)
|
||||||
rsum = 0 # counter
|
rsum = 0 # counter
|
||||||
|
@ -1281,9 +1233,11 @@ class Notifier:
|
||||||
wd, mask, cookie, fname_len = struct.unpack('iIII',
|
wd, mask, cookie, fname_len = struct.unpack('iIII',
|
||||||
r[rsum:rsum+s_size])
|
r[rsum:rsum+s_size])
|
||||||
# Retrieve name
|
# Retrieve name
|
||||||
fname, = struct.unpack('%ds' % fname_len,
|
bname, = struct.unpack('%ds' % fname_len,
|
||||||
r[rsum + s_size:rsum + s_size + fname_len])
|
r[rsum + s_size:rsum + s_size + fname_len])
|
||||||
rawevent = _RawEvent(wd, mask, cookie, fname)
|
# FIXME: should we explictly call sys.getdefaultencoding() here ??
|
||||||
|
uname = bname.decode()
|
||||||
|
rawevent = _RawEvent(wd, mask, cookie, uname)
|
||||||
if self._coalesce:
|
if self._coalesce:
|
||||||
# Only enqueue new (unique) events.
|
# Only enqueue new (unique) events.
|
||||||
raweventstr = str(rawevent)
|
raweventstr = str(rawevent)
|
||||||
|
@ -1326,13 +1280,10 @@ class Notifier:
|
||||||
def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull,
|
def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull,
|
||||||
stderr=os.devnull):
|
stderr=os.devnull):
|
||||||
"""
|
"""
|
||||||
@param pid_file: file where the pid will be written. If pid_file=None
|
pid_file: file where the pid will be written. If pid_file=None the pid
|
||||||
the pid is written to
|
is written to /var/run/<sys.argv[0]|pyinotify>.pid, if
|
||||||
/var/run/<sys.argv[0]|pyinotify>.pid, if pid_file=False
|
pid_file=False no pid_file is written.
|
||||||
no pid_file is written.
|
stdin, stdout, stderr: files associated to common streams.
|
||||||
@param stdin:
|
|
||||||
@param stdout:
|
|
||||||
@param stderr: files associated to common streams.
|
|
||||||
"""
|
"""
|
||||||
if pid_file is None:
|
if pid_file is None:
|
||||||
dirname = '/var/run/'
|
dirname = '/var/run/'
|
||||||
|
@ -1354,7 +1305,7 @@ class Notifier:
|
||||||
if (pid == 0):
|
if (pid == 0):
|
||||||
# child
|
# child
|
||||||
os.chdir('/')
|
os.chdir('/')
|
||||||
os.umask(022)
|
os.umask(0o022)
|
||||||
else:
|
else:
|
||||||
# parent 2
|
# parent 2
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
@ -1364,9 +1315,9 @@ class Notifier:
|
||||||
|
|
||||||
fd_inp = os.open(stdin, os.O_RDONLY)
|
fd_inp = os.open(stdin, os.O_RDONLY)
|
||||||
os.dup2(fd_inp, 0)
|
os.dup2(fd_inp, 0)
|
||||||
fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0600)
|
fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0o0600)
|
||||||
os.dup2(fd_out, 1)
|
os.dup2(fd_out, 1)
|
||||||
fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0600)
|
fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0o0600)
|
||||||
os.dup2(fd_err, 2)
|
os.dup2(fd_err, 2)
|
||||||
|
|
||||||
# Detach task
|
# Detach task
|
||||||
|
@ -1375,8 +1326,9 @@ class Notifier:
|
||||||
# Write pid
|
# Write pid
|
||||||
if pid_file != False:
|
if pid_file != False:
|
||||||
flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
|
flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
|
||||||
fd_pid = os.open(pid_file, flags, 0600)
|
fd_pid = os.open(pid_file, flags, 0o0600)
|
||||||
os.write(fd_pid, str(os.getpid()) + '\n')
|
os.write(fd_pid, bytes(str(os.getpid()) + '\n',
|
||||||
|
locale.getpreferredencoding()))
|
||||||
os.close(fd_pid)
|
os.close(fd_pid)
|
||||||
# Register unlink function
|
# Register unlink function
|
||||||
atexit.register(lambda : os.unlink(pid_file))
|
atexit.register(lambda : os.unlink(pid_file))
|
||||||
|
@ -1441,9 +1393,12 @@ class Notifier:
|
||||||
Close inotify's instance (close its file descriptor).
|
Close inotify's instance (close its file descriptor).
|
||||||
It destroys all existing watches, pending events,...
|
It destroys all existing watches, pending events,...
|
||||||
This method is automatically called at the end of loop().
|
This method is automatically called at the end of loop().
|
||||||
|
Afterward it is invalid to access this instance.
|
||||||
"""
|
"""
|
||||||
|
if self._fd is not None:
|
||||||
self._pollobj.unregister(self._fd)
|
self._pollobj.unregister(self._fd)
|
||||||
os.close(self._fd)
|
os.close(self._fd)
|
||||||
|
self._fd = None
|
||||||
self._sys_proc_fun = None
|
self._sys_proc_fun = None
|
||||||
|
|
||||||
|
|
||||||
|
@ -1468,7 +1423,7 @@ class ThreadedNotifier(threading.Thread, Notifier):
|
||||||
@type default_proc_fun: instance of ProcessEvent
|
@type default_proc_fun: instance of ProcessEvent
|
||||||
@param read_freq: if read_freq == 0, events are read asap,
|
@param read_freq: if read_freq == 0, events are read asap,
|
||||||
if read_freq is > 0, this thread sleeps
|
if read_freq is > 0, this thread sleeps
|
||||||
max(0, read_freq - timeout) seconds.
|
max(0, read_freq - (timeout / 1000)) seconds.
|
||||||
@type read_freq: int
|
@type read_freq: int
|
||||||
@param threshold: File descriptor will be read only if the accumulated
|
@param threshold: File descriptor will be read only if the accumulated
|
||||||
size to read becomes >= threshold. If != 0, you likely
|
size to read becomes >= threshold. If != 0, you likely
|
||||||
|
@ -1478,8 +1433,9 @@ class ThreadedNotifier(threading.Thread, Notifier):
|
||||||
until the amount of events to read is >= threshold. At
|
until the amount of events to read is >= threshold. At
|
||||||
least with read_freq you might sleep.
|
least with read_freq you might sleep.
|
||||||
@type threshold: int
|
@type threshold: int
|
||||||
@param timeout:
|
@param timeout: see read_freq above. If provided, it must be set in
|
||||||
https://docs.python.org/3/library/select.html#polling-objects
|
milliseconds. See
|
||||||
|
https://docs.python.org/3/library/select.html#select.poll.poll
|
||||||
@type timeout: int
|
@type timeout: int
|
||||||
"""
|
"""
|
||||||
# Init threading base class
|
# Init threading base class
|
||||||
|
@ -1498,7 +1454,7 @@ class ThreadedNotifier(threading.Thread, Notifier):
|
||||||
Stop notifier's loop. Stop notification. Join the thread.
|
Stop notifier's loop. Stop notification. Join the thread.
|
||||||
"""
|
"""
|
||||||
self._stop_event.set()
|
self._stop_event.set()
|
||||||
os.write(self._pipe[1], 'stop')
|
os.write(self._pipe[1], b'stop')
|
||||||
threading.Thread.join(self)
|
threading.Thread.join(self)
|
||||||
Notifier.stop(self)
|
Notifier.stop(self)
|
||||||
self._pollobj.unregister(self._pipe[0])
|
self._pollobj.unregister(self._pipe[0])
|
||||||
|
@ -1699,7 +1655,6 @@ class Watch:
|
||||||
class ExcludeFilter:
|
class ExcludeFilter:
|
||||||
"""
|
"""
|
||||||
ExcludeFilter is an exclusion filter.
|
ExcludeFilter is an exclusion filter.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, arg_lst):
|
def __init__(self, arg_lst):
|
||||||
"""
|
"""
|
||||||
|
@ -1731,16 +1686,13 @@ class ExcludeFilter:
|
||||||
|
|
||||||
def _load_patterns_from_file(self, filename):
|
def _load_patterns_from_file(self, filename):
|
||||||
lst = []
|
lst = []
|
||||||
file_obj = file(filename, 'r')
|
with open(filename, 'r') as file_obj:
|
||||||
try:
|
|
||||||
for line in file_obj.readlines():
|
for line in file_obj.readlines():
|
||||||
# Trim leading an trailing whitespaces
|
# Trim leading an trailing whitespaces
|
||||||
pattern = line.strip()
|
pattern = line.strip()
|
||||||
if not pattern or pattern.startswith('#'):
|
if not pattern or pattern.startswith('#'):
|
||||||
continue
|
continue
|
||||||
lst.append(pattern)
|
lst.append(pattern)
|
||||||
finally:
|
|
||||||
file_obj.close()
|
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
def _match(self, regex, path):
|
def _match(self, regex, path):
|
||||||
|
@ -1764,7 +1716,6 @@ class WatchManagerError(Exception):
|
||||||
"""
|
"""
|
||||||
WatchManager Exception. Raised on error encountered on watches
|
WatchManager Exception. Raised on error encountered on watches
|
||||||
operations.
|
operations.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg, wmd):
|
def __init__(self, msg, wmd):
|
||||||
"""
|
"""
|
||||||
|
@ -1851,7 +1802,7 @@ class WatchManager:
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
del self._wmd[wd]
|
del self._wmd[wd]
|
||||||
except KeyError, err:
|
except KeyError as err:
|
||||||
log.error('Cannot delete unknown watch descriptor %s' % str(err))
|
log.error('Cannot delete unknown watch descriptor %s' % str(err))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1868,13 +1819,7 @@ class WatchManager:
|
||||||
"""
|
"""
|
||||||
Format path to its internal (stored in watch manager) representation.
|
Format path to its internal (stored in watch manager) representation.
|
||||||
"""
|
"""
|
||||||
# Unicode strings are converted back to strings, because it seems
|
# path must be a unicode string (str) and is just normalized.
|
||||||
# that inotify_add_watch from ctypes does not work well when
|
|
||||||
# it receives an ctypes.create_unicode_buffer instance as argument.
|
|
||||||
# Therefore even wd are indexed with bytes string and not with
|
|
||||||
# unicode paths.
|
|
||||||
if isinstance(path, unicode):
|
|
||||||
path = path.encode(sys.getfilesystemencoding())
|
|
||||||
return os.path.normpath(path)
|
return os.path.normpath(path)
|
||||||
|
|
||||||
def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter):
|
def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter):
|
||||||
|
@ -1890,13 +1835,14 @@ class WatchManager:
|
||||||
return wd
|
return wd
|
||||||
watch = Watch(wd=wd, path=path, mask=mask, proc_fun=proc_fun,
|
watch = Watch(wd=wd, path=path, mask=mask, proc_fun=proc_fun,
|
||||||
auto_add=auto_add, exclude_filter=exclude_filter)
|
auto_add=auto_add, exclude_filter=exclude_filter)
|
||||||
|
# wd are _always_ indexed with their original unicode paths in wmd.
|
||||||
self._wmd[wd] = watch
|
self._wmd[wd] = watch
|
||||||
log.debug('New %s', watch)
|
log.debug('New %s', watch)
|
||||||
return wd
|
return wd
|
||||||
|
|
||||||
def __glob(self, path, do_glob):
|
def __glob(self, path, do_glob):
|
||||||
if do_glob:
|
if do_glob:
|
||||||
return glob(path)
|
return glob.iglob(path)
|
||||||
else:
|
else:
|
||||||
return [path]
|
return [path]
|
||||||
|
|
||||||
|
@ -1907,11 +1853,8 @@ class WatchManager:
|
||||||
Add watch(s) on the provided |path|(s) with associated |mask| flag
|
Add watch(s) on the provided |path|(s) with associated |mask| flag
|
||||||
value and optionally with a processing |proc_fun| function and
|
value and optionally with a processing |proc_fun| function and
|
||||||
recursive flag |rec| set to True.
|
recursive flag |rec| set to True.
|
||||||
Ideally |path| components should not be unicode objects. Note that
|
All |path| components _must_ be str (i.e. unicode) objects.
|
||||||
although unicode paths are accepted there are converted to byte
|
If |path| is already watched it is ignored, but if it is called with
|
||||||
strings before a watch is put on that path. The encoding used for
|
|
||||||
converting the unicode object is given by sys.getfilesystemencoding().
|
|
||||||
If |path| si already watched it is ignored, but if it is called with
|
|
||||||
option rec=True a watch is put on each one of its not-watched
|
option rec=True a watch is put on each one of its not-watched
|
||||||
subdirectory.
|
subdirectory.
|
||||||
|
|
||||||
|
@ -1945,10 +1888,9 @@ class WatchManager:
|
||||||
the class' constructor.
|
the class' constructor.
|
||||||
@type exclude_filter: callable object
|
@type exclude_filter: callable object
|
||||||
@return: dict of paths associated to watch descriptors. A wd value
|
@return: dict of paths associated to watch descriptors. A wd value
|
||||||
is positive if the watch was added sucessfully,
|
is positive if the watch was added sucessfully, otherwise
|
||||||
otherwise the value is negative. If the path was invalid
|
the value is negative. If the path was invalid or was already
|
||||||
or was already watched it is not included into this returned
|
watched it is not included into this returned dictionary.
|
||||||
dictionary.
|
|
||||||
@rtype: dict of {str: int}
|
@rtype: dict of {str: int}
|
||||||
"""
|
"""
|
||||||
ret_ = {} # return {path: wd, ...}
|
ret_ = {} # return {path: wd, ...}
|
||||||
|
@ -1958,6 +1900,11 @@ class WatchManager:
|
||||||
|
|
||||||
# normalize args as list elements
|
# normalize args as list elements
|
||||||
for npath in self.__format_param(path):
|
for npath in self.__format_param(path):
|
||||||
|
# Require that path be a unicode string
|
||||||
|
if not isinstance(npath, str):
|
||||||
|
ret_[path] = -3
|
||||||
|
continue
|
||||||
|
|
||||||
# unix pathname pattern expansion
|
# unix pathname pattern expansion
|
||||||
for apath in self.__glob(npath, do_glob):
|
for apath in self.__glob(npath, do_glob):
|
||||||
# recursively list subdirs according to rec param
|
# recursively list subdirs according to rec param
|
||||||
|
@ -2242,7 +2189,6 @@ class WatchManager:
|
||||||
"Make watch manager ignoring new events.")
|
"Make watch manager ignoring new events.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RawOutputFormat:
|
class RawOutputFormat:
|
||||||
"""
|
"""
|
||||||
Format string representations.
|
Format string representations.
|
||||||
|
|
Loading…
Reference in New Issue