forked from lastorset/bindir
-
Notifications
You must be signed in to change notification settings - Fork 1
/
git-lineowners
executable file
·98 lines (76 loc) · 2.77 KB
/
git-lineowners
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/usr/bin/env python
import sys
import subprocess
from collections import defaultdict
class AuthorCounter(object):
def __init__(self, rev, filename, size):
self.rev = rev
self.filename = filename
self.size = size
self.umap = defaultdict(lambda: 0)
def count_authors(self):
current_sha = ''
current_user = ''
commit_u_map = {}
if self.size < 2*1024*1024:
args = ['git', 'blame', '-p', self.rev, self.filename]
sub=subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)
for l in sub.stdout:
if l.startswith("\t"):
self.umap[current_user] += 1
else:
try:
if l.rstrip() == 'boundary':
k, v = 'boundary', ''
else:
k, v = l.strip().split(' ', 1)
except ValueError:
sys.stderr.write("Error parsing %s on %s\n" % (repr(l), self.filename))
k = l
v = ''
if len(k) == 40 or k == 'boundary': # Assumed SHA
current = ''
current_sha = k
if current_sha in commit_u_map:
current_user = commit_u_map[current_sha]
elif k == 'author':
current_user = v
commit_u_map[current_sha] = v
def load_blobs(ref):
args = ['git', 'ls-tree', '-z', '-l', '-r', ref]
sub=subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)
blobs = sub.stdout.read().split("\0")
rv = []
for b in (b for b in blobs if b):
info, filename = b.split("\t")
mode, t, blob_id, size = info.split()
assert t == 'blob'
rv.append(AuthorCounter(ref, filename, int(size)))
return rv
def rev_parse(ref):
args = ['git', 'rev-parse', ref]
sub = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)
return sub.stdout.read().strip()
def name(ref):
args = ['git', 'describe', ref]
sub = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)
return sub.stdout.read().strip()
def mergeDicts(inputs):
rv = defaultdict(lambda: 0)
for d in inputs:
for k,v in d.iteritems():
rv[k] += v
return rv
def output(d):
for v,k in sorted(((v,k) for k,v in d.iteritems()), reverse=True):
print v, k
if __name__ == '__main__':
refs = sys.argv[1:]
if not refs:
refs = ['HEAD']
for ref in refs:
ref = rev_parse(ref)
blobs = load_blobs(ref)
for b in blobs:
b.count_authors()
output(mergeDicts(b.umap for b in blobs))