indenture/indenture.py

254 lines
7.8 KiB
Python

#!/usr/bin/env python
# Fire up virtualenv
activate_this = "venv/bin/activate_this.py"
execfile(activate_this, dict(__file__=activate_this))
import os
import time
import uuid
from subprocess import call
import sqlite3
# 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 _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 _full_exec(self):
""" _full_exec()
returns the full command to be executed with the arguments
"""
return self.command+' '+self.arguments
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:
self._connect()
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()
def _disconnect(self):
""" _disconnect()
flushes writes to sqlite and closes the connection
"""
self._conn.commit()
self._c.close()
def describe(self):
""" 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')
print '\n'.join(description)
return '\n'.join(description)
def do_work(self):
""" do_work()
actually performs the work to be completed.
"""
return call(self.full_exec().split())
def list_jobs(self, include_completed=False):
""" list_jobs(include_completed = False)
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 += ';'
for row in self._query(query):
print row
def open(self, uuid):
""" open()
runs a query to populate with the information of an existing job
in the database
"""
data = self._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.
"""
print 'Does this ID exist?'
test = 'SELECT uuid FROM jobs WHERE uuid = "' + str(self.uuid) + '";'
print test
if self._query(test):
print 'Yes.'
query = 'UPDATE jobs SET '
query += 'uuid = "' + str(self.uuid) + '", '
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 += ';'
print self._query(query)
self._conn.commit()
else:
print 'No.'
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 += ');'
print 'Executing: '
print query
self._query(query)
self._conn.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()
def pretty_date(time=False):
"""
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"