Commit Graph

141 Commits

Author SHA1 Message Date
Boris Feld
80d3295191 extensions: register config item early
Config items are likely to be used in during extensions setup. So we much
register them before that.

For example this apply to the 'win32text.warn' options.
2017-09-05 00:34:13 +02:00
Boris Feld
8744970b58 extensions: factor extra data loading out
Some of the extra data need to be registered earlier than they currently are
(eg: config items). We first factor out the logic to registered them in a small
function before reusing it in the next changeset.
2017-09-05 00:31:59 +02:00
Yuya Nishihara
04508d7f1c extensions: fix wrapcommand/function of class instance
5f4c097a17d2 changed _updatewrapper() to copy the __name__ attribute, but
not all callable objects has __name__.

Spotted by loading mq with extdiff.
2017-09-10 23:37:14 +09:00
Jun Wu
8b69f8688d wrapcommand: use functools.partial
Like the previous patch, this helps remove noises in traceback.

Practically, this removes another 6 lines in `rebase -s . -d .` traceback in
my setup:

   ....
   File "hg/mercurial/util.py", line 1118, in check
     return func(*args, **kwargs)
  -File "hg/mercurial/extensions.py", line 331, in closure
  -  return func(*(args + a), **kw)
   File "hg/mercurial/util.py", line 1118, in check
     return func(*args, **kwargs)
   File "fb-hgext/hgext3rd/fbhistedit.py", line 283, in _rebase
     return orig(ui, repo, **opts)
   File "hg/mercurial/util.py", line 1118, in check
     return func(*args, **kwargs)
  -File "hg/mercurial/extensions.py", line 331, in closure
  -  return func(*(args + a), **kw)
   File "hg/mercurial/util.py", line 1118, in check
     return func(*args, **kwargs)
   File "remotenames.py", line 633, in exrebasecmd
     ret = orig(ui, repo, **opts)
   File "hg/mercurial/util.py", line 1118, in check
     return func(*args, **kwargs)
  -File "hg/mercurial/extensions.py", line 331, in closure
  -  return func(*(args + a), **kw)
   File "hg/mercurial/util.py", line 1118, in check
     return func(*args, **kwargs)
   File "fb-hgext/hgext3rd/fbamend/__init__.py", line 453, in wraprebase
     return orig(ui, repo, **opts)
   File "hg/mercurial/util.py", line 1118, in check
     return func(*args, **kwargs)
   ....

Differential Revision: https://phab.mercurial-scm.org/D633
2017-09-05 15:18:45 -07:00
Jun Wu
f89434c718 wrapfunction: use functools.partial if possible
Every `extensions.bind` call inserts a frame in traceback:

   ... in closure
     return func(*(args + a), **kw)

which makes traceback noisy.

The Python stdlib has a `functools.partial` which is backed by C code and
does not pollute traceback. However it does not support instancemethod and
sets `args` attribute which could be problematic for alias handling.

This patch makes `wrapfunction` use `functools.partial` if we are wrapping a
function directly exported by a module (so it's impossible to be a class or
instance method), and special handles `wrapfunction` results so alias
handling code could handle `args` just fine.

As an example, `hg rebase -s . -d . --traceback` got 6 lines removed in my
setup:

   File "hg/mercurial/dispatch.py", line 898, in _dispatch
     cmdpats, cmdoptions)
  -File "hg/mercurial/extensions.py", line 333, in closure
  -  return func(*(args + a), **kw)
   File "hg/hgext/journal.py", line 84, in runcommand
     return orig(lui, repo, cmd, fullargs, *args)
  -File "hg/mercurial/extensions.py", line 333, in closure
  -  return func(*(args + a), **kw)
   File "fb-hgext/hgext3rd/fbamend/hiddenoverride.py", line 119, in runcommand
     result = orig(lui, repo, cmd, fullargs, *args)
   File "hg/mercurial/dispatch.py", line 660, in runcommand
     ret = _runcommand(ui, options, cmd, d)
  -File "hg/mercurial/extensions.py", line 333, in closure
  -  return func(*(args + a), **kw)
   File "hg/hgext/pager.py", line 69, in pagecmd
     return orig(ui, options, cmd, cmdfunc)
   ....

