#!/usr/bin/python
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

import sys
import os
import time
import subprocess
import atexit
import signal
import syslog
import psycopg2

def update_handler():
	r=subprocess.call("/usr/sbin/update-packagelists")
	if r!=0:
		log("error calling update-packagelists")

def update_handler_puppet():
	r=subprocess.call("/usr/sbin/update-packagelists-puppet")
	if r!=0:
		log("error calling update-packagelists-puppet")

def database_changed(cursor,serial,id,handler):
        cursor.execute("UPDATE notification SET ack=%d WHERE id=%d" % (serial,id))
        # print " update"
        handler() 
        time.sleep(3)

def watch_db(db,id,handler):
        cursor=db.cursor()
        while True:
                time.sleep(3)
                cursor.execute("SELECT serial,ack FROM notification WHERE id=%d" % (id))
                result=cursor.fetchone()
                serial,ack=result
                # print serial,ack
                if ack<serial:
                        database_changed(cursor,serial,id,handler)
		# the select statement above starts a transaction, so
		# commit now
        	cursor.connection.commit()

def daemon(name):
        pidfile='/var/run/%s.pid' % (name)
	if os.access(pidfile,os.R_OK):
		sys.stderr.write('%s already running, %s exists\n' % (name,pidfile))
		sys.exit(2)
        # do the double fork()
        pid=os.fork()
        if pid==0:  # child process
                os.setsid()
                pid=os.fork()
                if pid==0:  # second child
                        signal.signal(signal.SIGTERM, lambda signum, stack_frame: exit(0))
                        os.chdir('/')
                        sys.stdin.close()
			os.close(0)
                        sys.stdin=open('/dev/null','w+')
                        if sys.stdin.fileno()!=0:
                                sys.stderr.write('error redirecting stdin')
                                sys.exit(3)
                        sys.stdout.close()
                        sys.stderr.close()
                        os.dup2(0,1)
                        os.dup2(0,2)
                        f=open(pidfile,'w+')
                        f.write(str(os.getpid())+'\n')
                        f.close()
                        atexit.register(lambda:os.remove(pidfile))
                else:
                        os._exit(0)
        else:
                os._exit(0)

def log(message):
        syslog.syslog(message)
 
if __name__=="__main__":
        debug=True
        use_puppet=False
        handler=update_handler
	if len(sys.argv)<3:
		sys.stderr.write('Usage: %s <database> <username> [puppet]\n' % (sys.argv[0]))
		sys.exit(1)

        dbname=sys.argv[1]
        username=sys.argv[2]
        if len(sys.argv)==4 and sys.argv[3]=='puppet':
                use_puppet=True 
                handler=update_handler_puppet

        daemon('packagemanager-watchdb')

        while True:
                if debug:
                        log("connecting to database %s" % (dbname))

                try:
                        db=psycopg2.connect("dbname=%s user=%s" % (dbname,username))
                        watch_db(db,1,handler)

                except psycopg2.DatabaseError:
                        if debug:
                                log("connection failed")
                        time.sleep(3)

                if not db.closed:
                        db.close()
