4 # Crank through the log looking at when developers did their first and
7 # git log | firstlast -v versiondb
9 import argparse, pickle
14 from utils import accumulator
19 p = argparse.ArgumentParser()
20 p.add_argument('-v', '--versiondb', help = 'Version database file',
21 required = False, default = 'committags.db')
22 p.add_argument('-c', '--config', help = 'Configuration file',
24 p.add_argument('-d', '--dbdir', help = 'Where to find the config database files',
25 required = False, default = '')
26 p.add_argument('-f', '--first', help = 'First version for detailed tracking',
27 required = False, default = '')
28 p.add_argument('-l', '--last', help = 'Last version for detailed tracking',
29 required = False, default = '')
30 p.add_argument('-m', '--minversions', required = False, default = 1, type = int,
31 help = 'How many versions an author contributes to for counting')
35 # Try to track the first directory a new developer touches.
39 def TrackFirstDirs(patch):
41 for file in patch.files:
42 split = file.split('/')
43 if split[0] in ['arch', 'drivers', 'fs']:
44 track = '/'.join(split[0:2])
56 return FirstDirs[d2] - FirstDirs[d1]
59 print '\nDirectories touched by first commits:'
60 dirs = FirstDirs.keys()
63 print '%5d: %s' % (FirstDirs[dir], dir)
66 # Let's also track who they worked for.
70 def TrackFirstEmpl(name):
77 return FirstEmpls[e2] - FirstEmpls[e1]
79 def PrintFirstEmpls():
80 empls = FirstEmpls.keys()
84 print '%5d: %s' % (FirstEmpls[e], e)
86 # We "know" that unknown/none are always the top two...
90 companies += FirstEmpls[e]
91 print 'Companies: %d' % (companies)
94 # Version comparison stuff. Kernel-specific, obviously.
97 sys.stderr.write(gripe + '\n')
100 def versionmap(vers):
101 split = vers.split('.')
102 if not (2 <= len(split) <= 4):
103 die('funky version %s' % (vers))
104 if split[0] in ['v2', '2']:
106 if split[0] in ['v3', '3']:
107 return 100 + int(split[1])
108 if split[0] in ['v4', '4']:
109 return 120 + int(split[1])
110 die('Funky version %s' % (vers))
115 def SetTrackingVersions(args):
116 global T_First, T_Last
118 T_First = versionmap(args.first)
120 T_Last = versionmap(args.last)
122 def TrackingVersion(vers):
123 return T_First <= versionmap(vers) <= T_Last
129 VDB = pickle.load(open(args.versiondb, 'r'))
130 ConfigFile.ConfigFile(args.config, args.dbdir)
131 SetTrackingVersions(args)
133 Firsts = accumulator()
134 Lasts = accumulator()
135 Singles = accumulator()
136 Versions = accumulator()
138 # Read through the full patch stream and collect the relevant info.
140 patch = gitlog.grabpatch(sys.stdin)
143 v = VDB[patch.commit]
145 print 'Funky commit', patch.commit
146 patch = gitlog.grabpatch(sys.stdin)
149 # The first patch we see is the last they committed, since git
150 # lists things in backwards order.
152 if len(patch.author.patches) == 0:
153 patch.author.lastvers = v
154 Lasts.append(v, patch.author)
155 patch.author.firstvers = v
156 patch.author.addpatch(patch)
157 Versions.append(patch.author.id, v, unique = True)
158 patch = gitlog.grabpatch(sys.stdin)
161 # Pass over all the hackers we saw and collate stuff.
163 for h in database.AllHackers():
164 if len(h.patches) > 0 and len(Versions[h.id]) >= args.minversions:
165 Firsts.append(h.firstvers, h)
166 if h.firstvers == h.lastvers:
167 Singles.incr(h.firstvers)
169 # Track details, but only for versions we care about
171 if TrackingVersion(h.firstvers):
175 empl = h.emailemployer(p.email, p.date)
176 except AttributeError:
177 print 'No email on ', p.commit
179 if empl.name == '(Unknown)':
180 print 'UNK: %s %s' % (p.email, h.name)
181 TrackFirstEmpl(empl.name)
183 versions = Lasts.keys()
186 return versionmap(v1) - versionmap(v2) # reverse sort
187 versions.sort(cmpvers)
189 if args.minversions <= 1:
190 print v, len(Firsts[v]), len(Lasts[v]), Singles[v]
192 print v, len(Firsts.get(v, [])), len(Lasts.get(v, []))