Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 177 lines (143 sloc) 5.89 KB
#!/usr/bin/python
# Copyright 2012:
#
# Nick Davidson <nicholas.davidson@gmail.com>,
# Simon Haswell <maxcady78@hotmail.co.uk>,
# Neil Williams <codehelp@debian.org>,
# James Bennet <github@james-bennet.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
# -*- coding: utf-8 -*-
import optparse
import pyinotify
import daemon
import pybit
import os
import sys
import logging
import signal
import subprocess
import time
from pybit.daemonlogger import LoggingDaemonContext, FileLikeLogger
from pyinotify import ProcessEvent
META="PYBIT_WATCHER_"
PIDFILE = "/var/run/pybit-watcher.pid"
def signal_handler(signal, frame):
try:
print '\nClosing %s' % os.path.basename(__file__)
sys.exit (os.EX_OK)
except Exception as e:
raise Exception('Error in signal handler: ' + str(e))
return
def getDaemonLogger (filePath, format = None) :
FORMAT = format or '%(asctime)s %(msg)s'
logging.basicConfig(filename=filePath, format=FORMAT, level=logging.DEBUG)
return logging.getLogger()
class EventHandler(pyinotify.ProcessEvent):
def process_IN_CREATE(self, event):
if os.path.isfile(event.pathname) and event.pathname.endswith(".changes"):
logging.debug("Sleeping for %ss" % self.sleeptime)
time.sleep(self.sleeptime)
if event.path in self.settings['rules'] :
rule = self.settings['rules'][event.path]
cmd = "reprepro -b %s processincoming %s" % (rule['repobase'], rule['rule'])
if ('user' in self.settings and
self.settings['user'] != ''):
cmd = "su %s -c '%s'" % (self.settings['user'], cmd)
if ('dryrun' not in self.settings or
self.settings['dryrun'] == False):
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
(stdout, stderr) = process.communicate()
if process.returncode:
logging.debug(stderr)
logging.debug("reprepo command failed with code: %s" % process.returncode)
else:
logging.debug(cmd)
else:
logging.debug("dry-run: %s" % cmd)
else:
logging.debug("couldn't find a rule which matched the watched path.")
def __init__(self, settings):
self.settings = settings
self.sleeptime = 3
if 'sleeptime' in self.settings:
self.sleeptime = self.settings['sleeptime']
ProcessEvent.__init__(self)
def run(settings):
try:
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
except Exception as e:
raise Exception('Error configuring signal handler: ' + str(e))
mask = pyinotify.IN_CREATE
if 'dryrun' in settings and settings['dryrun'] == True:
logging.debug("Starting in dryrun mode")
wm = pyinotify.WatchManager()
handler = EventHandler(settings)
notifier = pyinotify.Notifier(wm, handler)
for path in settings['rules'].keys():
wdd = wm.add_watch(path, mask, rec=True)
notifier.loop()
if __name__ == '__main__':
parser = optparse.OptionParser()
#options we can override in the config file.
groupConfigFile = optparse.OptionGroup(parser,
"Config File Defaults","All the options which have defaults read from a config file.")
groupConfigFile.add_option("--dry-run", dest="dryrun", action="store_true",
help="Controls if we simulate or do we actually run.", metavar=META + "DRYRUN")
groupConfigFile.add_option("--user", dest="user",
help="Which user do we run as?", metavar=META + "USER")
groupConfigFile.add_option("--sleeptime", dest="sleeptime",
help="The number of seconds we wait after a changes file is created before we run the reprepro command.",
metavar=META + "SLEEPTIME")
parser.add_option("--conf_file", dest="conf_file", default="watcher/watcher.conf",
help="Config file to read settings from, defaults to watcher.conf which will be read from configs/watcher and /etc/pybit/watcher in turn.",
metavar=META + "CONF_FILE")
parser.add_option("-v", dest="verbose", action="store_true", default=False,
help="Turn on verbose messages.", metavar=META+"VERBOSE")
parser.add_option("-d", dest="daemonise", action="store_true", default=False,
help="Daemonise with output going to /var/log/pybit-watcher", metavar=META+"DAEMONISE")
(options, args) = parser.parse_args()
context = None
if options.daemonise :
testLogger = getDaemonLogger('/var/log/pybitwatcher.log')
stdoutLogger = getDaemonLogger('/dev/null')
stderrLogger = getDaemonLogger('/dev/null')
context = LoggingDaemonContext()
context.loggers_preserve=[testLogger]
context.stdout_logger = stdoutLogger
context.stderr_logger = stderrLogger
logging.debug ("I: Daemonised")
else :
# FORMAT = format or '%(asctime)s %(msg)s'
logging.basicConfig(level=logging.DEBUG)
logging.debug ("I: Not daemonised")
(settings, opened_path) = pybit.load_settings(options.conf_file)
if settings == {}:
logging.debug("Couldn't load configuration from %s" % opened_path)
sys.exit(-1)
if 'configured' in settings and settings['configured'] == False:
logging.debug ("Please configure the Reprepro watcher. Edit %s" % opened_path)
sys.exit(os.EX_OK)
settings = pybit.merge_options(settings, groupConfigFile, options)
if options.daemonise:
with context :
pid = str(os.getpid())
file(PIDFILE, 'w').write(pid)
run(settings)
else:
logging.debug ("I: Running watcher...")
run(settings)