comparison hgext/eol.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents d98ec36be808
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
104 pycompat, 104 pycompat,
105 registrar, 105 registrar,
106 scmutil, 106 scmutil,
107 util, 107 util,
108 ) 108 )
109 from mercurial.utils import ( 109 from mercurial.utils import stringutil
110 stringutil,
111 )
112 110
113 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for 111 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
114 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should 112 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
115 # be specifying the version(s) of Mercurial they are tested with, or 113 # be specifying the version(s) of Mercurial they are tested with, or
116 # leave the attribute unspecified. 114 # leave the attribute unspecified.
117 testedwith = 'ships-with-hg-core' 115 testedwith = 'ships-with-hg-core'
118 116
119 configtable = {} 117 configtable = {}
120 configitem = registrar.configitem(configtable) 118 configitem = registrar.configitem(configtable)
121 119
122 configitem('eol', 'fix-trailing-newline', 120 configitem(
123 default=False, 121 'eol', 'fix-trailing-newline', default=False,
124 ) 122 )
125 configitem('eol', 'native', 123 configitem(
126 default=pycompat.oslinesep, 124 'eol', 'native', default=pycompat.oslinesep,
127 ) 125 )
128 configitem('eol', 'only-consistent', 126 configitem(
129 default=True, 127 'eol', 'only-consistent', default=True,
130 ) 128 )
131 129
132 # Matches a lone LF, i.e., one that is not part of CRLF. 130 # Matches a lone LF, i.e., one that is not part of CRLF.
133 singlelf = re.compile('(^|[^\r])\n') 131 singlelf = re.compile('(^|[^\r])\n')
134 132
133
135 def inconsistenteol(data): 134 def inconsistenteol(data):
136 return '\r\n' in data and singlelf.search(data) 135 return '\r\n' in data and singlelf.search(data)
136
137 137
138 def tolf(s, params, ui, **kwargs): 138 def tolf(s, params, ui, **kwargs):
139 """Filter to convert to LF EOLs.""" 139 """Filter to convert to LF EOLs."""
140 if stringutil.binary(s): 140 if stringutil.binary(s):
141 return s 141 return s
142 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s): 142 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
143 return s 143 return s
144 if (ui.configbool('eol', 'fix-trailing-newline') 144 if (
145 and s and not s.endswith('\n')): 145 ui.configbool('eol', 'fix-trailing-newline')
146 and s
147 and not s.endswith('\n')
148 ):
146 s = s + '\n' 149 s = s + '\n'
147 return util.tolf(s) 150 return util.tolf(s)
151
148 152
149 def tocrlf(s, params, ui, **kwargs): 153 def tocrlf(s, params, ui, **kwargs):
150 """Filter to convert to CRLF EOLs.""" 154 """Filter to convert to CRLF EOLs."""
151 if stringutil.binary(s): 155 if stringutil.binary(s):
152 return s 156 return s
153 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s): 157 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
154 return s 158 return s
155 if (ui.configbool('eol', 'fix-trailing-newline') 159 if (
156 and s and not s.endswith('\n')): 160 ui.configbool('eol', 'fix-trailing-newline')
161 and s
162 and not s.endswith('\n')
163 ):
157 s = s + '\n' 164 s = s + '\n'
158 return util.tocrlf(s) 165 return util.tocrlf(s)
166
159 167
160 def isbinary(s, params): 168 def isbinary(s, params):
161 """Filter to do nothing with the file.""" 169 """Filter to do nothing with the file."""
162 return s 170 return s
171
163 172
164 filters = { 173 filters = {
165 'to-lf': tolf, 174 'to-lf': tolf,
166 'to-crlf': tocrlf, 175 'to-crlf': tocrlf,
167 'is-binary': isbinary, 176 'is-binary': isbinary,
168 # The following provide backwards compatibility with win32text 177 # The following provide backwards compatibility with win32text
169 'cleverencode:': tolf, 178 'cleverencode:': tolf,
170 'cleverdecode:': tocrlf 179 'cleverdecode:': tocrlf,
171 } 180 }
181
172 182
173 class eolfile(object): 183 class eolfile(object):
174 def __init__(self, ui, root, data): 184 def __init__(self, ui, root, data):
175 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'} 185 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
176 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'} 186 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
206 for pattern, key, m in self.patterns: 216 for pattern, key, m in self.patterns:
207 try: 217 try:
208 ui.setconfig('decode', pattern, self._decode[key], 'eol') 218 ui.setconfig('decode', pattern, self._decode[key], 'eol')
209 ui.setconfig('encode', pattern, self._encode[key], 'eol') 219 ui.setconfig('encode', pattern, self._encode[key], 'eol')
210 except KeyError: 220 except KeyError:
211 ui.warn(_("ignoring unknown EOL style '%s' from %s\n") 221 ui.warn(
212 % (key, self.cfg.source('patterns', pattern))) 222 _("ignoring unknown EOL style '%s' from %s\n")
223 % (key, self.cfg.source('patterns', pattern))
224 )
213 # eol.only-consistent can be specified in ~/.hgrc or .hgeol 225 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
214 for k, v in self.cfg.items('eol'): 226 for k, v in self.cfg.items('eol'):
215 ui.setconfig('eol', k, v, 'eol') 227 ui.setconfig('eol', k, v, 'eol')
216 228
217 def checkrev(self, repo, ctx, files): 229 def checkrev(self, repo, ctx, files):
218 failed = [] 230 failed = []
219 for f in (files or ctx.files()): 231 for f in files or ctx.files():
220 if f not in ctx: 232 if f not in ctx:
221 continue 233 continue
222 for pattern, key, m in self.patterns: 234 for pattern, key, m in self.patterns:
223 if not m(f): 235 if not m(f):
224 continue 236 continue
225 target = self._encode[key] 237 target = self._encode[key]
226 data = ctx[f].data() 238 data = ctx[f].data()
227 if (target == "to-lf" and "\r\n" in data 239 if (
228 or target == "to-crlf" and singlelf.search(data)): 240 target == "to-lf"
241 and "\r\n" in data
242 or target == "to-crlf"
243 and singlelf.search(data)
244 ):
229 failed.append((f, target, bytes(ctx))) 245 failed.append((f, target, bytes(ctx)))
230 break 246 break
231 return failed 247 return failed
248
232 249
233 def parseeol(ui, repo, nodes): 250 def parseeol(ui, repo, nodes):
234 try: 251 try:
235 for node in nodes: 252 for node in nodes:
236 try: 253 try:
242 data = repo[node]['.hgeol'].data() 259 data = repo[node]['.hgeol'].data()
243 return eolfile(ui, repo.root, data) 260 return eolfile(ui, repo.root, data)
244 except (IOError, LookupError): 261 except (IOError, LookupError):
245 pass 262 pass
246 except errormod.ParseError as inst: 263 except errormod.ParseError as inst:
247 ui.warn(_("warning: ignoring .hgeol file due to parse error " 264 ui.warn(
248 "at %s: %s\n") % (inst.args[1], inst.args[0])) 265 _("warning: ignoring .hgeol file due to parse error " "at %s: %s\n")
266 % (inst.args[1], inst.args[0])
267 )
249 return None 268 return None
269
250 270
251 def ensureenabled(ui): 271 def ensureenabled(ui):
252 """make sure the extension is enabled when used as hook 272 """make sure the extension is enabled when used as hook
253 273
254 When eol is used through hooks, the extension is never formally loaded and 274 When eol is used through hooks, the extension is never formally loaded and
258 """ 278 """
259 if 'eol' in ui._knownconfig: 279 if 'eol' in ui._knownconfig:
260 return 280 return
261 ui.setconfig('extensions', 'eol', '', source='internal') 281 ui.setconfig('extensions', 'eol', '', source='internal')
262 extensions.loadall(ui, ['eol']) 282 extensions.loadall(ui, ['eol'])
283
263 284
264 def _checkhook(ui, repo, node, headsonly): 285 def _checkhook(ui, repo, node, headsonly):
265 # Get revisions to check and touched files at the same time 286 # Get revisions to check and touched files at the same time
266 ensureenabled(ui) 287 ensureenabled(ui)
267 files = set() 288 files = set()
282 303
283 if failed: 304 if failed:
284 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'} 305 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
285 msgs = [] 306 msgs = []
286 for f, target, node in sorted(failed): 307 for f, target, node in sorted(failed):
287 msgs.append(_(" %s in %s should not have %s line endings") % 308 msgs.append(
288 (f, node, eols[target])) 309 _(" %s in %s should not have %s line endings")
310 % (f, node, eols[target])
311 )
289 raise errormod.Abort(_("end-of-line check failed:\n") + "\n".join(msgs)) 312 raise errormod.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
313
290 314
291 def checkallhook(ui, repo, node, hooktype, **kwargs): 315 def checkallhook(ui, repo, node, hooktype, **kwargs):
292 """verify that files have expected EOLs""" 316 """verify that files have expected EOLs"""
293 _checkhook(ui, repo, node, False) 317 _checkhook(ui, repo, node, False)
294 318
319
295 def checkheadshook(ui, repo, node, hooktype, **kwargs): 320 def checkheadshook(ui, repo, node, hooktype, **kwargs):
296 """verify that files have expected EOLs""" 321 """verify that files have expected EOLs"""
297 _checkhook(ui, repo, node, True) 322 _checkhook(ui, repo, node, True)
298 323
324
299 # "checkheadshook" used to be called "hook" 325 # "checkheadshook" used to be called "hook"
300 hook = checkheadshook 326 hook = checkheadshook
327
301 328
302 def preupdate(ui, repo, hooktype, parent1, parent2): 329 def preupdate(ui, repo, hooktype, parent1, parent2):
303 p1node = scmutil.resolvehexnodeidprefix(repo, parent1) 330 p1node = scmutil.resolvehexnodeidprefix(repo, parent1)
304 repo.loadeol([p1node]) 331 repo.loadeol([p1node])
305 return False 332 return False
306 333
334
307 def uisetup(ui): 335 def uisetup(ui):
308 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol') 336 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
337
309 338
310 def extsetup(ui): 339 def extsetup(ui):
311 try: 340 try:
312 extensions.find('win32text') 341 extensions.find('win32text')
313 ui.warn(_("the eol extension is incompatible with the " 342 ui.warn(
314 "win32text extension\n")) 343 _(
344 "the eol extension is incompatible with the "
345 "win32text extension\n"
346 )
347 )
315 except KeyError: 348 except KeyError:
316 pass 349 pass
317 350
318 351
319 def reposetup(ui, repo): 352 def reposetup(ui, repo):
325 repo.adddatafilter(name, fn) 358 repo.adddatafilter(name, fn)
326 359
327 ui.setconfig('patch', 'eol', 'auto', 'eol') 360 ui.setconfig('patch', 'eol', 'auto', 'eol')
328 361
329 class eolrepo(repo.__class__): 362 class eolrepo(repo.__class__):
330
331 def loadeol(self, nodes): 363 def loadeol(self, nodes):
332 eol = parseeol(self.ui, self, nodes) 364 eol = parseeol(self.ui, self, nodes)
333 if eol is None: 365 if eol is None:
334 return None 366 return None
335 eol.copytoui(self.ui) 367 eol.copytoui(self.ui)
412 # We should not abort here, since the user should 444 # We should not abort here, since the user should
413 # be able to say "** = native" to automatically 445 # be able to say "** = native" to automatically
414 # have all non-binary files taken care of. 446 # have all non-binary files taken care of.
415 continue 447 continue
416 if inconsistenteol(data): 448 if inconsistenteol(data):
417 raise errormod.Abort(_("inconsistent newline style " 449 raise errormod.Abort(
418 "in %s\n") % f) 450 _("inconsistent newline style " "in %s\n") % f
451 )
419 return super(eolrepo, self).commitctx(ctx, error, origctx) 452 return super(eolrepo, self).commitctx(ctx, error, origctx)
453
420 repo.__class__ = eolrepo 454 repo.__class__ = eolrepo
421 repo._hgcleardirstate() 455 repo._hgcleardirstate()