forked from owenthereal/ccat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hg_repo_annotate_py.go
128 lines (109 loc) · 3.9 KB
/
hg_repo_annotate_py.go
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
123
124
125
126
127
128
package hgcmd
var hgRepoAnnotatePy = `
import hglib, sys, re, json, subprocess, os
from email.utils import parseaddr
from datetime import datetime, tzinfo, timedelta
import time as _time
class LocalTimezone(tzinfo):
def utcoffset(self, dt):
if self._isdst(dt):
return DSTOFFSET
else:
return STDOFFSET
def dst(self, dt):
if self._isdst(dt):
return DSTDIFF
else:
return ZERO
def tzname(self, dt):
return _time.tzname[self._isdst(dt)]
def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day,
dt.hour, dt.minute, dt.second,
dt.weekday(), 0, 0)
stamp = _time.mktime(tt)
tt = _time.localtime(stamp)
return tt.tm_isdst > 0
Local = LocalTimezone()
STDOFFSET = timedelta(seconds = -_time.timezone)
if _time.daylight:
DSTOFFSET = timedelta(seconds = -_time.altzone)
else:
DSTOFFSET = STDOFFSET
DSTDIFF = DSTOFFSET - STDOFFSET
repodir = os.path.abspath(sys.argv[1])
v = sys.argv[2]
files = sys.argv[3:]
explicitFiles = []
if len(files) > 0:
# sys.stderr.write("Using %d files specified on command line: %r\n" % (len(files), files))
explicitFiles = files
if len(files) == 0:
filesNulSep = subprocess.check_output(["hg", "locate", "--print0", "--rev="+v], cwd=repodir)
files = [f for f in filesNulSep.split("\x00") if f]
# sys.stderr.write("Found %d files in hg repository at %s, revision %s\n" % (len(files), repodir, v))
# sys.stderr.write("Opening hg repository at %s, revision %s\n" % (repodir, v))
client = hglib.open(repodir)
commits = {}
hunksByFile = {}
if explicitFiles:
# sys.stderr.write("Finding commits for files: %r\n" % explicitFiles)
pass
for rev in client.log('%s:0' % v, files=explicitFiles):
authorName, authorEmail = parseaddr(rev.author)
dt = rev.date.replace(tzinfo=Local)
commitID = rev.node[:40]
commit = {
# 'ID': commitID, # not needed
# 'Message': rev.desc, # not needed
'Author': {'Name': authorName, 'Email': authorEmail},
'AuthorDate': dt.isoformat('T'),
}
commits[commitID] = commit
# sys.stderr.write("Read %d commits in hg repository at %s, revision %s\n" % (len(commits), repodir, v))
totalHunks = 0
def addHunk(file, hunk):
if file not in hunksByFile:
hunksByFile[file] = []
hunksByFile[file].append(hunk)
global totalHunks
totalHunks += 1
i = 0
for file in files:
filepath = os.path.join(repodir, file)
# sys.stderr.write("[% 2d/%d %.1f%%] Annotating file %s in hg repository at %s\n" % (i, len(files), float(i)/float(len(files))*100, file, repodir))
i += 1
lineno = 1
hunk = None
byteOffsetInFile = 0
for (info, contents) in client.annotate(files=['--debug', '--', filepath], rev=v, changeset=True):
changeset = info.strip()
startNewHunk = False
advanceCurrentHunk = False
if hunk is None:
startNewHunk = True
byteOffsetInFile = 0
elif changeset != hunk['CommitID']:
addHunk(file, hunk)
startNewHunk = True
else:
advanceCurrentHunk = True
if startNewHunk:
hunk = {
'CommitID': changeset,
'StartLine': lineno,
'EndLine': lineno + 1,
'StartByte': byteOffsetInFile,
'EndByte': byteOffsetInFile+len(contents)+1,
}
byteOffsetInFile += len(contents) + 1 # +1 for newline
if advanceCurrentHunk:
hunk['EndLine'] += 1
hunk['EndByte'] = byteOffsetInFile
lineno += 1
if hunk is not None:
hunk['EndByte'] = byteOffsetInFile
addHunk(file, hunk)
# sys.stderr.write("Read %d hunks from %d files in hg repository at %s, revision %s\n" % (totalHunks, len(hunksByFile), repodir, v))
json.dump({'Commits': commits, 'Hunks': hunksByFile}, sys.stdout)
`