add linux file monitor
This commit is contained in:
		
							parent
							
								
									b3b4e40bcf
								
							
						
					
					
						commit
						79c4bfa289
					
				
					 5 changed files with 202 additions and 31 deletions
				
			
		| 
						 | 
				
			
			@ -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
									
								
							
							
						
						
									
										46
									
								
								edbob/filemon/__init__.py
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										120
									
								
								edbob/filemon/linux.py
									
										
									
									
									
										Normal 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)
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue