dotfiles/bin/ptw
michener 1af0bb64b4 Update ptw
git-svn-id: http://photonzero.com/dotfiles/trunk@98 23f722f6-122a-0410-8cef-c75bd312dd78
2011-05-05 19:28:34 +00:00

282 lines
9.5 KiB
Python
Executable file

#!/usr/bin/env python
import json
import os.path
import time
import sys
from optparse import OptionParser
from operator import itemgetter
# Start Parser I grabbed from http://pyparsing.wikispaces.com/UnderDevelopment#toc0
from datetime import datetime, timedelta
from pyparsing import *
import calendar
# string conversion parse actions
def convertToTimedelta(toks):
unit = toks.timeunit.lower().rstrip("s")
td = {
'week' : timedelta(7),
'day' : timedelta(1),
'hour' : timedelta(0,0,0,0,0,1),
'hr' : timedelta(0,0,0,0,0,1),
'minute' : timedelta(0,0,0,0,1),
'min' : timedelta(0,0,0,0,1),
'second' : timedelta(0,1),
'sec' : timedelta(0,1),
}[unit]
if toks.qty:
td *= int(toks.qty)
x = 0
if toks.dir == "":
x = 1
else:
x = toks.dir
if x > 0:
td *= -x
else:
td *= x
toks["timeOffset"] = td
def convertToDay(toks):
now = datetime.now()
if "wkdayRef" in toks:
todaynum = now.weekday()
daynames = [n.lower() for n in calendar.day_name]
nameddaynum = daynames.index(toks.wkdayRef.day.lower())
if toks.wkdayRef.dir > 0:
daydiff = (nameddaynum + 7 - todaynum) % 7
else:
daydiff = -((todaynum + 7 - nameddaynum) % 7)
toks["absTime"] = datetime(now.year, now.month, now.day)+timedelta(daydiff)
else:
name = toks.name.lower()
toks["absTime"] = {
"now" : now,
"today" : datetime(now.year, now.month, now.day),
"yesterday" : datetime(now.year, now.month, now.day)+timedelta(-1),
"tomorrow" : datetime(now.year, now.month, now.day)+timedelta(+1),
}[name]
def convertToAbsTime(toks):
now = datetime.now()
if "dayRef" in toks:
day = toks.dayRef.absTime
day = datetime(day.year, day.month, day.day)
else:
day = datetime(now.year, now.month, now.day)
if "timeOfDay" in toks:
if isinstance(toks.timeOfDay,basestring):
timeOfDay = {
"now" : timedelta(0, (now.hour*60+now.minute)*60+now.second, now.microsecond),
"noon" : timedelta(0,0,0,0,0,12),
"midnight" : timedelta(),
}[toks.timeOfDay]
else:
hhmmss = toks.timeparts
if hhmmss.miltime:
hh,mm = hhmmss.miltime
ss = 0
else:
hh,mm,ss = (hhmmss.HH % 12), hhmmss.MM, hhmmss.SS
if not mm: mm = 0
if not ss: ss = 0
if toks.timeOfDay.ampm == 'pm':
hh += 12
timeOfDay = timedelta(0, (hh*60+mm)*60+ss, 0)
else:
timeOfDay = timedelta(0, (now.hour*60+now.minute)*60+now.second, now.microsecond)
toks["absTime"] = day + timeOfDay
def calculateTime(toks):
if toks.absTime:
absTime = toks.absTime
else:
absTime = datetime.now()
if toks.timeOffset:
absTime += toks.timeOffset
toks["calculatedTime"] = absTime
# grammar definitions
CL = CaselessLiteral
today, tomorrow, yesterday, noon, midnight, now = map( CL,
"today tomorrow yesterday noon midnight now".split())
plural = lambda s : Combine(CL(s) + Optional(CL("s")))
week, day, hour, hr, minute, min, second, sec = map( plural,
"week day hour hr minute min second sec".split())
am = CL("am")
pm = CL("pm")
COLON = Suppress(':')
# are these actually operators?
in_ = CL("in").setParseAction(replaceWith(1))
from_ = CL("from").setParseAction(replaceWith(1))
before = CL("before").setParseAction(replaceWith(-1))
after = CL("after").setParseAction(replaceWith(1))
ago = CL("ago").setParseAction(replaceWith(-1))
next_ = CL("next").setParseAction(replaceWith(1))
last_ = CL("last").setParseAction(replaceWith(-1))
couple = (Optional(CL("a")) + CL("couple") + Optional(CL("of"))).setParseAction(replaceWith(2))
a_qty = CL("a").setParseAction(replaceWith(1))
integer = Word(nums).setParseAction(lambda t:int(t[0]))
int4 = Group(Word(nums,exact=4).setParseAction(lambda t: [int(t[0][:2]),int(t[0][2:])] ))
qty = integer | couple | a_qty
dayName = oneOf( list(calendar.day_name) + [x.lower() for x in calendar.day_name] )
dayOffset = (qty("qty") + (week | day)("timeunit"))
dayFwdBack = (from_ + now.suppress() | ago)("dir")
weekdayRef = (Optional(next_ | last_, -1 )("dir") + dayName("day"))
dayRef = Optional( (dayOffset + (before | after | from_)("dir") ).setParseAction(convertToTimedelta) ) + \
((yesterday | today | tomorrow)("name")|
weekdayRef("wkdayRef")).setParseAction(convertToDay)
todayRef = (dayOffset + dayFwdBack).setParseAction(convertToTimedelta) | \
(in_("dir") + qty("qty") + day("timeunit")).setParseAction(convertToTimedelta)
dayTimeSpec = dayRef | todayRef
dayTimeSpec.setParseAction(calculateTime)
hourMinuteOrSecond = (hour | hr | minute | min | second | sec)
timespec = Group(int4("miltime") |
integer("HH") +
Optional(COLON + integer("MM")) +
Optional(COLON + integer("SS")) + (am | pm)("ampm")
)
absTimeSpec = ((noon | midnight | now | timespec("timeparts"))("timeOfDay") +
Optional(dayRef)("dayRef"))
absTimeSpec.setParseAction(convertToAbsTime,calculateTime)
relTimeSpec = qty("qty") + hourMinuteOrSecond("timeunit") + \
(from_ | before | after)("dir") + \
absTimeSpec("absTime") | \
qty("qty") + hourMinuteOrSecond("timeunit") + ago("dir") | \
in_ + qty("qty") + hourMinuteOrSecond("timeunit") | \
qty("qty") + hourMinuteOrSecond("timeunit")
relTimeSpec.setParseAction(convertToTimedelta,calculateTime)
nlTimeExpression = (absTimeSpec | dayTimeSpec | relTimeSpec)
# End parser
def db_append(data):
db_file = open(os.path.expanduser("~/.ptwdb"), "r")
db = json.load(db_file)
db_file.close()
if not timestamp_and_text_exists(data["timestamp"], data["text"], db):
db.append(data)
db_file = open(os.path.expanduser("~/.ptwdb"), "w")
json.dump(db, db_file, indent=2)
db_file.close()
def db_new():
db_file = open(os.path.expanduser("~/.ptwdb"), "w")
json.dump([], db_file)
db_file.close()
def db_get(count=None, since=None):
if count is None and since is None:
count = 10
if count is None and since is not None:
count = 500000
out = []
db_file = open(os.path.expanduser("~/.ptwdb"), "r")
db = json.load(db_file)
db_file.close()
db.sort(key=itemgetter(u"timestamp"))
while count != 0:
if len(db) == 0:
break
x = db.pop()
if since is not None and x["timestamp"] < since:
break
out.append(x)
count -= 1
return out
def timestamp_and_text_exists(timestamp, text, db):
for x in db:
if x["timestamp"] == timestamp:
if text.startswith(x["text"]):
return True
return False
def format(l):
out = []
for x in l:
timestr = time.strftime("%a %b %d %Y @ %I:%M%p",
time.localtime(x["timestamp"]))
out.append("%s: %s" % (timestr, x["text"]))
return out
parser = OptionParser()
parser.add_option("--host", dest="hostname", help="Hostname from post",
metavar="HOSTNAME", default="localhost")
parser.add_option("--client", dest="client", help="Client for post",
default="Command Line", metavar="CLIENT")
parser.add_option("-n", dest="num", help="Number of posts to show",
type="int", default=None, metavar="N")
parser.add_option("--source", dest="import_source", help="Source of git imports",
type="str", default="", metavar="STR")
parser.add_option("-s", "--since", dest="since", help="Number of posts to show",
default=None, metavar="SINCE")
parser.add_option("-v", "--verbose", dest="verbose", help="Debug output",
default=False, action="store_true")
(options, args) = parser.parse_args()
if len(args) < 1:
parser.print_help()
exit()
command = args[0]
text = " ".join(args[1:])
if command == "post":
if len(text) < 1:
parser.print_help()
exit()
data = {"timestamp" : time.time(), "text" : text, "client" : options.client,
"hostname" : options.hostname }
if not os.path.exists(os.path.expanduser("~/.ptwdb")):
db_new()
db_append(data)
elif command == "get":
if options.since is not None:
p = nlTimeExpression.parseString(options.since)
if "calculatedTime" in p:
options.since = time.mktime(p.calculatedTime.timetuple())
if options.verbose:
print p.calculatedTime.isoformat()
else:
options.since = None
for x in format(db_get(options.num, options.since)):
print x
elif command == "since":
if len(args) < 2:
parser.print_help()
exit()
p = nlTimeExpression.parseString(text)
if "calculatedTime" in p:
options.since = time.mktime(p.calculatedTime.timetuple())
if options.verbose:
print p.calculatedTime.isoformat()
else:
options.since = None
for x in format(db_get(options.num, options.since)):
print x
elif command == "import":
for line in sys.stdin:
fields = line.strip().split("\t")
ts = int(fields[0])
text = fields[1]
if options.import_source != "":
text = "%s: %s" % (options.import_source, text)
data = {"timestamp" : ts, "text" : text, "client" : options.client,
"hostname" : options.hostname }
if not os.path.exists(os.path.expanduser("~/.ptwdb")):
db_new()
db_append(data)
else:
print "Invalid Command"
parser.print_help()
exit()