Repository navigation
Expand file tree
/
Copy pathgitlog2json.py
More file actions
executable file
·122 lines (98 loc) · 3.58 KB
/
Copy pathgitlog2json.py
File metadata and controls
executable file
·122 lines (98 loc) · 3.58 KB
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python
import argparse
import collections
import datetime
import json
import sys
MAX_INACTIVITY = datetime.timedelta(days=90).total_seconds()
class DevRange:
def __init__(self, minr=None, maxr=None, count=0):
self.packed_ranges = []
self.count = count
self.min = minr
self.max = maxr
def add(self, ts):
if self.min is None: # == self.max is None
self.min = self.max = ts
elif ts < self.min:
if self.min - ts > MAX_INACTIVITY:
self.packed_ranges.append(DevRange(self.min, self.max, self.count))
self.max = ts
self.count = 0
self.min = ts
elif ts > self.max:
self.max = ts
self.count += 1
@property
def earliest(self):
return self.min
@property
def latest(self):
if self.packed_ranges:
return self.packed_ranges[0].max
else:
return self.max
def __repr__(self):
return 'DevRange(%s, %s)' % (fdate(self.min), fdate(self.max))
def main():
argp = argparse.ArgumentParser()
argp.add_argument('--ldap-only', action='store_true', default=False,
help='Ignore developers that are not present in LDAP')
sortg = argp.add_mutually_exclusive_group()
sortg.add_argument('--sort-earliest', action='store_true',
help='Sort by earliest commit date')
sortg.add_argument('--sort-latest', action='store_true',
help='Sort by most recent commit date')
sortg.add_argument('--sort-name', action='store_true',
help='Sort by developer name')
argp.add_argument('input', type=argparse.FileType('r'),
help='Input file (output of git --format="%%H %%ct %%ce %%ae")')
argp.add_argument('output', type=argparse.FileType('w'),
help='Output JSON file')
argp.add_argument('aliases_json', type=argparse.FileType('r'),
help='Aliases JSON file')
vals = argp.parse_args()
devs = collections.defaultdict(DevRange)
aliases = json.load(vals.aliases_json)
# --format='%H %ct %ce %ae'
for l in vals.input:
spl = l.split('\0')
if len(spl) < 4: # some entries lack e-mail, for some reason
continue
h, ts, cemail, aemail = spl
# use both committer & author:
# - committer indicates developer activity (to merge stuff)
# - author to 'fill' bars of pull request authors who became
# developers
mails = set((cemail.lower(), aemail.lower()))
for m in mails:
# map from email to canonical dev name
# (including alternate aliases, emails)
if m in aliases:
uid = aliases[m]
# accidental historical commit
elif m == 'larry@gentoo.org':
continue
# devs not in LDAP?
elif m.endswith('@gentoo.org') and not vals.ldap_only:
uid = m[:-len('@gentoo.org')]
# let's skip everyone else, for now
else:
continue
devs[uid.lower()].add(int(ts))
if vals.sort_latest:
sort_key = lambda x: x[1].latest
elif vals.sort_name:
sort_key = lambda x: x[0]
else: # vals.sort_earliest
sort_key = lambda x: x[1].earliest
out = []
for d, bigrange in sorted(devs.items(), key=sort_key):
ranges = []
for r in (*bigrange.packed_ranges, bigrange):
ranges.append((r.count, r.min, r.max))
out.append((d, ranges))
json.dump(out, vals.output)
return 0
if __name__ == '__main__':
sys.exit(main())