Skip to content

Instantly share code, notes, and snippets.

@jesskfullwood
Created January 10, 2019 13:23
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 jesskfullwood/17928e33ce9312e5281495214d7c73d3 to your computer and use it in GitHub Desktop.
Save jesskfullwood/17928e33ce9312e5281495214d7c73d3 to your computer and use it in GitHub Desktop.
librsvg oxidation chart
import json
import os
import re
import pandas
import matplotlib.pyplot as plt
import dateutil
from subprocess import run, PIPE
repo = "/home/jess/repo/librsvg"
tmp_csv = "/tmp/burndown.csv"
rx1 = re.compile("(\d+) insertions")
rx2 = re.compile("(\d+) deletions")
def inspect(info):
proc = run(["git", "show", "-s", "--format=%ci", "HEAD"], stdout=PIPE)
date = dateutil.parser.parse(proc.stdout)
date = date.replace(tzinfo=None)
proc = run(["git", "diff", "HEAD^", "HEAD", "--shortstat"], stdout=PIPE)
m1 = rx1.search(proc.stdout.decode("utf8"))
if m1:
addd = int(m1.groups(1)[0])
else:
addd = 0
m2 = rx2.search(proc.stdout.decode("utf8"))
if m2:
deld = int(m2.groups(1)[0])
else:
deld = 0
proc = run(["tokei", "-o", "json", "-t", "Rust,C,C Header"], stdout=PIPE)
out = json.loads(proc.stdout)
del out["C"]["stats"]
del out["CHeader"]["stats"]
try:
del out["Rust"]["stats"]
except KeyError:
# add the first non-rusty stats then reraise to catch in parent
info.append((date, out["C"]["lines"], 0, out["CHeader"]["lines"], addd, deld))
raise
info.append(
(
date,
out["C"]["lines"],
out["Rust"]["lines"],
out["CHeader"]["lines"],
addd,
deld,
)
)
def postprocess(df):
df.sort_index(inplace=True)
df.to_csv(tmp_csv)
ax = df[["C", "Rust", "CHeader"]].plot(title="librsvg burndown", drawstyle="steps")
ax.set_ylabel("LOC")
# df["Commit"] = 1
# df2 = df[["Added", "Deleted", "Commit"]].resample("D").sum().rolling("7D").mean()
# df2.plot(ax=ax, )
plt.show()
def new_run():
info = []
ct = 0
os.chdir(repo)
proc = run(["git", "checkout", "master"])
while True:
try:
inspect(info)
except KeyError:
break
ct += 1
print(ct)
_proc = run(["git", "checkout", "HEAD^"], stderr=PIPE)
assert _proc.returncode == 0
df = pandas.DataFrame.from_records(
info, "Date", columns=["Date", "C", "Rust", "CHeader", "Added", "Deleted"]
)
proc = run(["git", "checkout", "master"])
return df
if __name__ == "__main__":
try:
# delete tmp_csv file to re-run everything
df = pandas.read_csv(tmp_csv, index_col="Date", parse_dates=["Date"])
except:
df = new_run()
postprocess(df)
@federicomenaquintero
Copy link

Hi! I saw your /r/rust post with the oxidation chart. Thanks for putting it together; it is very nice! Would you let me paste that image in my blog? I'll try to set up my environment to be able to run your script in the future :)

@jesskfullwood
Copy link
Author

jesskfullwood commented Jan 11, 2019

Hi there - yes of course, it's all your hard work, do whatever you like with it. I feel a little bit like I've stolen some unearned credit!

@jesskfullwood
Copy link
Author

In theory, to run the script, all you need to do is pip3 install --user matplotlib pandas dateutil and change the repo location on line 10

@federicomenaquintero
Copy link

Thanks! I'll try to get my env set up for running it in the future.

@jaccarmac
Copy link

May I cannibalize the code to generate a similar chart for Remacs? We like the chart over there and are working on tracking something similar for that project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment