From 80d9c9c42e877de154e6a0c7ce4c725a1448c51f Mon Sep 17 00:00:00 2001 From: Matthew Vernon Date: Tue, 2 Aug 2011 18:34:04 +0100 Subject: [PATCH] add blame command --- Servus-chiark.py | 27 ++++++++++++++++++- commands.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++- servus.html | 15 +++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/Servus-chiark.py b/Servus-chiark.py index e0eb741..26d46a1 100644 --- a/Servus-chiark.py +++ b/Servus-chiark.py @@ -35,7 +35,7 @@ owner = "Emperor" # Everything else in this file is configuration-specific. -import os, time, re, twitter +import os, time, re, twitter, subprocess, sys # Most command implementations are stored in a separate module. import commands as c @@ -51,6 +51,30 @@ class fish: DoS=0 Boring_Git='Nobody' quotatime=0 + last="" + +# load the "blame" details for a file +def loadblame(filename): + p=subprocess.Popen(["git","blame","-s",filename], + stdout=subprocess.PIPE,stderr=subprocess.PIPE) + out,err=p.communicate() + if len(err)>0: + sys.exit("git blame failure: %s" % err) + bdb={} + lines=out.split("\n") + for line in lines: + l=line.split() + if len(line.strip())>0: + commit=l[0] + thing=' '.join(l[2:]) + bdb[thing]=commit + keys=bdb.keys() + return bdb,keys + +#set up blame dbs for trouts/flirts/slashes +tbdb,tbdbk=loadblame("trouts") +fbdb,fbdbk=loadblame("flirts") +sbdb,sbdbk=loadblame("slashes") # load a file full of flirts or trouts def __load(filename): @@ -170,6 +194,7 @@ commands = {"karma": (c.karmaq,karmadb), "nws": (c.nsfwq,urldb), "units": c.unitq, "currency":c.currencyq, + "blame": (c.blameq,fish,tbdb,tbdbk,fbdb,fbdbk,sbdb,sbdbk), "help": c.helpq, "say": c.sayq, "do": c.doq, diff --git a/commands.py b/commands.py index 882b67a..bbcaeb8 100644 --- a/commands.py +++ b/commands.py @@ -1,5 +1,5 @@ # Part of Acrobat. -import string, cPickle, random, urllib, sys, time, re, os, twitter +import string, cPickle, random, urllib, sys, time, re, os, twitter, subprocess, datetime from irclib import irc_lower, nm_to_n # query karma @@ -84,6 +84,7 @@ def troutq(bot, cmd, nick, conn, public, cfg): return me = bot.connection.get_nickname() trout_msg = random.choice(fishlist) + fishpond.last=trout_msg # The bot won't trout or flirt with itself; if irc_lower(me) == irc_lower(target): target = nick @@ -262,6 +263,71 @@ def currencyq(bot, cmd, nick, conn, public): bot.automsg(public,nick,"The web's broken. Waah!") +### extract the commit message and timestamp for commit +def __getcommitinfo(commit): + cmd=["git","log","-n","1","--pretty=format:%ct|%s",commit] + x=subprocess.Popen(cmd, + stdout=subprocess.PIPE,stderr=subprocess.PIPE) + out,err=x.communicate() + + if len(err): + return(err) + + ts,mes=out.split('|') + when=datetime.date.fromtimestamp(float(ts)) + return mes.strip(), when + +###Return an array of commit messages and timestamps for lines in db that match what +def __getcommits(db,keys,what): + ans=[] + for k in keys: + if what in k: + ret=__getcommitinfo(db[k]) + if len(ret)==1: #error message + return ["Error message from git blame: %s" % ret] + else: + ans.append( (k,ret[0],ret[1]) ) + return ans + +###search all three databases for what +def __getall(tdb,tdbk,fdb,fdbk,sdb,sdbk,what): + if what.strip()=="": + return [] + tans=__getcommits(tdb,tdbk,what) + fans=__getcommits(fdb,fdbk,what) + sans=__getcommits(sdb,sdbk,what) + return tans+fans+sans + +def blameq(bot,cmd,nick,conn,public,fish,tdb,tdbk,fdb,fdbk,sdb,sdbk): + clist=cmd.split() + cwhat=' '.join(clist[2:]) + if clist[1]=="#last": + ans=__getall(tdb,tdbk,fdb,fdbk,sdb,sdbk,fish.last) + elif clist[1]=="#trouts" or clist[1]=="#trout": + ans=__getcommits(tdb,tdbk,cwhat) + elif clist[1]=="#flirts" or clist[1]=="#flirt": + ans=__getcommits(fdb,fdbk,cwhat) + elif clist[1]=="#slashes" or clist[1]=="#slash": + ans=__getcommits(sdb,sdbk,cwhat) + else: + cwhat=' '.join(clist[1:]) + ans=__getall(tdb,tdbk,fdb,fdbk,sdb,sdbk,cwhat) + if len(ans)==0: + bot.automsg(public,nick,"No match found") + elif len(ans)==1: + if len(ans[0])==1: + bot.automsg(public,nick,ans[0]) + else: + bot.automsg(public,nick,"Added %s: %s" % (ans[0][2].isoformat(),ans[0][1])) + elif len(ans)>4: + bot.automsg(public,nick,"I found %d matches, which is too many. Please be more specific!" % (len(ans)) ) + else: + for a in ans: + if len(a)==1: + bot.automsg(public,nick,a) + else: + bot.automsg(public,nick,"'%s' added on %s: %s" % (a[0],a[2].isoformat(),a[1])) + ### say to msg/channel def sayq(bot, cmd, nick, conn, public): if irc_lower(nick) == irc_lower(bot.owner): diff --git a/servus.html b/servus.html index 41c76f5..b96a258 100644 --- a/servus.html +++ b/servus.html @@ -38,6 +38,7 @@ class="code">~command. Alternatively, you may pass commands by

Commands