Activity: Hour of Day.
[gitstats.git] / statgit
blob1e9fce57a199464a5968fd0cd635a040922040c6
1 #!/usr/bin/python
2 # Copyright (c) 2007 Heikki Hokkanen <hoxu@users.sf.net>
3 # GPLv2
4 import commands
5 import datetime
6 import os
7 import re
8 import sys
10 def getoutput(cmd):
11 print '>> %s' % cmd
12 output = commands.getoutput(cmd)
13 return output
15 class DataCollector:
16 def __init__(self):
17 pass
20 # This should be the main function to extract data from the repository.
21 def collect(self, dir):
22 self.dir = dir
25 # : get a dictionary of author
26 def getAuthorInfo(self, author):
27 return None
29 def getActivityByHourOfDay(self):
30 return {}
33 # Get a list of authors
34 def getAuthors(self):
35 return []
37 def getFirstCommitDate(self):
38 return datetime.datetime.now()
40 def getLastCommitDate(self):
41 return datetime.datetime.now()
43 def getTags(self):
44 return []
46 def getTotalAuthors(self):
47 return -1
49 def getTotalCommits(self):
50 return -1
52 def getTotalFiles(self):
53 return -1
55 def getTotalLOC(self):
56 return -1
58 class GitDataCollector(DataCollector):
59 def collect(self, dir):
60 DataCollector.collect(self, dir)
62 self.total_authors = int(getoutput('git-log |git-shortlog -s |wc -l'))
63 self.total_commits = int(getoutput('git-rev-list --all |wc -l'))
64 self.total_files = int(getoutput('git-ls-files |wc -l'))
65 self.total_lines = int(getoutput('git-ls-files |xargs cat |wc -l'))
67 self.activity_by_hour_of_day = {} # hour -> commits
68 self.activity_by_day_of_week = {} # day -> commits
70 # activity
71 lines = getoutput('git-rev-list --all --pretty=format:%at |grep -v ^commit').split('\n')
72 for stamp in lines:
73 date = datetime.datetime.fromtimestamp(float(stamp))
75 # hour
76 hour = date.hour
77 if hour in self.activity_by_hour_of_day:
78 self.activity_by_hour_of_day[hour] += 1
79 else:
80 self.activity_by_hour_of_day[hour] = 1
82 # day
83 day = date.weekday()
84 if day in self.activity_by_day_of_week:
85 self.activity_by_day_of_week[day] += 1
86 else:
87 self.activity_by_day_of_week[day] = 1
90 def getActivityByHourOfDay(self):
91 return self.activity_by_hour_of_day
93 def getAuthorInfo(self, author):
94 commits = int(getoutput('git-rev-list --all --author="%s" |wc -l' % author))
95 commits_frac = (100 * float(commits)) / self.getTotalCommits()
96 date_first = '0000-00-00'
97 date_last = '0000-00-00'
98 rev_last = getoutput('git-rev-list --all --author="%s" -n 1' % author)
99 rev_first = getoutput('git-rev-list --all --author="%s" |tail -n 1' % author)
100 date_first = self.revToDate(rev_first)
101 date_last = self.revToDate(rev_last)
103 res = { 'commits': commits, 'commits_frac': commits_frac, 'date_first': date_first, 'date_last': date_last }
104 return res
106 def getAuthors(self):
107 lines = getoutput('git-rev-list --all --pretty=format:%an |grep -v ^commit |sort |uniq')
108 return lines.split('\n')
110 def getTags(self):
111 lines = getoutput('git-show-ref --tags |cut -d/ -f3')
112 return lines.split('\n')
114 def getTagDate(self, tag):
115 return self.revToDate('tags/' + tag)
117 def getTotalAuthors(self):
118 return self.total_authors
120 def getTotalCommits(self):
121 return self.total_commits
123 def getTotalFiles(self):
124 return self.total_files
126 def getTotalLOC(self):
127 return self.total_lines
129 def revToDate(self, rev):
130 stamp = int(getoutput('git-log --pretty=format:%%at "%s" -n 1' % rev))
131 return datetime.datetime.fromtimestamp(stamp).strftime('%Y-%m-%d')
133 class ReportCreator:
134 def __init__(self):
135 pass
137 def create(self, data, path):
138 self.data = data
139 self.path = path
141 class HTMLReportCreator(ReportCreator):
142 def create(self, data, path):
143 ReportCreator.create(self, data, path)
145 f = open(path + "/index.html", 'w')
146 format = '%Y-%m-%d %H:%m:%S'
147 self.printHeader(f)
149 f.write('<h1>StatGit</h1>')
151 f.write('<dl>');
152 f.write('<dt>Generated</dt><dd>%s</dd>' % datetime.datetime.now().strftime(format));
153 f.write('<dt>Report Period</dt><dd>%s to %s</dd>' % (data.getFirstCommitDate().strftime(format), data.getLastCommitDate().strftime(format)))
154 f.write('<dt>Total Files</dt><dd>%s</dd>' % data.getTotalFiles())
155 f.write('<dt>Total Lines of Code</dt><dd>%s</dd>' % data.getTotalLOC())
156 f.write('<dt>Total Commits</dt><dd>%s</dd>' % data.getTotalCommits())
157 f.write('<dt>Authors</dt><dd>%s</dd>' % data.getTotalAuthors())
158 f.write('</dl>');
160 f.write("""<ul>
161 <li><a href="activity.html">Activity</a></li>
162 <li><a href="authors.html">Authors</a></li>
163 <li><a href="files.html">Files</a></li>
164 <li><a href="lines.html">Lines</a></li>
165 </ul>
166 """)
168 f.write('<h2>Authors</h2>')
170 f.write('<table class="authors">')
171 f.write('<tr><th>Author</th><th>Commits (%)</th><th>First commit</th><th>Last commit</th></tr>')
172 for author in data.getAuthors():
173 info = data.getAuthorInfo(author)
174 f.write('<tr><td>%s</td><td>%d (%.2f%%)</td><td>%s</td><td>%s</td></tr>' % (author, info['commits'], info['commits_frac'], info['date_first'], info['date_last']))
175 f.write('</table>')
177 f.write('<h2>Tags</h2>')
178 f.write('<table>')
179 f.write('<tr><th>Name</th><th>Date</th><th>Developers</th></tr>')
180 for tag in data.getTags():
181 f.write('<tr><td>%s</td><td></td></tr>' % tag)
182 f.write('</table>')
184 f.write('</body>\n</html>');
185 f.close()
187 # activity.html
188 f = open(path + '/activity.html', 'w')
189 self.printHeader(f)
190 f.write('<h1>Activity</h1>')
192 f.write('<h2>Last 30 days</h2>')
194 f.write('<h2>Last 12 months</h2>')
196 f.write('\n<h2>Hour of Day</h2>\n\n')
197 hour_of_day = data.getActivityByHourOfDay()
198 f.write('<table><tr><th>Hour</th>')
199 for i in range(1, 25):
200 f.write('<th>%d</th>' % i)
201 f.write('</tr>\n<tr><th>Commits</th>')
202 for i in range(1, 25):
203 if i in hour_of_day:
204 f.write('<td>%d</td>' % hour_of_day[i])
205 else:
206 f.write('<td>0</td>')
207 f.write('</tr>\n<tr><th>%</th>')
208 totalcommits = data.getTotalCommits()
209 for i in range(1, 25):
210 if i in hour_of_day:
211 f.write('<td>%.2f</td>' % ((100.0 * hour_of_day[i]) / totalcommits))
212 else:
213 f.write('<td>0.00</td>')
214 f.write('</tr></table>')
216 f.write('\n\n<h2>Day of Week</h2>')
217 # TODO 7x(24+1)
219 f.close()
220 pass
222 def printHeader(self, f):
223 f.write("""<html>
224 <head>
225 <title>StatGit</title>
226 <link rel="stylesheet" href="statgit.css" type="text/css" />
227 </head>
228 <body>
229 """)
232 usage = """
233 Usage: statgit [options] <gitpath> <outputpath>
235 Options:
236 -o html
239 if len(sys.argv) < 3:
240 print usage
241 sys.exit(0)
243 gitpath = sys.argv[1]
244 outputpath = sys.argv[2]
246 print 'Git path: %s' % gitpath
247 print 'Output path: %s' % outputpath
249 os.chdir(gitpath)
251 print 'Collecting data...'
252 data = GitDataCollector()
253 data.collect(gitpath)
255 print 'Generating report...'
256 report = HTMLReportCreator()
257 report.create(data, outputpath)