add linux file monitor

This commit is contained in:
Lance Edgar 2012-07-14 15:24:58 -05:00
parent b3b4e40bcf
commit 79c4bfa289
5 changed files with 202 additions and 31 deletions

View file

@ -386,12 +386,15 @@ class DatabaseCommand(Subcommand):
class FileMonitorCommand(Subcommand):
"""
Interacts with the file monitor Windows service; called as ``edbob
filemon``. This command expects a subcommand; one of the following:
Interacts with the file monitor service; called as ``edbob filemon``. This
command expects a subcommand; one of the following:
* ``edbob filemon install``
* ``edbob filemon start``
* ``edbob filemon stop``
On Windows platforms, the following additional subcommands are available:
* ``edbob filemon install``
* ``edbob filemon uninstall``
.. note::
@ -399,28 +402,46 @@ class FileMonitorCommand(Subcommand):
``cmd.exe`` as an Administrator in order to have sufficient rights to
run the above commands.
.. todo::
Verify the previous statement... (Maybe test with/out UAC?)
See :doc:`howto.use_filemon` for more information.
"""
name = 'filemon'
description = "Manage the file monitor service on Windows"
description = "Manage the file monitor service"
def add_parser_args(self, parser):
subparsers = parser.add_subparsers(title='subcommands')
install = subparsers.add_parser('install',
help="Install (register) service")
install.set_defaults(subcommand='install')
uninstall = subparsers.add_parser('uninstall',
help="Uninstall (unregister) service")
uninstall.set_defaults(subcommand='remove')
start = subparsers.add_parser('start', help="Start service")
start.set_defaults(subcommand='start')
stop = subparsers.add_parser('stop', help="Stop service")
stop.set_defaults(subcommand='stop')
if sys.platform == 'win32':
install = subparsers.add_parser('install',
help="Install (register) service")
install.set_defaults(subcommand='install')
uninstall = subparsers.add_parser('uninstall',
help="Uninstall (unregister) service")
uninstall.set_defaults(subcommand='remove')
def run(self, args):
from edbob.filemon import exec_server_command
exec_server_command(args.subcommand)
if sys.platform == 'linux2':
if args.subcommand == 'start':
from edbob.filemon.linux import start_daemon
start_daemon()
elif args.subcommand == 'stop':
from edbob.filemon.linux import stop_daemon
stop_daemon()
elif sys.platform == 'win32':
from edbob.filemon.win32 import exec_server_command
exec_server_command(args.subcommand)
else:
print "Sorry, file monitor is not supported on platform %s." % sys.platform
class ShellCommand(Subcommand):

46
edbob/filemon/__init__.py Normal file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
################################################################################
#
# edbob -- Pythonic Software Framework
# Copyright © 2010-2012 Lance Edgar
#
# This file is part of edbob.
#
# edbob is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# edbob is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
# more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with edbob. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
``edbob.filemon`` -- File Monitoring Service
"""
import edbob
from edbob.exceptions import ConfigError
class MonitorProfile(object):
"""
This is a simple profile class, used to represent configuration of the file
monitor service.
"""
def __init__(self, key):
self.key = key
self.dirs = eval(edbob.config.require('edbob.filemon', '%s.dirs' % key))
if not self.dirs:
raise ConfigError('edbob.filemon', '%s.dirs' % key)
self.actions = eval(edbob.config.require('edbob.filemon', '%s.actions' % key))
if not self.actions:
raise ConfigError('edbob.filemon', '%s.actions' % key)

120
edbob/filemon/linux.py Normal file
View file

@ -0,0 +1,120 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
################################################################################
#
# edbob -- Pythonic Software Framework
# Copyright © 2010-2012 Lance Edgar
#
# This file is part of edbob.
#
# edbob is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# edbob is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
# more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with edbob. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
``edbob.filemon.linux`` -- File Monitor for Linux
"""
import sys
import os
import os.path
import signal
import pyinotify
import edbob
from edbob.filemon import MonitorProfile
class EventHandler(pyinotify.ProcessEvent):
"""
Event processor for file monitor daemon.
"""
def my_init(self, actions=[], **kwargs):
self.actions = actions
def process_IN_CREATE(self, event):
self.perform_actions(event.pathname)
def process_IN_MOVED_TO(self, event):
self.perform_actions(event.pathname)
def perform_actions(self, path):
for action in self.actions:
if isinstance(action, tuple):
func = action[0]
args = action[1:]
else:
func = action
args = []
func = edbob.load_spec(func)
func(path, *args)
def get_pid_path():
"""
Returns the path to the PID file for the file monitor daemon.
"""
basename = os.path.basename(sys.argv[0])
return '/tmp/%s_filemon.pid' % basename
def start_daemon():
"""
Starts the file monitor daemon.
"""
pid_path = get_pid_path()
if os.path.exists(pid_path):
print "File monitor is already running"
return
wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm)
monitored = {}
keys = edbob.config.require('edbob.filemon', 'monitored')
keys = keys.split(',')
for key in keys:
key = key.strip()
monitored[key] = MonitorProfile(key)
mask = pyinotify.IN_CREATE | pyinotify.IN_MOVED_TO
for profile in monitored.itervalues():
for path in profile.dirs:
wm.add_watch(path, mask, proc_fun=EventHandler(actions=profile.actions))
notifier.loop(daemonize=True, pid_file=pid_path)
def stop_daemon():
"""
Stops the file monitor daemon.
"""
pid_path = get_pid_path()
if not os.path.exists(pid_path):
print "File monitor is not running"
return
f = open(pid_path)
pid = f.read().strip()
f.close()
if not pid.isdigit():
print "Hm, found bogus PID:", pid
return
os.kill(int(pid), signal.SIGKILL)
os.remove(pid_path)

View file

@ -23,7 +23,7 @@
################################################################################
"""
``edbob.filemon`` -- File Monitoring Service
``edbob.filemon.win32`` -- File Monitor for Windows
"""
# Much of the Windows monitoring code below was borrowed from Tim Golden:
@ -67,22 +67,6 @@ def exec_server_command(command):
subprocess.call([sys.executable, server_path, command])
class MonitorProfile(object):
"""
This is a simple profile class, used to represent configuration of the file
monitor service.
"""
def __init__(self, key):
self.key = key
self.dirs = eval(edbob.config.require('edbob.filemon', '%s.dirs' % key))
if not self.dirs:
raise ConfigError('edbob.filemon', '%s.dirs' % key)
self.actions = eval(edbob.config.require('edbob.filemon', '%s.actions' % key))
if not self.actions:
raise ConfigError('edbob.filemon', '%s.actions' % key)
def monitor_win32(path, include_subdirs=False):
"""
This is the workhorse of file monitoring on the Windows platform. It is a

View file

@ -32,9 +32,9 @@ import time
import Queue
import edbob
from edbob.filemon import MonitorProfile
from edbob.filemon.win32 import WatcherWin32, ACTION_CREATE, ACTION_UPDATE
from edbob.win32 import file_is_free
from edbob.filemon import (MonitorProfile, WatcherWin32,
ACTION_CREATE, ACTION_UPDATE)
import sys
if sys.platform == 'win32': # docs should build for everyone