12 Commits
12 changed files with 50 additions and 39 deletions
-3
View File
@@ -117,6 +117,3 @@ dmypy.json
# Temporary Vim files # Temporary Vim files
.*.swp .*.swp
# config file
/config.py
+6 -2
View File
@@ -49,7 +49,7 @@ The basic idea is to instantiate one or multiple schedulers and map specific ino
pyinotifyd has different schedulers to schedule tasks with an optional delay. The advantages of using a scheduler are consistent logging and the possibility to cancel delayed tasks. Furthermore, schedulers have the ability to differentiate between files and directories. pyinotifyd has different schedulers to schedule tasks with an optional delay. The advantages of using a scheduler are consistent logging and the possibility to cancel delayed tasks. Furthermore, schedulers have the ability to differentiate between files and directories.
### TaskScheduler ### TaskScheduler
Schedule a custom python method *job* with an optional *delay* in seconds. Skip scheduling of tasks for files and/or directories according to *files* and *dirs* arguments. If there already is a scheduled task, re-schedule it with *delay*. Use *logname* in log messages. Schedule a custom python method *job* with an optional *delay* in seconds. Skip scheduling of tasks for files and/or directories according to *files* and *dirs* arguments. If there already is a scheduled task, re-schedule it with *delay*. Use *logname* in log messages. All additional modules, functions and variables that are defined in the config file and are needed within the *job*, need to be passed as dictionary to the TaskManager through *global_vars*.
All arguments except for *job* are optional. All arguments except for *job* are optional.
```python ```python
# Please note that pyinotifyd uses pythons asyncio for asynchronous task execution. # Please note that pyinotifyd uses pythons asyncio for asynchronous task execution.
@@ -58,6 +58,9 @@ All arguments except for *job* are optional.
# Bad: time.sleep(10) # Bad: time.sleep(10)
# Good: await asyncio.sleep(10) # Good: await asyncio.sleep(10)
import asyncio
import logging
async def custom_job(event, task_id): async def custom_job(event, task_id):
await asyncio.sleep(10) await asyncio.sleep(10)
logging.info(f"{task_id}: execute example task: {event}") logging.info(f"{task_id}: execute example task: {event}")
@@ -67,7 +70,8 @@ task_sched = TaskScheduler(
files=True, files=True,
dirs=False, dirs=False,
delay=0, delay=0,
logname="sched") logname="sched",
global_vars=globals())
``` ```
### ShellScheduler ### ShellScheduler
@@ -2,7 +2,7 @@
# Distributed under the terms of the GNU General Public License v2 # Distributed under the terms of the GNU General Public License v2
EAPI=7 EAPI=7
PYTHON_COMPAT=( python3_{7,8,9} ) PYTHON_COMPAT=( python3_{8..10} )
DISTUTILS_USE_SETUPTOOLS=rdepend DISTUTILS_USE_SETUPTOOLS=rdepend
SCM="" SCM=""
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
set -e set -e
set -x
PYTHON=$(which python) PYTHON=$(which python)
script_dir=$(dirname "$(readlink -f -- "$BASH_SOURCE")") script_dir=$(dirname "$(readlink -f -- "$BASH_SOURCE")")
+1
View File
@@ -7,6 +7,7 @@ script_dir=$(dirname "$(readlink -f -- "$BASH_SOURCE")")
pkg_dir=$(realpath "${script_dir}/../..") pkg_dir=$(realpath "${script_dir}/../..")
cd "${pkg_dir}/dist" cd "${pkg_dir}/dist"
ls -la
msg="Select version to distribute (cancel with CTRL+C):" msg="Select version to distribute (cancel with CTRL+C):"
echo "${msg}" echo "${msg}"
select version in $(find . -maxdepth 1 -type f -name "pyinotifyd-*.*.*.tar.gz" -printf "%f\n" | sed "s#\.tar\.gz##g"); do select version in $(find . -maxdepth 1 -type f -name "pyinotifyd-*.*.*.tar.gz" -printf "%f\n" | sed "s#\.tar\.gz##g"); do
+6 -6
View File
@@ -36,7 +36,7 @@ from pyinotify import ProcessEvent
from pyinotifyd._install import install, uninstall from pyinotifyd._install import install, uninstall
from pyinotifyd.scheduler import TaskScheduler, Cancel from pyinotifyd.scheduler import TaskScheduler, Cancel
__version__ = "0.0.5" __version__ = "0.0.6"
def setLoglevel(loglevel, logname=None): def setLoglevel(loglevel, logname=None):
@@ -203,12 +203,12 @@ class Pyinotifyd:
config = {} config = {}
name = Pyinotifyd.name name = Pyinotifyd.name
exec("from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL", exec("from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL",
{}, config) config)
exec(f"from {name} import Pyinotifyd, Watch", {}, config) exec(f"from {name} import Pyinotifyd, Watch", config)
exec(f"from {name} import setLoglevel, enableSyslog", {}, config) exec(f"from {name} import setLoglevel, enableSyslog", config)
exec(f"from {name}.scheduler import *", {}, config) exec(f"from {name}.scheduler import *", config)
with open(config_file, "r") as fh: with open(config_file, "r") as fh:
exec(fh.read(), {}, config) exec(fh.read(), config)
instance = config[f"{name}"] instance = config[f"{name}"]
assert isinstance(instance, Pyinotifyd), \ assert isinstance(instance, Pyinotifyd), \
f"{name}: expected {type(Pyinotifyd)}, " \ f"{name}: expected {type(Pyinotifyd)}, " \
+12 -3
View File
@@ -21,14 +21,19 @@ import shutil
import sys import sys
SYSTEMD_PATH = "/lib/systemd/system" SYSTEMD_PATHS = ["/lib/systemd/system", "/usr/lib/systemd/system"]
OPENRC = "/sbin/openrc" OPENRC = "/sbin/openrc"
def _systemd_files(pkg_dir, name): def _systemd_files(pkg_dir, name):
for path in SYSTEMD_PATHS:
if os.path.isdir(path):
break
return [ return [
(f"{pkg_dir}/misc/systemd/{name}.service", (f"{pkg_dir}/misc/systemd/{name}.service",
f"{SYSTEMD_PATH}/{name}.service", True)] f"{path}/{name}.service", True)]
def _openrc_files(pkg_dir, name): def _openrc_files(pkg_dir, name):
@@ -113,7 +118,11 @@ def _check_root():
def _check_systemd(): def _check_systemd():
systemd = os.path.isdir(SYSTEMD_PATH) for path in SYSTEMD_PATHS:
systemd = os.path.isdir(path)
if systemd:
break
if systemd: if systemd:
logging.info("systemd detected") logging.info("systemd detected")
+6 -1
View File
@@ -2,14 +2,19 @@
# TaskScheduler config # # TaskScheduler config #
########################## ##########################
#import asyncio
#import logging
#
#async def custom_job(event, task_id): #async def custom_job(event, task_id):
# asyncio.sleep(1)
# logging.info(f"{task_id}: execute example task: {event}") # logging.info(f"{task_id}: execute example task: {event}")
# #
#task_sched = TaskScheduler( #task_sched = TaskScheduler(
# job=custom_job, # job=custom_job,
# files=True, # files=True,
# dirs=False, # dirs=False,
# delay=10) # delay=10
# global_vars=globals())
########################### ###########################
-5
View File
@@ -13,11 +13,6 @@ retry="SIGTERM/${shutdown_timeout}"
extra_commands="configtest reload" extra_commands="configtest reload"
depend() {
need net
before mta
}
checkconfig() { checkconfig() {
output=$(${command} ${command_args} -t 2>&1) output=$(${command} ${command_args} -t 2>&1)
ret=$? ret=$?
+16 -7
View File
@@ -46,13 +46,13 @@ class SchedulerLogger(logging.LoggerAdapter):
class TaskScheduler: class TaskScheduler:
class TaskState: class TaskState:
def __init__(self, id=None, task=None, cancelable=True): def __init__(self, task_id=None, task=None, cancelable=True):
self.id = id or str(uuid4()) self.id = task_id or str(uuid4())
self.task = task self.task = task
self.cancelable = cancelable self.cancelable = cancelable
def __init__(self, job, files=True, dirs=False, delay=0, logname="sched", def __init__(self, job, files=True, dirs=False, delay=0, logname="sched",
loop=None): loop=None, global_vars={}):
assert iscoroutinefunction(job), \ assert iscoroutinefunction(job), \
f"job: expected coroutine, got {type(job)}" f"job: expected coroutine, got {type(job)}"
assert isinstance(files, bool), \ assert isinstance(files, bool), \
@@ -61,6 +61,8 @@ class TaskScheduler:
f"dirs: expected {type(bool)}, got {type(dirs)}" f"dirs: expected {type(bool)}, got {type(dirs)}"
assert isinstance(delay, int), \ assert isinstance(delay, int), \
f"delay: expected {type(int)}, got {type(delay)}" f"delay: expected {type(int)}, got {type(delay)}"
assert isinstance(global_vars, dict), \
f"global_vars: expected {type(dict)}, got {type(global_vars)}"
self._job = job self._job = job
self._files = files self._files = files
@@ -68,7 +70,7 @@ class TaskScheduler:
self._delay = delay self._delay = delay
self._log = logging.getLogger((logname or __name__)) self._log = logging.getLogger((logname or __name__))
self._loop = (loop or asyncio.get_event_loop()) self._loop = (loop or asyncio.get_event_loop())
self._globals = global_vars
self._tasks = {} self._tasks = {}
self._pause = False self._pause = False
@@ -124,9 +126,16 @@ class TaskScheduler:
return return
logger.info("start task") logger.info("start task")
if self._globals:
local_vars = {"self": self,
"event": event,
"task_id": task_state.id}
task_state.task = self._loop.create_task(
eval("self._job(event, task_id)", self._globals, local_vars))
task_state.task = self._loop.create_task( else:
self._job(event, task_state.id)) task_state.task = self._loop.create_task(
self._job(event, task_state.id))
try: try:
task_state.cancelable = False task_state.cancelable = False
@@ -134,7 +143,7 @@ class TaskScheduler:
except asyncio.CancelledError: except asyncio.CancelledError:
logger.warning("ongoing task cancelled") logger.warning("ongoing task cancelled")
else: else:
self._log.info("task finished") logger.info("task finished")
finally: finally:
del self._tasks[event.pathname] del self._tasks[event.pathname]
+1 -1
View File
@@ -18,7 +18,7 @@ setup(name = "pyinotifyd",
# 3 - Alpha # 3 - Alpha
# 4 - Beta # 4 - Beta
# 5 - Production/Stable # 5 - Production/Stable
"Development Status :: 4 - Beta", "Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: Python", "Programming Language :: Python",
-9
View File
@@ -1,9 +0,0 @@
#!/usr/bin/env python
import sys
import pyinotifyd
if __name__ == '__main__':
sys.exit(
pyinotifyd.main()
)