comparison mercurial/utils/stringutil.py @ 37248:0e7550b0964c

stringutil: improve check for failed mailmap line parsing The existing check for a bad mailmap file entry fails with inputs like b'>@<'. This commit adds a function to check if a sufficient amount of information has been parsed from a mailmap file entry. At minimum, one email must be found (assumed to be the commit email). If email is not empty and no names are found, then there must be two emails. If there are at least one email and name, the mapping is valid. Differential Revision: https://phab.mercurial-scm.org/D3003
author Connor Sheehan <sheehan@mozilla.com>
date Sat, 31 Mar 2018 11:36:55 -0400
parents 54b896f195d1
children 2ed180117f76
comparison
equal deleted inserted replaced
37247:54b896f195d1 37248:0e7550b0964c
163 class mailmapping(object): 163 class mailmapping(object):
164 '''Represents a username/email key or value in 164 '''Represents a username/email key or value in
165 a mailmap file''' 165 a mailmap file'''
166 email = attr.ib() 166 email = attr.ib()
167 name = attr.ib(default=None) 167 name = attr.ib(default=None)
168
169 def _ismailmaplineinvalid(names, emails):
170 '''Returns True if the parsed names and emails
171 in a mailmap entry are invalid.
172
173 >>> # No names or emails fails
174 >>> names, emails = [], []
175 >>> _ismailmaplineinvalid(names, emails)
176 True
177 >>> # Only one email fails
178 >>> emails = [b'email@email.com']
179 >>> _ismailmaplineinvalid(names, emails)
180 True
181 >>> # One email and one name passes
182 >>> names = [b'Test Name']
183 >>> _ismailmaplineinvalid(names, emails)
184 False
185 >>> # No names but two emails passes
186 >>> names = []
187 >>> emails = [b'proper@email.com', b'commit@email.com']
188 >>> _ismailmaplineinvalid(names, emails)
189 False
190 '''
191 return not emails or not names and len(emails) < 2
168 192
169 def parsemailmap(mailmapcontent): 193 def parsemailmap(mailmapcontent):
170 """Parses data in the .mailmap format 194 """Parses data in the .mailmap format
171 195
172 >>> mmdata = b"\\n".join([ 196 >>> mmdata = b"\\n".join([
197 221
198 for line in mailmapcontent.splitlines(): 222 for line in mailmapcontent.splitlines():
199 223
200 # Don't bother checking the line if it is a comment or 224 # Don't bother checking the line if it is a comment or
201 # is an improperly formed author field 225 # is an improperly formed author field
202 if line.lstrip().startswith('#') or any(c not in line for c in '<>@'): 226 if line.lstrip().startswith('#'):
203 continue 227 continue
204 228
205 # names, emails hold the parsed emails and names for each line 229 # names, emails hold the parsed emails and names for each line
206 # name_builder holds the words in a persons name 230 # name_builder holds the words in a persons name
207 names, emails = [], [] 231 names, emails = [], []
227 break 251 break
228 252
229 else: 253 else:
230 # We have found another word in the committers name 254 # We have found another word in the committers name
231 namebuilder.append(element) 255 namebuilder.append(element)
256
257 # Check to see if we have parsed the line into a valid form
258 # We require at least one email, and either at least one
259 # name or a second email
260 if _ismailmaplineinvalid(names, emails):
261 continue
232 262
233 mailmapkey = mailmapping( 263 mailmapkey = mailmapping(
234 email=emails[-1], 264 email=emails[-1],
235 name=names[-1] if len(names) == 2 else None, 265 name=names[-1] if len(names) == 2 else None,
236 ) 266 )