Commit Graph

121 Commits

Author SHA1 Message Date
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
Yuya Nishihara
783b9a6384 extensions: copy attributes to wrapper by wrapfunction()
Before this patch, new partial function "wrap" had no useful docstring. It
makes sense to copy __doc__ and __module__ as we do for wrapcommand().
2016-01-09 19:52:55 +09:00
Yuya Nishihara
80951b9f1b extensions: extract function that copies function attributes to wrapper
wrapfunction() will be changed to copy these attributes. See the next patch
for details.
2016-01-09 19:45:10 +09:00
Jun Wu
6ee6b437f3 extensions: add notloaded method to return extensions failed to load
Before this patch, there is no easy way to detect if there are extensions
failed to load. While this is okay for most situations, chgserver is designed
to preload all extensions specified in config and does need the information.
This patch adds extensions.notloaded() to return names of extensions failed
to load.
2016-02-10 16:59:34 +00:00
liscju
64f1a9aa22 version: verbose list internal and external extension source (issue4731) 2016-02-05 13:20:23 +01:00
timeless
ebb1d48658 cleanup: remove superfluous space after space after equals (python) 2015-12-31 08:16:59 +00:00
Gregory Szorc
2afb6aff3e extensions: refuse to load extensions if minimum hg version not met
As the author of several 3rd party extensions, I frequently see bug
reports from users attempting to run my extension with an old version
of Mercurial that I no longer support in my extension. Oftentimes, the
extension will import just fine. But as soon as we run extsetup(),
reposetup(), or get into the guts of a wrapped function, we encounter
an exception and abort. Today, Mercurial will print a message about
extensions that don't have a "testedwith" declaring explicit
compatibility with the current version.

The existing mechanism is a good start. But it isn't as robust as I
would like. Specifically, Mercurial assumes compatibility by default.
This means extension authors must perform compatibility checking in
their extsetup() or we wait and see if we encounter an abort at
runtime. And, compatibility checking can involve a lot of code and
lots of error checking. It's a lot of effort for extension authors.

Oftentimes, extension authors know which versions of Mercurial there
extension works on and more importantly where it is broken.

This patch introduces a magic "minimumhgversion" attribute in
extensions. When found, the extension loading mechanism will compare
the declared version against the current Mercurial version. If the
extension explicitly states we require a newer Mercurial version, a
warning is printed and the extension isn't loaded beyond importing
the Python module. This causes a graceful failure while alerting
the user of the compatibility issue.

I would be receptive to the idea of making the failure more fatal.
However, care would need to be taken to not criple every hg command.
e.g. the user may use `hg config` to fix the hgrc and if we aborted
trying to run that, the user would effectively be locked out of `hg`!

A potential future improvement to this functionality would be to catch
ImportError for the extension/module and parse the source code for
"minimumhgversion = 'XXX'" and do similar checking. This way we could
give more information about why the extension failed to load.
2015-11-24 15:16:25 -08:00
Augie Fackler
dafe189e47 extensions: properly mark progress as part of core
This should have been done as part of or as an immediate follow-up to
01b01d59e33f, but presumably this feature of extensions.py was
forgotten at that time.
2015-11-24 18:40:16 -05:00
Bryan O'Sullivan
94365b400e extensions: rename _ignore to _builtin, add descriptive comment
It was previously not at all obvious what this was for.

We also change it to a set to avoid iterating over an admittedly
small list repeatedly at startup time.
2015-11-24 16:38:54 -08:00
Mads Kiilerich
09567db49a spelling: trivial spell checking 2015-10-17 00:58:46 +02:00
Gregory Szorc
3d27c748ce extensions: use absolute_import 2015-08-08 19:13:14 -07:00
Gregory Szorc
5380dea2a7 global: mass rewrite to use modern exception syntax
Python 2.6 introduced the "except type as instance" syntax, replacing
the "except type, instance" syntax that came before. Python 3 dropped
support for the latter syntax. Since we no longer support Python 2.4 or
2.5, we have no need to continue supporting the "except type, instance".

This patch mass rewrites the exception syntax to be Python 2.6+ and
Python 3 compatible.

This patch was produced by running `2to3 -f except -w -n .`.
2015-06-23 22:20:08 -07:00
Yuya Nishihara
8c4e6f9099 extensions: show traceback on load failure if --traceback flag is set
Before this patch, there was no handy way to investigate the reason why
extension couldn't be loaded.

If ui.debug is set, tracebacks of both "hgext.foo" and "foo" are displayed
because the first ImportError could occur at very deep dependency module.
2015-03-30 16:23:35 +09:00
Gregory Szorc
466d2ce272 extensions: clear aftercallbacks after execution (issue4646)
It was reported that enabling pager without color could cause a hang.
Inserting print statements revealed that the callbacks in
extensions._aftercallbacks were being invoked twice.

extensions.loadall can be called multiple times. If entries in
extensions._aftercallbacks linger between calls, this could result
in double execution of the callbacks. This can lead to unwanted
behavior.

The reproduce steps in the bug seem to only occur when the output of
a command is less than the size of the current screen. This is not
something that can easily be tested. I verified the test case works
with this patch and that pager and color interaction continues to
work. Since we have no existing automated tests for pager, this sadly
appears to be the best testing I can do.
2015-05-06 09:52:10 -07:00
Eric Sumner
89d6b43acb extensions: extract partial application into a bind() function
We use partial function application for wrapping existing Mercurial functions,
and it's implemented separately each time.  This patch extracts the partial
application into a new bind() function that can be used on its own by extensions
when appropriate.

In particular, the evolve extension needs to wrap functions in the various
bundle2 processing dictionaries, which the pre-existing methods don't support.
2015-04-15 12:18:05 -04:00
Matt Harbison
7c735629be extensions: indicate loaded for an immediately called afterload callback
Otherwise, there's no way to tell between the immediate callback when it is
already loaded, and when the extension is not loaded at all.
2015-02-21 00:40:18 -05:00
Ryan McElroy
54e6a6adbc extensions: allow extending command synopsis and docstring
Mercurial uses a synopsis string and the docstring of a command for the
command's help output. Today  there is no way for an extension that adds
functionality to a command to extend either of these help strings.

This patch enables appending to both the doctring and the synopsis, and adds
a test for this functionality. Example usage is shown in the test and is also
described in the docstring of extensions.wrapcommand().
2015-02-09 11:02:45 -08:00
Gregory Szorc
d7228dc186 extensions: support callbacks after another extension loads
An upcoming patch will introduce a dependency between the color and
pager extensions. To prepare for this, we teach extensions how to
register callbacks that can execute when another extension loads.

This patch is based on code provided by Matt Mackall. But significant
parts have changed (such as the ability to register multiple callbacks
and the change in behavior to always call a callback).

I believe that always firing the callback is a good practice. I think
the common use for this feature will be for extensions to say "run this
one-time setup code, after this other extension if possible." Always
running the callback will facilitate this.
2015-02-06 12:07:32 -08:00
Siddharth Agarwal
845426bfe6 extensions: don't quit loading extensions in the middle if traceback is on
This was introduced way back in 2006 (rev e8e3582d6f80) as sys.exit(0) if
loading an extension failed when --traceback was on, then at some point morphed
into a 'return 1' in a function that otherwise returns nothing.

At this point, if ui.traceback is enabled and if loading an extension fails for
whatever reason, including one as innocent as it not being present, we leave
any extensions loaded so far in a bogus half-initialized state. That doesn't
really make any sense.
2015-01-23 20:30:49 -08:00
anatoly techtonik
1ed4ec4c3a version: show enabled extensions (issue4209)
This code is based by hg-versions extension (GPLv2)
by Markus Zapke-Gruendemann <info@keimlink.de>


http://mercurial.selenic.com/wiki/VersionsExtension
2014-06-10 13:44:37 +03:00
Augie Fackler
d39e848921 extensions: restore use of callable() since it was readded in Python 3.2 2014-06-23 09:24:06 -04:00