2 # Stuff for dealing with the git log output.
4 # Someday this will be the only version of grabpatch, honest.
6 import re
, rfc822
, datetime
7 from patterns
import patterns
12 # Input file handling. Someday it would be good to make this smarter
13 # so that it handles running git with the right options and such.
35 # A simple state machine based on where we are in the patch. The
36 # first stuff we get is the header.
40 # Then comes the single-line description.
44 # ...the full changelog...
48 # ...the tag section....
52 # ...the numstat section.
59 # The functions to handle each of these states.
61 def get_header(patch
, line
, input):
63 if patch
.author
== '':
64 print 'Funky auth line in', patch
.commit
65 patch
.author
= database
.LookupStoreHacker('Unknown',
68 m
= patterns
['author'].match(line
)
70 patch
.email
= database
.RemapEmail(m
.group(2))
71 patch
.author
= database
.LookupStoreHacker(m
.group(1), patch
.email
)
73 m
= patterns
['date'].match(line
)
75 dt
= rfc822
.parsedate(m
.group(2))
76 patch
.date
= datetime
.date(dt
[0], dt
[1], dt
[2])
79 def get_desc(patch
, line
, input):
81 print 'Missing desc in', patch
.commit
90 tagline
= re
.compile(r
'^\s+(([-a-z]+-by)|cc|fixes):.*$', re
.I
)
91 def get_changelog(patch
, line
, input):
94 patch
.changelog
+= patch
.templog
96 if patterns
['commit'].match(line
):
97 # No changelog at all - usually a Linus tag
100 elif tagline
.match(line
):
102 patch
.changelog
+= patch
.templog
103 return get_tag(patch
, line
, input)
105 patch
.templog
+= line
+ '\n'
108 def get_tag(patch
, line
, input):
110 # Some people put blank lines in the middle of tags.
115 # A new commit line says we've gone too far.
117 if patterns
['commit'].match(line
):
121 # Check for a numstat line
123 if patterns
['numstat'].match(line
):
124 return get_numstat(patch
, line
, input)
126 # Look for interesting tags
128 m
= patterns
['signed-off-by'].match(line
)
130 patch
.signoffs
.append(m
.group(2))
133 # Look for other tags indicating that somebody at least
134 # looked at the patch.
136 for tag
in ('acked-by', 'reviewed-by', 'tested-by'):
137 if patterns
[tag
].match(line
):
140 patch
.taglines
.append(line
)
143 def get_numstat(patch
, line
, input):
144 m
= patterns
['numstat'].match(line
)
148 patch
.addfile(int(m
.group(1)), int(m
.group(2)), m
.group(3))
150 # Binary files just have "-" in the line fields. In this case, set
151 # the counts to zero so that we at least track that the file was
155 patch
.addfile(0, 0, m
.group(3))
158 grabbers
= [ get_header
, get_desc
, get_changelog
, get_tag
, get_numstat
]
162 # A variant on the gitdm patch class.
165 def __init__(self
, commit
):
173 self
.added
= self
.removed
= 0
177 def addfile(self
, added
, removed
, file):
179 self
.removed
+= removed
180 self
.files
.append(file)
182 def grabpatch(input):
184 # If it's not a patch something is screwy.
186 line
= getline(input)
189 m
= patterns
['commit'].match(line
)
191 print 'noncommit', line
193 p
= patch(m
.group(1))
196 # Crank through the patch.
198 while state
!= S_DONE
:
199 line
= getline(input)
201 if state
!= S_NUMSTAT
:
202 print 'Ran out of patch', state
205 state
= grabbers
[state
](p
, line
, input)