135 lines
3.2 KiB
Python
Executable File
135 lines
3.2 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import re
|
|
from email.utils import parsedate
|
|
from time import mktime
|
|
from datetime import datetime
|
|
from os import popen
|
|
import os
|
|
from sys import argv,stderr,stdout
|
|
import getopt
|
|
|
|
|
|
opts, args = getopt.getopt(argv[1:],None, ['svg'])
|
|
needsvg = False
|
|
for o, a in opts:
|
|
if o == "--svg":
|
|
needsvg = True
|
|
extfolder = False
|
|
if len(args) == 1:
|
|
extfolder = True
|
|
targetfolder = args[0]
|
|
|
|
|
|
fc=0
|
|
locs=0
|
|
adds=None
|
|
cmt=None
|
|
|
|
h=[]
|
|
|
|
def pop():
|
|
if adds is not None:
|
|
pstr="%s %8u %5s %5s %7s %s \t%s"%(d,locs,'+'+str(adds),'-'+str(dels),hsh,who,cmt.strip())
|
|
if needsvg: stderr.write(pstr+'\n')
|
|
else: print(pstr)
|
|
h.append((d,locs,adds,dels,hsh,who,cmt))
|
|
|
|
prevfolder = os.getcwd()
|
|
if extfolder:
|
|
os.chdir(targetfolder)
|
|
|
|
for x in popen('git log --no-color --reverse -p'):
|
|
if x.startswith('commit'):
|
|
pop()
|
|
hsh=x[7:14];
|
|
if x.startswith('Author'):
|
|
who=x.replace("Author: ",'').replace('\n','');
|
|
who=re.sub(">.*","",who);
|
|
who=re.sub(".*<","",who);
|
|
if x.startswith('Date'):
|
|
fc=1
|
|
d=datetime(*parsedate(x[5:])[:7])
|
|
t=mktime(parsedate(x[5:]))
|
|
adds=0
|
|
dels=0
|
|
if fc==2:
|
|
cmt=x[:-1]
|
|
fc=0
|
|
if fc==1:
|
|
if len(x)==1: fc=2
|
|
if x.startswith('+') and not x.startswith('+++'):
|
|
adds+=1
|
|
locs+=1
|
|
if x.startswith('-') and not x.startswith('---'):
|
|
dels+=1
|
|
locs-=1
|
|
|
|
pop()
|
|
os.chdir(prevfolder)
|
|
|
|
def makesvg():
|
|
def quoteone(x):
|
|
if x in 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789': return x
|
|
return "&#x%02x;"%(ord(x),)
|
|
|
|
def quote(s):
|
|
return ''.join([quoteone(x) for x in s])
|
|
|
|
mlocs=max([locs for d,locs,adds,dels,hsh,who,cmt in h])
|
|
yscale=800.0/mlocs
|
|
|
|
svg=stdout
|
|
svg.write("""<?xml version="1.0" standalone="no"?>"""
|
|
"""<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">"""
|
|
"""<svg preserveAspectRatio="none" width="100%%" height="100%%" viewBox="0 0 %u %u" version="1.1" xmlns="http://www.w3.org/2000/svg">"""%(25*len(h),mlocs*yscale))
|
|
|
|
svg.write("""<style>"""
|
|
"""rect.o{opacity:0}"""
|
|
"""rect.o:hover{opacity:0.2}"""
|
|
""".a{fill:none;stroke:black;stroke-width:2}"""
|
|
"""</style>""")
|
|
|
|
def rect(x,y,w,h,c,a=''):
|
|
svg.write("""<rect x="%u" y="%u" width="%u" height="%u" style="%s" %s/>"""
|
|
%(x,y,w,h,c,a))
|
|
|
|
|
|
ps=[]
|
|
bl=[]
|
|
tx=[]
|
|
x=25
|
|
for d,locs,adds,dels,hsh,who,cmt in h:
|
|
y=(mlocs-locs)*yscale
|
|
bl.append((x-1,y,3,dels*yscale,"fill:rgb(0,0,255)"))
|
|
bl.append((x-1,y-adds*yscale,3,adds*yscale,"fill:rgb(0,255,0)"))
|
|
|
|
bl.append((x-12,0,25,mlocs*yscale,'',
|
|
"""title="%s %8u %5s %5s %s" """%(d,locs,'+'+str(adds),'-'+str(dels),quote(cmt.strip()))
|
|
+"""class="o" """))
|
|
|
|
ps.append("%u,%u"%(x,y))
|
|
x+=25
|
|
|
|
svg.write("""\n""")
|
|
svg.write("""<polyline points="0,%u %u,%u" class="a"/>"""%(mlocs*yscale,x,mlocs*yscale,))
|
|
svg.write("""<polyline points="25,0 25,%u" class="a"/>"""%(mlocs*yscale+25,))
|
|
|
|
it=pow(10,len(str(mlocs))-2)
|
|
for i in range(it,mlocs,it):
|
|
svg.write("""<polyline points="0,%u %u,%u" class="a" style="stroke:rgb(200,200,200)"/>"""%(mlocs*yscale-i*yscale,x,mlocs*yscale-i*yscale,))
|
|
svg.write("""\n""")
|
|
|
|
for b in bl:
|
|
rect(*b)
|
|
svg.write("""\n""")
|
|
|
|
svg.write("""<polyline points="%s" class="a" style="stroke:red"/>"""%(' '.join(ps),))
|
|
|
|
|
|
|
|
|
|
svg.write("""</svg>\n""")
|
|
|
|
if needsvg: makesvg()
|