Differential Revision: https://phab.mercurial-scm.org/D632
2017-09-05 13:37:36 -07:00
Christophe de Vienne
87902af734 extensions: prohibit unicode defaults
If the default value of an option is a unicode string (something
than happen easily when using a 'from __future__ import unicode_literals'),
any value passed on the command line will be ignored because the fancyopts
module only checks for byte strings and not unicode strings.

Changing fancyopts behavior is easy but would make assumptions on how
the python3 port should be done, which is outside the scope of this patch.

The chosen approach is to stop an extension from being loaded when a unicode
default value is detected, with a hint for the developer.
2017-08-29 18:24:51 +02:00
Martin von Zweigbergk
45124be9f2 extensions: add wrappedfunction() context manager
Several extensions exist that temporarily want to wrap a function (at
least narrowhg, any many of the extensions in hg-experimental). That's
why we have the unwrapfunction() that was introduced in c8cda8f6f043
(extensions: add unwrapfunction to undo wrapfunction, 2016-08-10).

This patch adds a simple wrappedfunction() that returns a context
manager.

Differential Revision: https://phab.mercurial-scm.org/D472
2017-08-21 16:46:05 -07:00
Augie Fackler
a5ac7e4cdd extensions: don't give AttributeError bytes message on Python 3
Differential Revision: https://phab.mercurial-scm.org/D353
2017-08-11 15:09:54 -04:00
Augie Fackler
749c36880e extensions: if on py3 and propname is a bytestr, convert to sysstr
Property names are unicodes on Python 3.

Differential Revision: https://phab.mercurial-scm.org/D296
2017-07-25 22:49:43 -04:00
Augie Fackler
132219fd71 extensions: attempt to use non-deprecated inspect method
Avoids some deprecation warnings when extension loading breaks.

Differential Revision: https://phab.mercurial-scm.org/D295
2017-07-25 22:48:46 -04:00
FUJIWARA Katsunori
0c86ac795a filemerge: move decorator definition for internal merge tools to registrar
This patch also adds extra loading entry for internal merge tools to
extensions.py, for similarity to other decorators defined in
registrar.py.

This patch uses "internalmerge" for decorator class name, instead of
original "internaltool", because the latter is too generic.

BTW, after this patch, 4-spaces indentation is added to the 1st line
of internal merge tool description docstring, and this may make
already translated entries in *.po fuzzy.

Even though this indentation is required for "definition list" in reST
syntax, absence of it has been overlooked, because help.makeitemsdoc()
forcibly inserts it at generation of online help.

But this forcible insertion causes formatting issue (I'll send another
patch series for this). Therefore, this additional indentation should
be reasonable.
2017-08-06 01:13:57 +09:00
Yuya Nishihara
fb236e4381 py3: convert arbitrary exception object to byte string more reliably
Our exception types implement __bytes__(), which should be tried first. Do
lossy encoding conversion as a last resort.
2017-08-03 23:02:32 +09:00
Boris Feld
d46e1b04e2 color: drop the now useless color extension
all the extension features are provided by core since 4.2.
2017-07-15 14:17:35 +02:00
Boris Feld
776e7ed136 extensions: expand the builtins extensions declaration
This will future updates of the set cleaner and more readable.
2017-07-15 14:16:54 +02:00
Martin von Zweigbergk
d4520a7687 dispatch: fix typo suggestion for disabled extension
If the matching command lives in an in-tree extension (which is all we
scan for), and the user has disabled that extension with
"extensions.<name>=!", we were not finding it, because the path in
_disabledextensions was the empty string. If the user had set
"extensions.<name>=!<valid path>" it would work, so it seems like just
a mistake that it didn't work.
2017-07-07 00:13:53 -07:00
Pierre-Yves David
1dab0bbe74 configitems: add an official API for extensions to register config item
Extensions can have a 'configtable' mapping and use
'registrar.configitem(table)' to retrieve the registration function.

