comparison mercurial/dispatch.py @ 23871:b2d8f3685b06

dispatch: only check compatibility against major and minor versions (BC) Extensions can declare compatibility with Mercurial versions. If an error occurs, Mercurial will attempt to pin blame on an extension that isn't marked as compatible. While all bets are off when it comes to the internal API, my experience has shown that a monthly/patch release of Mercurial has never broken any of the extensions I've written. I think that expecting extensions to declare compatibility with every patch release of Mercurial is asking a bit much and adds little to no value. This patch changes the blame logic from exact version matching to only match on the major and minor Mercurial versions. This means that extensions only need to mark themselves as compatible with the major, quarterly releases and not the monthly ones in order to stay current and avoid what is almost certainly unfair blame. This will mean less work for extension authors and almost certainly fewer false positives in the blame attribution.
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 15 Jan 2015 20:36:03 -0800
parents 41c03b7592ed
children 2ee35b6ee4fb 97a548aeb749
comparison
equal deleted inserted replaced
23870:9070e20057ae 23871:b2d8f3685b06
281 report = getattr(mod, 'buglink', _('the extension author.')) 281 report = getattr(mod, 'buglink', _('the extension author.'))
282 if not testedwith.strip(): 282 if not testedwith.strip():
283 # We found an untested extension. It's likely the culprit. 283 # We found an untested extension. It's likely the culprit.
284 worst = name, 'unknown', report 284 worst = name, 'unknown', report
285 break 285 break
286 if compare not in testedwith.split() and testedwith != 'internal': 286
287 tested = [tuplever(v) for v in testedwith.split()] 287 # Never blame on extensions bundled with Mercurial.
288 lower = [t for t in tested if t < ct] 288 if testedwith == 'internal':
289 nearest = max(lower or tested) 289 continue
290 if worst[0] is None or nearest < worst[1]: 290
291 worst = name, nearest, report 291 tested = [tuplever(t) for t in testedwith.split()]
292 if ct in tested:
293 continue
294
295 lower = [t for t in tested if t < ct]
296 nearest = max(lower or tested)
297 if worst[0] is None or nearest < worst[1]:
298 worst = name, nearest, report
292 if worst[0] is not None: 299 if worst[0] is not None:
293 name, testedwith, report = worst 300 name, testedwith, report = worst
294 if not isinstance(testedwith, str): 301 if not isinstance(testedwith, str):
295 testedwith = '.'.join([str(c) for c in testedwith]) 302 testedwith = '.'.join([str(c) for c in testedwith])
296 warning = (_('** Unknown exception encountered with ' 303 warning = (_('** Unknown exception encountered with '
313 320
314 return -1 321 return -1
315 322
316 def tuplever(v): 323 def tuplever(v):
317 try: 324 try:
318 return tuple([int(i) for i in v.split('.')]) 325 # Assertion: tuplever is only used for extension compatibility
326 # checking. Otherwise, the discarding of extra version fields is
327 # incorrect.
328 return tuple([int(i) for i in v.split('.')[0:2]])
319 except ValueError: 329 except ValueError:
320 return tuple() 330 return tuple()
321 331
322 def aliasargs(fn, givenargs): 332 def aliasargs(fn, givenargs):
323 args = getattr(fn, 'args', []) 333 args = getattr(fn, 'args', [])