indenture/indenture.py
2012-08-17 18:45:18 -07:00

317 lines
9 KiB
Python

#!/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