Skip to content

Instantly share code, notes, and snippets.

@koreno
Last active February 14, 2021 12:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koreno/4890b990a231424858f83cf118ff3c96 to your computer and use it in GitHub Desktop.
Save koreno/4890b990a231424858f83cf118ff3c96 to your computer and use it in GitHub Desktop.
import re
import time
import linecache
from subprocess import check_output
DAY = 60 * 60 * 24
BLAME_REGEX = re.compile(
r"(?P<commit>\w+)\s+"
r"(?P<file>\S+)\s+"
r"\(<(?P<author>\S+@.*)>\s+"
r"(?P<timestamp>[-\d]+ [:\d]+ [-+]\d+)\s+"
r"(?P<lineno>\d+)\) "
r"(?P<line>.*)"
)
def inject_blame(fname):
raw = check_output(["git", "blame", fname, "-ef"])
now = time.time()
linecache.getlines(fname) # force-load the file to cache
cache = linecache.cache[fname] # extract the cache entry
annotated_lines = []
for line in raw.decode().splitlines():
match = BLAME_REGEX.match(line)
if match:
parsed = match.groupdict()
# convert the timestamp to something more user-friendly
line_time = time.mktime(time.strptime(parsed['timestamp'], "%Y-%m-%d %H:%M:%S %z"))
time_ago = now - line_time
if time_ago <= DAY:
when = "today"
else:
when = f"{int(round(time_ago / DAY))}d ago"
# format the line with annotation
line = "{line:80} ### edited {when} by {author} in {commit:8.8}".format(when=when, **parsed)
else:
pass # our regex failed - we keep the line untouched
annotated_lines.append(line.rstrip("") + "\n")
# unpack the cache entry, discarding the 'lines' element
size, mtime, _, fullname = cache
# replacing the cache entry with thew annotated lines element
linecache.cache[fname] = size, mtime, annotated_lines, fullname
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment