[PATCH 10 of 10] extensions: devel-warn ui object escaping from ui/extsetup
Jun Wu
quark at fb.com
Thu Jun 30 12:59:05 EDT 2016
# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1467296787 -3600
# Thu Jun 30 15:26:27 2016 +0100
# Node ID caf11c2daf24c7f94a506acb440e80ea37898870
# Parent 7c2dc6643d1c37dbc388ce4ac7112341f0926f28
# Available At https://bitbucket.org/quark-zju/hg-draft
# hg pull https://bitbucket.org/quark-zju/hg-draft -r caf11c2daf24
extensions: devel-warn ui object escaping from ui/extsetup
Storing a reference to the ui object in uisetup or extsetup can cause troubles
since the ui object can be outdated because of ui.copy()s or ui.__init__()s.
It's especially an issue with chgserver since it's designed to call uisetup
only once.
This patch adds a develwarn to notify developers this usage is discouraged.
See also https://twitter.com/durin42/status/739836476318318592 .
diff --git a/mercurial/extensions.py b/mercurial/extensions.py
--- a/mercurial/extensions.py
+++ b/mercurial/extensions.py
@@ -7,8 +7,10 @@
from __future__ import absolute_import
+import contextlib
import imp
import os
+import sys
from .i18n import (
_,
@@ -127,20 +129,31 @@ def load(ui, name, path):
fn(loaded=True)
return mod
+ at contextlib.contextmanager
+def _checkuiescape(name, ui):
+ nref = sys.getrefcount(ui)
+ yield
+ nrefchange = sys.getrefcount(ui) - nref
+ if nrefchange > 0 and (ui.configbool('devel', 'all-warnings')
+ or ui.configbool('devel', 'check-uiescape')):
+ ui.develwarn('"ui" escaped from %s' % name, stacklevel=None)
+
def _runuisetup(name, ui):
- uisetup = getattr(_extensions[name], 'uisetup', None)
- if uisetup:
- uisetup(ui)
+ with _checkuiescape('%s.uisetup' % name, ui):
+ uisetup = getattr(_extensions[name], 'uisetup', None)
+ if uisetup:
+ uisetup(ui)
def _runextsetup(name, ui):
- extsetup = getattr(_extensions[name], 'extsetup', None)
- if extsetup:
- try:
- extsetup(ui)
- except TypeError:
- if extsetup.func_code.co_argcount != 0:
- raise
- extsetup() # old extsetup with no ui argument
+ with _checkuiescape('%s.extsetup' % name, ui):
+ extsetup = getattr(_extensions[name], 'extsetup', None)
+ if extsetup:
+ try:
+ extsetup(ui)
+ except TypeError:
+ if extsetup.func_code.co_argcount != 0:
+ raise
+ extsetup() # old extsetup with no ui argument
def loadall(ui):
result = ui.configitems("extensions")
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -1164,6 +1164,7 @@ class ui(object):
return
msg = 'devel-warn: ' + msg
if stacklevel is None:
+ self.write_err('%s\n' % msg)
self.log('develwarn', msg)
return
stacklevel += 1 # get in develwarn
diff --git a/tests/test-devel-warnings.t b/tests/test-devel-warnings.t
--- a/tests/test-devel-warnings.t
+++ b/tests/test-devel-warnings.t
@@ -1,4 +1,3 @@
-
$ cat << EOF > buggylocking.py
> """A small extension that tests our developer warnings
> """
@@ -74,6 +73,18 @@
> all-warnings=1
> EOF
+ $ cat << EOF > uiescape.py
+ > a = []
+ > def uisetup(ui):
+ > ui.write('ui escaping\n')
+ > a.append(ui)
+ > EOF
+
+ $ hg --config extensions.uiescape=uiescape.py version -q
+ ui escaping
+ devel-warn: "ui" escaped from uiescape.uisetup
+ Mercurial * (glob)
+
$ hg init lock-checker
$ cd lock-checker
$ hg buggylocking
More information about the Mercurial-devel
mailing list