This behave in the same way as the other way for extensions to register new
items (commands, colors, etc).
2017-06-17 13:48:20 +02:00
FUJIWARA Katsunori
fdb6557cf4 extensions: register functions always at loading extension (issue5601)
Before this patch, functions defined in extensions are registered via
extra loaders only in _dispatch(). Therefore, loading extensions in
other code paths like below omits registration of functions.

  - WSGI service
  - operation across repositories (e.g. subrepo)
  - test-duplicateoptions.py, using extensions.loadall() directly

To register functions always at loading new extension, this patch
moves implementation for extra loading from dispatch._dispatch() to
extensions.loadall().

AFAIK, only commands module causes cyclic dependency between
extensions module, but this patch imports all related modules just
before extra loading in loadall(), in order to centralize them.

This patch makes extensions.py depend on many other modules, even
though extensions.py itself doesn't. It should be avoided if possible,
but I don't have any better idea. Some other places like below aren't
reasonable for extra loading, IMHO.

  - specific function in newly added module:
    existing callers of extensions.loadall() should invoke it, too

  - hg.repository() or so:
    no-repo commands aren't covered by this.

BTW, this patch removes _loaded.add(name) on relocation, because
dispatch._loaded is used only for extraloaders (for similar reason,
"exts" variable is removed, too).
2017-06-24 02:39:20 +09:00
Adam Simpkins
bca99d2980 extensions: call afterloaded() with loaded=False for disabled extensions
If an extension was loaded but disabled due to a minimumhgversion check it
will be present in the _extensions map, but set to None.  The rest of the
extensions code treats the extension as if it were not present in this case,
but the afterloaded() function called the callback with loaded=True.
2017-06-23 10:59:05 -07:00
Augie Fackler
19e290eb76 extensions: catch uisetup and extsetup failures and don't let them break hg
Otherwise users of the patience diff extension will be unable to run
anything at all in hg 4.3 until they figure out what's broken.
2017-06-06 10:09:48 -04:00
Augie Fackler
fc22e5fdd7 extensions: move wrapfilecache function from fsmonitor
It makes more sense to put this in core, so other extensions can
trivially get access to it without having to rely on importing
fsmonitor.
2017-06-08 10:44:53 -04:00
Jun Wu
610c5f87a9 profiling: allow loading profiling extension before everything else
459366b580cf makes profiler start early without loading extensions. That
makes it impossible for an extension to add customized profilers.

This patch adds a special case: if a profiler is not found but an extension
with the same name could be loaded, load that extension first, and expect it
to have a "profile" contextmanager method. This allows customized profilers
and extension setup time is still profiled.
2017-05-22 01:17:49 -07:00
Jun Wu
1e83688564 extensions: allow loading a whitelisted subset of extensions
This feature will be used by the next patch.
2017-05-22 00:51:56 -07:00
Yuya Nishihara
7b77796abc extensions: show deprecation warning for the use of cmdutil.command
Since this is a fundamental API for extensions, we set 1-year period until
actually removing it.
2016-01-09 23:24:52 +09:00
Yuya Nishihara
029af11327 extensions: prohibit registration of command without using @command (API)
Detect the problem earlier for better error indication. I'm tired of teaching
users that the mq extension is not guilty but the third-party extension is.

https://bitbucket.org/tortoisehg/thg/issues?q=%27norepo%27
2017-05-13 15:41:50 +09:00
Yuya Nishihara
748641feec extensions: optionally print hint on import failure
Test will be added by the next patch.
2017-05-14 15:46:45 +09:00
Martin von Zweigbergk
c3406ac3db cleanup: use set literals
We no longer support Python 2.6, so we can now use set literals.
2017-02-10 16:56:29 -08:00
Yuya Nishihara
1310da54cd cleanup: remove useless re-raises of KeyboardInterrupt
KeyboardInterrupt is no longer a subclass of Exception since Python 2.5.

