# -*- coding: utf-8 -*- ############################################################################### # CronCommand - Cron Paste Script Command # # --------------------------------------------------------------------------- # # Copyright (c) 2009 Raoul Snyman # # --------------------------------------------------------------------------- # # This library is free software; you can redistribute it and/or modify it # # under the terms of the GNU Lesser General Public License as published by # # the Free Software Foundation; either version 2.1 of the License, or (at # # your option) any later version. # # # # This library 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 Lesser General Public # # License for more details. # # # # You should have received a copy of the GNU Lesser General Public License # # along with this library; if not, write to the Free Software Foundation, # # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # ############################################################################### """ The croncommand module allows you to register a ``cron`` command with paster. The aim of this command is to give your Pylons application the ability to run a set of scheduled tasks via a UNIX cron job. By simply giving your controllers a ``cron`` method, this command will detect all your controllers, and call the ``cron`` method when run. To make use of this module: 1. Create a ``commands`` module in your Pylons app's directory (i.e. on the same level as ``controllers``). 2. Place this module file in that directory. 3. Modify setup.py in the top-most directory and add the following two lines in the ``entry_points`` variable:: [paste.paster_command] cron = myapp.commands.croncommand:CronCommand 4. Import the ``CronInterval`` class at the top of your controller file:: from myapp.commands.croncommand import CronInterval 5. Add a ``cron`` method to all the controllers you want responding to the cron system:: def cron(self, interval): if interval == CronInterval.Daily: # do some daily stuff here else: # do some minute-level stuff here 6. In your /etc/crontab.d directory, add a file called ``myapp`` and put something like this in it:: * * * * * /usr/bin/paster cron 7. In your /etc/crontab.hourly directory, add a file called ``myapp-hourly`` and put something like this in it:: 0 * * * * /usr/bin/paster cron hourly 8. Do the same as the above step for other cron settings like weekly. 9. Reinstall your app using the ``easy_install`` command, this will register the ``cron`` command in paster. """ import os from inspect import getmembers, isclass from paste.script.command import Command from ..lib.base import BaseController class CronInterval(object): """ Enumeration-style class. This class specifies the different types of cron intervals. """ Default = 0 Hourly = 1 Daily = 2 Weekly = 3 Monthly = 4 class CronCommand(Command): """ Used as a cron job. Run a set of tasks on a regular basis. The cron command will run a set of actions needed by the project on a regular basis. By specifying an argument, you can run specify that certain things are run at certain intervals. If no argument is given, the command runs the minute-level tasks. Example usage:: $ paster cron $ paster cron hourly $ paster cron daily **Arguments** (no argument) Run the tasks that should be run immediately or most often. ``hourly`` Run the hourly tasks. ``daily`` Run the daily tasks. ``weekly`` Run the weekly tasks. ``monthly`` Run the monthly tasks. """ summary = __doc__.splitlines()[1] usage = '\n' + __doc__ min_args = 0 max_args = 1 group_name = 'myapp' default_verbosity = 3 parser = Command.standard_parser(simulate=True) def __init__(self, name): Command.__init__(self, name) self.controllers = [] self.load_controllers() def command(self): """ Run the command. """ if len(self.args): frequency = str(self.args[0]).lower().trim() if frequency == u'hourly': for controller in self.controllers: controller.cron(CronInterval.Hourly) elif frequency == u'daily': for controller in self.controllers: controller.cron(CronInterval.Daily) elif frequency == u'weekly': for controller in self.controllers: controller.cron(CronInterval.Weekly) elif frequency == 'monthly': for controller in self.controllers: controller.cron(CronInterval.Monthly) else: for controller in self.controllers: controller.cron(CronInterval.Default) def load_controllers(self): base_path = os.path.abspath(os.path.join(os.path.dirname( os.path.abspath(__file__)), u'..', u'..')) project_path = os.path.abspath(os.path.join(os.path.dirname( os.path.abspath(__file__)), u'..')) controller_path = os.path.abspath(os.path.join(project_path, u'controllers')) for root, dirs, files in os.walk(controller_path): for name in files: if name.endswith(u'.py') and not name.startswith(u'__'): path = os.path.abspath(os.path.join(root, name)) modulename, pyext = os.path.splitext(path) prefix_len = len(os.path.commonprefix([base_path, path])) + 1 modulename = modulename.replace(os.path.sep, '.')[prefix_len:] try: members = __import__(modulename, globals(), locals(), ['*']) except: pass controller_classes = BaseController.__subclasses__() self.controllers = [] for c in controller_classes: if hasattr(c, 'cron'): try: controller = c() self.controllers.append(controller) except: pass