Skip to content

Commit

Permalink
- Removed custom glob functions, uses standard glob module directly.
Browse files Browse the repository at this point in the history
- Modified exclusion filter mechanism, patterns still can be loaded
  from files but the syntax has changed see exclude.lst for more
  details. This new method is safer since the external file is not
  executed anymore, it is only parsed looking for patterns loaded
  as strings.
  • Loading branch information
seb-m committed Jan 3, 2010
1 parent a8a70ee commit 7bbd6da
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 202 deletions.
12 changes: 12 additions & 0 deletions python2/examples/exclude.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# File associated to exclude.py
#
# List of patterns using regexps as defined into re standard module.
# These regexps are matched against submitted paths with re.match().

# Put only one pattern by line.
^/etc/apache[2]?/
^/etc/rc.*
^/etc/hostname
^/etc/hosts
^/etc/(fs|m)tab
^/etc/cron\..*
16 changes: 0 additions & 16 deletions python2/examples/exclude.patterns

This file was deleted.

35 changes: 19 additions & 16 deletions python2/examples/exclude.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
# Example: excludes items from being monitored.
# Example: exclude items from being monitored.
#
import pyinotify
import os

excl_file = os.path.join(os.getcwd(), 'exclude.patterns')
import pyinotify

wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm)


### Method 1:
# Exclude filter object
excl = pyinotify.ExcludeFilter({excl_file: ('excl_lst1', 'excl_lst2')})
# Exclude patterns from file
excl_file = os.path.join(os.getcwd(), 'exclude.lst')
excl = pyinotify.ExcludeFilter(excl_file)
# Add watches
wm.add_watch(['/etc/*', '/var'], pyinotify.ALL_EVENTS,
rec=True, do_glob=True, exclude_filter=excl)

res = wm.add_watch(['/etc/hostname', '/etc/cups', '/etc/rc0.d'],
pyinotify.ALL_EVENTS, rec=True, exclude_filter=excl)

### Method 2 (Equivalent)
wm.add_watch('/etc/*', pyinotify.ALL_EVENTS, rec=True, do_glob=True,
exclude_filter=pyinotify.ExcludeFilter({excl_file:('excl_lst1',)}))
wm.add_watch('/var', pyinotify.ALL_EVENTS, rec=True,
exclude_filter=pyinotify.ExcludeFilter({excl_file:('excl_lst2',)}))

# Exclude patterns from list
excl_lst = ['^/etc/apache[2]?/',
'^/etc/rc.*',
'^/etc/hostname',
'^/etc/hosts',
'^/etc/(fs|m)tab',
'^/etc/cron\..*']
excl = pyinotify.ExcludeFilter(excl_lst)
# Add watches
res = wm.add_watch(['/etc/hostname', '/etc/cups', '/etc/rc0.d'],
pyinotify.ALL_EVENTS, rec=True, exclude_filter=excl)

notifier.loop()
#notifier.loop()
111 changes: 26 additions & 85 deletions python2/pyinotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def __init__(self, version):
import ctypes
import ctypes.util
import asyncore
import glob

try:
from functools import reduce
Expand Down Expand Up @@ -183,10 +184,7 @@ def logger_init():
log = logger_init()



### inotify's variables ###


# inotify's variables
class SysCtlINotify:
"""
Access (read, write) inotify's variables through sysctl. Usually it
Expand Down Expand Up @@ -253,74 +251,6 @@ def __repr__(self):
globals()[attrname] = SysCtlINotify(attrname)



### iglob ###


# Code taken from standart Python Lib, slightly modified in order to work
# with pyinotify (don't exclude dotted files/dirs like .foo).
# Original version:
# @see: http://svn.python.org/projects/python/trunk/Lib/glob.py

def iglob(pathname):
if not has_magic(pathname):
if hasattr(os.path, 'lexists'):
if os.path.lexists(pathname):
yield pathname
else:
if os.path.islink(pathname) or os.path.exists(pathname):
yield pathname
return
dirname, basename = os.path.split(pathname)
# relative pathname
if not dirname:
return
# absolute pathname
if has_magic(dirname):
dirs = iglob(dirname)
else:
dirs = [dirname]
if has_magic(basename):
glob_in_dir = glob1
else:
glob_in_dir = glob0
for dirname in dirs:
for name in glob_in_dir(dirname, basename):
yield os.path.join(dirname, name)

def glob1(dirname, pattern):
if not dirname:
dirname = os.curdir
try:
names = os.listdir(dirname)
except os.error:
return []
return fnmatch.filter(names, pattern)

def glob0(dirname, basename):
if basename == '' and os.path.isdir(dirname):
# `os.path.split()` returns an empty basename for paths ending with a
# directory separator. 'q*x/' should match only directories.
return [basename]
if hasattr(os.path, 'lexists'):
if os.path.lexists(os.path.join(dirname, basename)):
return [basename]
else:
if (os.path.islink(os.path.join(dirname, basename)) or
os.path.exists(os.path.join(dirname, basename))):
return [basename]
return []

MAGIC_CHECK = re.compile('[*?[]')

def has_magic(s):
return MAGIC_CHECK.search(s) is not None



### Core ###


class EventsCodes:
"""
Set of codes corresponding to each kind of events.
Expand Down Expand Up @@ -1501,14 +1431,20 @@ class ExcludeFilter:
"""
def __init__(self, arg_lst):
"""
Examples:
ef1 = ExcludeFilter(["^/etc/rc.*", "^/etc/hostname"])
ef2 = ExcludeFilter("/my/path/exclude.lst")
Where exclude.lst contains:
^/etc/rc.*
^/etc/hostname
@param arg_lst: is either a list or dict of patterns:
[pattern1, ..., patternn]
{'filename1': (list1, listn), ...} where list1 is
a list of patterns
@type arg_lst: list or dict
[pattern1, ..., patternn] or a filename from which
patterns will be loaded.
@type arg_lst: list(str) or str
"""
if isinstance(arg_lst, dict):
lst = self._load_patterns(arg_lst)
if isinstance(arg_lst, str):
lst = self._load_patterns_from_file(arg_lst)
elif isinstance(arg_lst, list):
lst = arg_lst
else:
Expand All @@ -1518,13 +1454,18 @@ def __init__(self, arg_lst):
for regex in lst:
self._lregex.append(re.compile(regex, re.UNICODE))

def _load_patterns(self, dct):
def _load_patterns_from_file(self, filename):
lst = []
for path, varnames in dct.items():
loc = {}
execfile(path, {}, loc)
for varname in varnames:
lst.extend(loc.get(varname, []))
file_obj = file(filename, 'r')
try:
for line in file_obj.readlines():
# Trim leading an trailing whitespaces
pattern = line.strip()
if not pattern or pattern.startswith('#'):
continue
lst.append(pattern)
finally:
file_obj.close()
return lst

def _match(self, regex, path):
Expand Down Expand Up @@ -1656,7 +1597,7 @@ def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter):

def __glob(self, path, do_glob):
if do_glob:
return iglob(path)
return glob.iglob(path)
else:
return [path]

Expand Down
108 changes: 23 additions & 85 deletions python3/pyinotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def __init__(self, version):
import ctypes
import ctypes.util
import asyncore
import glob

try:
from functools import reduce
Expand Down Expand Up @@ -148,10 +149,7 @@ def logger_init():
log = logger_init()



### inotify's variables ###


# inotify's variables
class SysCtlINotify:
"""
Access (read, write) inotify's variables through sysctl. Usually it
Expand Down Expand Up @@ -218,74 +216,6 @@ def __repr__(self):
globals()[attrname] = SysCtlINotify(attrname)



### iglob ###


# Code taken from standart Python Lib, slightly modified in order to work
# with pyinotify (don't exclude dotted files/dirs like .foo).
# Original version:
# @see: http://svn.python.org/projects/python/trunk/Lib/glob.py

def iglob(pathname):
if not has_magic(pathname):
if hasattr(os.path, 'lexists'):
if os.path.lexists(pathname):
yield pathname
else:
if os.path.islink(pathname) or os.path.exists(pathname):
yield pathname
return
dirname, basename = os.path.split(pathname)
# relative pathname
if not dirname:
return
# absolute pathname
if has_magic(dirname):
dirs = iglob(dirname)
else:
dirs = [dirname]
if has_magic(basename):
glob_in_dir = glob1
else:
glob_in_dir = glob0
for dirname in dirs:
for name in glob_in_dir(dirname, basename):
yield os.path.join(dirname, name)

def glob1(dirname, pattern):
if not dirname:
dirname = os.curdir
try:
names = os.listdir(dirname)
except os.error:
return []
return fnmatch.filter(names, pattern)

def glob0(dirname, basename):
if basename == '' and os.path.isdir(dirname):
# `os.path.split()` returns an empty basename for paths ending with a
# directory separator. 'q*x/' should match only directories.
return [basename]
if hasattr(os.path, 'lexists'):
if os.path.lexists(os.path.join(dirname, basename)):
return [basename]
else:
if (os.path.islink(os.path.join(dirname, basename)) or
os.path.exists(os.path.join(dirname, basename))):
return [basename]
return []

MAGIC_CHECK = re.compile('[*?[]')

def has_magic(s):
return MAGIC_CHECK.search(s) is not None



### Core ###


class EventsCodes:
"""
Set of codes corresponding to each kind of events.
Expand Down Expand Up @@ -1459,14 +1389,20 @@ class ExcludeFilter:
"""
def __init__(self, arg_lst):
"""
Examples:
ef1 = ExcludeFilter(["^/etc/rc.*", "^/etc/hostname"])
ef2 = ExcludeFilter("/my/path/exclude.lst")
Where exclude.lst contains:
^/etc/rc.*
^/etc/hostname
@param arg_lst: is either a list or dict of patterns:
[pattern1, ..., patternn]
{'filename1': (list1, listn), ...} where list1 is
a list of patterns
@type arg_lst: list or dict
[pattern1, ..., patternn] or a filename from which
patterns will be loaded.
@type arg_lst: list(str) or str
"""
if isinstance(arg_lst, dict):
lst = self._load_patterns(arg_lst)
if isinstance(arg_lst, str):
lst = self._load_patterns_from_file(arg_lst)
elif isinstance(arg_lst, list):
lst = arg_lst
else:
Expand All @@ -1476,13 +1412,15 @@ def __init__(self, arg_lst):
for regex in lst:
self._lregex.append(re.compile(regex, re.UNICODE))

def _load_patterns(self, dct):
def _load_patterns_from_file(self, filename):
lst = []
for path, varnames in dct.items():
loc = {}
execfile(path, {}, loc)
for varname in varnames:
lst.extend(loc.get(varname, []))
with open(filename, 'r') as file_obj:
for line in file_obj.readlines():
# Trim leading an trailing whitespaces
pattern = line.strip()
if not pattern or pattern.startswith('#'):
continue
lst.append(pattern)
return lst

def _match(self, regex, path):
Expand Down Expand Up @@ -1613,7 +1551,7 @@ def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter):

def __glob(self, path, do_glob):
if do_glob:
return iglob(path)
return glob.iglob(path)
else:
return [path]

Expand Down

0 comments on commit 7bbd6da

Please sign in to comment.