#!/usr/bin/env python # Fire up virtualenv activate_this = "venv/bin/activate_this.py" execfile(activate_this, dict(__file__=activate_this)) ###### ### What are we going to be using today? ###### import os import time import uuid from subprocess import call import sqlite3 ###### ### Classes! ##### class _db: def _connect(self, db="jobs.db"): """ connect() connects to the sqlite database, uses a try/except to return False if it fails """ try: self._conn = sqlite3.connect('jobs.db') self._c = self._conn.cursor() return True except: return False def commit(self): """ commit() commits any pending changes to the database file. """ return self._conn.commit() def query(self,query,returns="list",timeout=10,db="jobs.db"): """ query() run a query against the sqlite database. will attempt to reconnect if necessary. will timeout after $timeout seconds. """ t = time.time() + timeout while True: try: self._c.execute(query) break except: if db != "jobs.db": self._connect(db=db) else: if not self._connect(): print "ERROR: Cannot connect to database." time.sleep(2) if time.time() > t: print 'ERROR: Query timed out.' break if returns == "list": return self._c.fetchall() elif returns == "one": return self._c.fetchone() # Job Class class Job: def __init__(self, due = time.time() + 3600, command = 'true', originator = 'indenture', completed = False, arguments = ''): self.arguments = arguments self.due = due self.command = command self.uuid = uuid.uuid4() self.originator = originator self.completed = completed def _full_exec(self): """ _full_exec() returns the full command to be executed with the arguments """ return self.command+' '+self.arguments def _disconnect(self): """ _disconnect() flushes writes to sqlite and closes the connection """ self._conn.commit() self._c.close() def describe(self,prints=True,returns=False): """ describe(): a public function that describes the job to be completed. """ description = [] description.append('UUID: ' + self.uuid) description.append('Commmand: ' + self._full_exec()) description.append('Due Date: ' + self.what_time()) if self.completed: description.append('Completion: Completed') else: description.append('Completion: Incomplete') if prints == True: print '\n'.join(description) if returns == True: return '\n'.join(description) def do_work(self): """ do_work() actually performs the work to be completed. """ print self._full_exec().split() r = call(self._full_exec().split()) if not r > 0: return True else: return False def open(self, uuid): """ open() runs a query to populate with the information of an existing job in the database """ jobsdb = _db() data = jobsdb.query('SELECT uuid,command,arguments,due,originator,completed \ FROM jobs WHERE uuid = "' + uuid + '" LIMIT 1;', returns="one") print data if data: (self.uuid, self.command, self.arguments, self.due, self.originator, self.completed) = data def save(self): """ save() saves the current job to the database. will determine if it's necessary insert a new job or update an old job. """ jobsdb = _db() test = 'SELECT uuid FROM jobs WHERE uuid = "' + str(self.uuid) + '";' if len(jobsdb.query(test,returns="list")) > 0: query = 'UPDATE jobs SET ' query += 'command = "' + self.command + '", ' query += 'arguments = "' + self.arguments + '", ' query += 'due = "' + str(self.due) + '", ' query += 'originator = "' + self.originator + '", ' if self.completed: query += 'completed = 1 ' else: query += 'completed = 0 ' query += 'WHERE uuid = "'+str(self.uuid)+'" LIMIT 1;' print query jobsdb.query(query) jobsdb.commit() else: query = 'INSERT INTO jobs (uuid, command, arguments, due, originator, completed) ' query += 'VALUES (' query += '"' + str(self.uuid) + '",' query += '"' + self.command + '",' query += '"' + self.arguments + '",' query += '"' + str(self.due) + '",' query += '"' + self.originator + '",' if self.completed: query += str(1) else: query += str(0) query += ');' jobsdb.query(query) jobsdb.commit() def what_time(self): """ what_time() returns a prettified version of the due date. """ return pretty_date(self.due) def what_work(self): """ what_work() public function to see what work is going to be done. """ return self._full_exec() ###### ### Helper Functions ###### def pretty_date(time=False): """ pretty_date() Get a datetime object or a int() Epoch timestamp and return a pretty string like 'an hour ago', 'Yesterday', '3 months ago', 'just now', etc """ from datetime import datetime now = datetime.now() if type(time) is int: d = datetime.fromtimestamp(time) elif type(time) is float: d = datetime.fromtimestamp(time) elif not time: diff = now - now if now > d: diff = now - d elif d > now: diff = d - now else: diff = now - now second_diff = diff.seconds day_diff = diff.days if now > d: if day_diff == 0: if second_diff < 10: return "just now" if second_diff < 60: return str(second_diff) + " seconds ago" if second_diff < 120: return "a minute ago" if second_diff < 3600: return str( second_diff / 60 ) + " minutes ago" if second_diff < 7200: return "an hour ago" if second_diff < 86400: return str( second_diff / 3600 ) + " hours ago" if day_diff == 1: return "Yesterday" if day_diff < 7: return str(day_diff) + " days ago" if day_diff < 31: return str(day_diff/7) + " weeks ago" if day_diff < 365: return str(day_diff/30) + " months ago" return str(day_diff/365) + " years ago" elif d > now: if day_diff == 0: if second_diff < 10: return "just now" if second_diff < 60: return str(second_diff) + " seconds from now" if second_diff < 120: return "a minute from now" if second_diff < 3600: return str( second_diff / 60 ) + " minutes from now" if second_diff < 7200: return "an hour from now" if second_diff < 86400: return str( second_diff / 3600 ) + " hours from now" if day_diff == 1: return "Tomorrow" if day_diff < 7: return str(day_diff) + " days from now" if day_diff < 31: return str(day_diff/7) + " weeks from now" if day_diff < 365: return str(day_diff/30) + " months from now" return str(day_diff/365) + " years from now" ###### ### General functions ###### def list_of_jobs(include_completed=False,only_past_due=True): """ list_of_jobs() returns a python list of all the outstanding jobs. """ query = "SELECT uuid FROM jobs" if include_completed == False and only_past_due == True: query += " WHERE completed = 0 and due <= " + str(time.time()) + ';' elif include_completed == False and only_past_due == False: query += " WHERE completed = 0;" elif include_completed == True and only_past_due == True: query += " WHERE due <= " + str(time.time()) + ';' jobsdb = _db() job_list = [] for row in jobsdb.query(query): j = Job() j.open(uuid=row[0]) job_list.append(j) return job_list def print_jobs(include_completed=False): """ print_jobs() list all the jobs that need to be done, does not include completed jobs by default. """ query = 'SELECT * FROM jobs' if include_completed == False: query += ' WHERE `completed` = 0' query += ';' jobsdb = _db() for row in jobsdb.query(query): print row