From 8528d27df64cc84163c98bd76cd4921165392ee7 Mon Sep 17 00:00:00 2001 From: "R. Tyler Ballance" Date: Thu, 8 Jan 2009 00:42:42 -0800 Subject: [PATCH] Support the statistics gathering for the churn graph I'm still somewhat uncertain about how I want to create the graphs, I may need to add historgram support to CairoPlot to do precisely what I want: | | |+++| | |+++| | |///| ___ | |///| |+++| <-- avg added per commit | |///| |+++| |__|///|_______|///|_<-- avg removed per commit [tyler] [other] Uncertainly, BAH. Signed-off-by: R. Tyler Ballance --- git-plot.py | 2 +- internal/log.py | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/git-plot.py b/git-plot.py index 449cc36..16c6f74 100755 --- a/git-plot.py +++ b/git-plot.py @@ -6,7 +6,7 @@ import internal import internal.log def main(): - sub_commands = ['leaderboard', 'timeofday'] + sub_commands = ['leaderboard', 'timeofday', 'churn'] usage = 'usage: %%prog [options] <%s>' % '|'.join(sub_commands) _op = OptionParser(usage=usage) _op.add_option('-d', '--directory', default='.', dest='directory', help='Directory of the Git repository to analyze') diff --git a/internal/log.py b/internal/log.py index a513fa4..2614cf0 100644 --- a/internal/log.py +++ b/internal/log.py @@ -68,15 +68,16 @@ class GitLog(object): # OW OW OW OW numstat = [n.split('\t') for n in r[1].strip().split('\n')] def _numstat_gen(line): - d = {'added' : 0, 'removed' : 0, 'filename' : line[2], 'newfile' : False} + d = {'added' : 0, 'removed' : 0, 'filename' : line[2], 'binary' : False} if line[0] == '-' and line[1] == '-': - d['newfile'] = True + d['binary'] = True else: - d['added'], d['removed'] = line[0],line[1] + d['added'], d['removed'] = int(line[0]),int(line[1]) return d t['numstat'] = map(lambda n: len(n) == 3 and _numstat_gen(n), numstat) + t['numstat'] = [nm for nm in t['numstat'] if nm] else: - t['numstat'] = None + t['numstat'] = [] rc.append(t) self.results = rc def timeofday(f): @@ -162,3 +163,39 @@ class GitLog(object): except KeyError: print 'This function does not support chart type: %s' % chart + def churn(self, width=None, height=None, filename=None, chart=internal.ChartType.Bar): + assert width or height + if not self.results: + self.load() + results = copy.deepcopy(self.results) + results.reverse() + filename = '%s_churn.png' % (self.filename or time.time()) + + rc = {} + for commit in results: + if not commit['numstat']: + continue + churn = [] + for file in commit['numstat']: + if file['binary']: + continue + churn.append( (file['added'], file['removed'], file['filename']) ) + + author = commit['committer_handle'] + if not rc.get(author): + rc[author] = {'commits' : 0, 'files' : [], 'added' : 0, 'removed' : 0} + + rc[author]['commits'] += 1 + rc[author]['files'].extend([f[2] for f in churn]) + added = map(lambda c: c[0], churn) + removed = map(lambda c: c[1], churn) + rc[author]['added'] += added and reduce(lambda x,y: x+y, added) or 0 + rc[author]['removed'] += removed and reduce(lambda x,y: x+y, removed) or 0 + + for k in rc.keys(): + rc[k]['files'] = list(set(rc[k]['files'])) + rc[k]['distinct_files'] = len(rc[k]['files']) + + for k,r in rc.iteritems(): + print '%s touched %d files, +%s, -%s lines (total: %s, net: %s)' % (k, r['distinct_files'], r['added'], r['removed'], r['added']+r['removed'], r['added']-r['removed']) +