[PATCH 3 of 3] dispatch: only check compatibility against major and minor versions

Gregory Szorc gregory.szorc at gmail.com
Thu Jan 15 22:36:20 CST 2015


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1421382963 28800
#      Thu Jan 15 20:36:03 2015 -0800
# Node ID 28e3fdafed22396c10964fa72c869c0e8c81ae05
# Parent  d9c6f710438d71fb5b4114f0639d27f75d8cf1b9
dispatch: only check compatibility against major and minor versions

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.

diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -282,14 +282,21 @@ def _runcatch(req):
             if not testedwith.strip():
                 # We found an untested extension. It's likely the culprit.
                 worst = name, 'unknown', report
                 break
-            if compare not in testedwith.split() and testedwith != 'internal':
-                tested = [tuplever(v) for v in testedwith.split()]
-                lower = [t for t in tested if t < ct]
-                nearest = max(lower or tested)
-                if worst[0] is None or nearest < worst[1]:
-                    worst = name, nearest, report
+
+            # Never blame on extensions bundled with Mercurial.
+            if testedwith == 'internal':
+                continue
+
+            tested = [tuplever(t) for t in testedwith.split()]
+            if ct in tested:
+                continue
+
+            lower = [t for t in tested if t < ct]
+            nearest = max(lower or tested)
+            if worst[0] is None or nearest < worst[1]:
+                worst = name, nearest, report
         if worst[0] is not None:
             name, testedwith, report = worst
             if not isinstance(testedwith, str):
                 testedwith = '.'.join([str(c) for c in testedwith])
@@ -314,9 +321,12 @@ def _runcatch(req):
     return -1
 
 def tuplever(v):
     try:
-        return tuple([int(i) for i in v.split('.')])
+        # Assertion: tuplever is only used for extension compatibility
+        # checking. Otherwise, the discarding of extra version fields is
+        # incorrect.
+        return tuple([int(i) for i in v.split('.')[0:2]])
     except ValueError:
         return tuple()
 
 def aliasargs(fn, givenargs):
diff --git a/tests/test-extension.t b/tests/test-extension.t
--- a/tests/test-extension.t
+++ b/tests/test-extension.t
@@ -857,9 +857,9 @@ Broken disabled extension and command:
   (try "hg help --keyword foo")
   [255]
 
   $ cat > throw.py <<EOF
-  > from mercurial import cmdutil, commands
+  > from mercurial import cmdutil, commands, util
   > cmdtable = {}
   > command = cmdutil.command(cmdtable)
   > class Bogon(Exception): pass
   > @command('throw', [], 'hg throw', norepo=True)
@@ -909,9 +909,9 @@ If the extensions declare outdated versi
   $ rm -f throw.pyc throw.pyo
   $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
   >   throw 2>&1 | egrep '^\*\*'
   ** Unknown exception encountered with possibly-broken third-party extension older
-  ** which supports versions 1.9.3 of Mercurial.
+  ** which supports versions 1.9 of Mercurial.
   ** Please disable older and try your action again.
   ** If that fixes the bug please report it to the extension author.
   ** Python * (glob)
   ** Mercurial Distributed SCM (version 2.2)
@@ -922,9 +922,9 @@ One extension only tested with older, on
   $ rm -f older.pyc older.pyo
   $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
   >   throw 2>&1 | egrep '^\*\*'
   ** Unknown exception encountered with possibly-broken third-party extension older
-  ** which supports versions 1.9.3 of Mercurial.
+  ** which supports versions 1.9 of Mercurial.
   ** Please disable older and try your action again.
   ** If that fixes the bug please report it to the extension author.
   ** Python * (glob)
   ** Mercurial Distributed SCM (version 2.1)
@@ -935,9 +935,9 @@ Older extension is tested with current v
   $ rm -f older.pyc older.pyo
   $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
   >   throw 2>&1 | egrep '^\*\*'
   ** Unknown exception encountered with possibly-broken third-party extension throw
-  ** which supports versions 2.1.1 of Mercurial.
+  ** which supports versions 2.1 of Mercurial.
   ** Please disable throw and try your action again.
   ** If that fixes the bug please report it to http://example.com/bts
   ** Python * (glob)
   ** Mercurial Distributed SCM (version 1.9.3)
@@ -953,8 +953,19 @@ Declare the version as supporting this h
   ** Python * (glob)
   ** Mercurial Distributed SCM (*) (glob)
   ** Extensions loaded: throw
 
+Patch version is ignored during compatibility check
+  $ echo "testedwith = '3.2'" >> throw.py
+  $ echo "util.version = lambda:'3.2.2'" >> throw.py
+  $ rm -f throw.pyc throw.pyo
+  $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
+  ** unknown exception encountered, please report by visiting
+  ** http://mercurial.selenic.com/wiki/BugTracker
+  ** Python * (glob)
+  ** Mercurial Distributed SCM (*) (glob)
+  ** Extensions loaded: throw
+
 Test version number support in 'hg version':
   $ echo '__version__ = (1, 2, 3)' >> throw.py
   $ rm -f throw.pyc throw.pyo
   $ hg version -v


More information about the Mercurial-devel mailing list