https://docs.python.org/2/whatsnew/2.5.html#pep-352-exceptions-as-new-style-classes
2017-05-03 11:16:55 +09:00
Yuya Nishihara
af7f25fdb3 encoding: add converter between native str and byte string
This kind of encoding conversion is unavoidable on Python 3.
2017-03-13 09:12:56 -07:00
Yuya Nishihara
dcade16cf7 encoding: factor out unicode variants of from/tolocal()
Unfortunately, these functions will be commonly used on Python 3.
2017-03-13 09:11:08 -07:00
Augie Fackler
4d06a903c5 extensions: tapdance to get reasonable import error formatting
I'm not thrilled with this, but it seems to work.
2017-03-03 14:08:02 -05:00
Augie Fackler
98883dec44 extensions: use [0:1] slice on config path instead of [0]
This behaves the same in Python 2 and Python 3, even though the path
is a bytes.
2017-03-03 13:32:10 -05:00
Augie Fackler
8db5d39760 extensions: use inspect module instead of func_code.co_argcount
Fixes the extsetup argspec check on Python 3.
2017-03-03 13:27:21 -05:00
Pulkit Goyal
22dbb9466c py3: use pycompat.fsencode() to convert __file__ to bytes
__file__ returns unicodes on Python 3. This patch uses pycompat.fsencode() to
convert them to bytes.
2017-02-20 18:40:42 +05:30
Pulkit Goyal
617e2aec61 py3: use pycompat.fsdecode() to pass to imp.* functions
When we try to pass a bytes argument to a function from imp library, it
returns TypeError as it deals with unicodes internally. So we can't use bytes
with imp.* functions. Hunting through this, I found we were returning bytes
path variable to loadpath() on Python 3.5 (yes most of our codebase is
dealing with bytes on Python 3 especially the path variables). Passing unicode
does not fails the purpose of loding the extensions and a module object is
returned.
2016-12-05 06:46:51 +05:30
Pulkit Goyal
849c625bac py3: use pycompat.sysstr() in __import__()
__import__() on Python 3 accepts strings which are different from that of
Python 2. Used pycompat.sysstr() to get string accordingly.
2016-12-01 13:12:04 +05:30
Pulkit Goyal
96b2983c6a help: show help for disabled extensions (issue5228)
This patch does not exactly solve issue5228 but it results in a better
condition on this issue. For disabled extensions, we used to parse the
module and get the first occurrences of docstring and then return the first
line of that as an introductory heading of extension. This is what we get
today.

This patch returns the whole docstring of the module as a help for extension,
which is more informative. There are some modules which don't have much
docstring at top level except the heading so those are unaffected by this
change. To follow the existing trend of showing commands either we have to
load the extension or have a very ugly parsing method which don't even assure
correctness.
2016-11-06 06:54:31 +05:30
Jun Wu
af2ff7c3d4 extensions: move the "import" logic out from "load"
The "load" method does too many things: on-demand import and check version.
This patch moves the import logic out from "load" so it could be wrapped to
change the import behavior, for example, chg will use it to pre-import
extensions.
2016-10-03 03:37:10 +01:00
Pierre-Yves David
cefbc74b98 extensions: add a note about debug output during extensions search
These messages do not show up when one use '--debug'. This is quite confusing so
we clarify the situation next to the 'ui.debug' call.
2016-09-30 00:27:35 +02:00
Pierre-Yves David
9680f282d3 extensions: fix a debug message when searching for extensions
The "next" value was wrong. When 'hgext.NAME' is not found we now search for
'hgext3rd.NAME'.
2016-09-30 00:25:15 +02:00
liscju
3f71c6cdfa help: show content for explicitly disabled extension (issue5228) 2016-09-01 22:06:42 +02:00
Augie Fackler
4e1c384d0a extensions: change magic "shipped with hg" string
I've caught multiple extensions in the wild lying about being
'internal', so it's time to move the goalposts on people. Goalpost
moving will continue until third party extensions stop trying to
defeat the system.
2016-08-23 11:26:08 -04:00
Jun Wu
c363f01ef4 extensions: add unwrapfunction to undo wrapfunction
Before this patch, we don't have a safe way to undo a wrapfunction because
other extensions may wrap the same function and calling setattr will undo
them accidentally.

This patch adds an "unwrapfunction" to address the issue. It removes the
wrapper from the wrapper chain, and re-wraps everything, which is not the
most efficient but short and easy to understand. We can revisit the code
if we have perf issues with long chains.

The "undo" feature is useful in cases like wrapping a function just in a
scope. Like, having a "select" command to interactively (using arrow keys)
select content from some output (ex. smartlog). It could wrap "ui.label" to
extract interesting texts just in the "select" command.
2016-08-10 16:27:33 +01:00
Jun Wu
8d2cc91a76 extensions: add getwrapperchain to get a list of wrappers
The getwrapperchain returns a list of wrappers + the original function, making
it easier to understand what has been wrapped by whom. For example:

  In : mercurial.extensions.getwrapperchain(mercurial.dispatch, '_runcommand')
  Out:
  [<function hgext.pager.pagecmd>,
   <function hgext.color.colorcmd>,
   <function hgext.zeroconf.cleanupafterdispatch>,
   <function mercurial.dispatch._runcommand>]

It will also be useful to safely unwrap a function. See the next patch.
2016-08-10 15:21:42 +01:00
Jun Wu
2b5d8836a9 extensions: set attributes to wrappers so we can trace them back
This patch adds two attributes about the original function and the unbound
wrapper. It allows us to get a chain of wrappers. See the next patch.
2016-08-10 15:21:42 +01:00
Jun Wu
1dbd891ce1 extensions: move uisetup and extsetup to standalone functions
This is to make them wrap-able. chgserver wants to know if an extension
accesses config or environment variables during uisetup and extsetup and
include them in confighash accordingly.
2016-06-30 10:31:50 +01:00
Jun Wu
1c8f26818c hgcia: remove hgcia (BC)
As discussed at:
https://www.mercurial-scm.org/pipermail/mercurial-devel/2016-March/081018.html,
cia service is down for years. It also uses socket.setdefaulttimeout() which
will break chg. This patch removes the extension.
2016-05-12 01:03:19 +01:00
Pierre-Yves David
5d3d0e1d77 extensions: also search for extension in the 'hgext3rd' package
Mercurial extensions are not meant to be normal python package/module. Yet the
lack of an official location to install them means that a lot of them actually
install as root level python package, polluting the global Python package
namespace and risking collision with more legit packages. As we recently
discovered, core python actually support namespace package. A way for multiples
distinct "distribution" to share a common top level package without fear of
installation headache. (Namespace package allow submodule installed in different
location (of the 'sys.path') to be imported properly. So we are fine as long as
extension includes a proper 'hgext3rd.__init__.py' to declare the namespace
package.)

Therefore we introduce a 'hgext3rd' namespace packages and search for extension
in it. We'll then recommend third extensions to install themselves in it.
Strictly speaking we could just get third party extensions to install in 'hgext'
as it is also a namespace package. However, this would make the integration of
formerly third party extensions in the main distribution more complicated as the third
party install would overwrite the file from the main install. Moreover, having an
explicit split between third party and core extensions seems like a good idea.

The name 'hgext3rd' have been picked because it is short and seems explicit enough.
Other alternative I could think of where:

- hgextcontrib
- hgextother
- hgextunofficial
2016-03-11 10:30:08 +00:00
Pierre-Yves David
e51996ccf2 extensions: factor import error reporting out
To clarify third party extensions lookup, we are about to add a third place
where extensions are searched for. So we factor the error reporting logic out to
be able to easily reuse it in the next patch.
2016-03-11 10:28:58 +00:00
Pierre-Yves David
1ab6440d02 extensions: extract the 'importh' closure as normal function
There is no reason for this to be a closure so we extract it for clarity.
2016-03-11 10:24:54 +00:00
Yuya Nishihara
ef3218aaaf extensions: copy extra __dict__ of original function
Future patches will make @command decorator set properties such as "norepo" to
a function object. This patch makes sure these properties never be lost by
wrapcommand() or wrapfunction().

This change won't be crazy as the standard functools.wraps() copies __dict__.
2016-01-09 20:04:03 +09:00