[PATCH RFC] shellext: automatically add shell scripts as new commands
Matt Mackall
mpm at selenic.com
Mon Jan 9 13:24:44 CST 2012
On Sat, 2012-01-07 at 18:56 +0100, Martin Geisler wrote:
> # HG changeset patch
> # User Martin Geisler <mg at aragost.com>
> # Date 1325959011 -3600
> # Node ID 8c34fa2adf476a1e07512207fb18866e7908cf58
> # Parent 3fe39d6d2bd8331932df063d272fff8af327881c
> shellext: automatically add shell scripts as new commands
>
> People sometimes note that Mercurial extensions must be written in
> Python, whereas extensions for Git can be written in any language.
> Some people see this as an advantage for Git. This extension lets you
> do the same for Mercurial.
>
> The only required change to core Mercurial is loading the extensions
> before checking for shell aliases -- this is so that the extension has
> a chance to register the new shell aliases.
Interesting. Some musings:
- Is this any different from aliases.foo = !somecommand?
Not yet?
- Do we search for other extensions in ~/.hgext?
Looks like no.
- Should this be built-in functionality?
Probably, if the aim is to making dropping things in trivial.
- Should we automatically enable everything in .hgext?
Probably, for consistency. But then 'hg showconfig --debug' no longer
completely explains where extensions are coming from. Alternately, the
name needs to be .hgshellext or something to make it clear that it's not
for normal extensions.
- How do we ship a shell extension in a way that a user can enable?
Should --config extensions.shellfoo= find $HGLIB/shellfoo.sh?
- How do we make these things work with the help engine?
By wrapping some RST in a specially-formatted comment block?
- What happens if someone shadows a built-in?
- Can we do anything to facilitate argument parsing?
It'd be extremely helpful to do some option parsing/validation like
fancyopts does and making sure we have the right number of args.
- How does the created environment compare to the generic pre- and post-
command hooks?
It should be the same (or richer). We'll need to be able to find the
current hg executable, for starters.
- What about Windows?
Should we look for .cmd scripts too?
- What if I want to write an extension in Python that's not a normal
Mercurial extension?
Ok, probably don't care about that.
> diff --git a/hgext/shellext.py b/hgext/shellext.py
> new file mode 100644
> --- /dev/null
> +++ b/hgext/shellext.py
> @@ -0,0 +1,50 @@
> +# Copyright 2012 Martin Geisler <mg at aragost.com>
> +#
> +# This software may be used and distributed according to the terms of
> +# the GNU General Public License version 2 or any later version.
> +
> +"""automatically register executables in ~/.hgext as new commands
> +
> +Enable this extension and you'll get a new command for any executable
> +script found in your ``~/.hgext`` folder. A script named ``foo.sh``
> +will give you a new ``hg foo`` command. If you invoke it as::
> +
> + hg foo -x bar -y baz
> +
> +then ``foo.sh`` will be invoked as
> +
> + foo.sh -x bar -y baz
> +
> +The above directory is the default and you can change it by setting
> +``shellext.extdir`` to another value.
> +"""
> +
> +import os, sys
> +from mercurial import util, dispatch
> +
> +_earlyopts = ["--config", "--cwd", "-R", "--repository", "--repo"]
> +
> +def uisetup(ui):
> + args = sys.argv[1:]
> + # remove the earlyopts that dispatch has already acted upon.
> + dispatch._earlygetopt(_earlyopts, args)
> + try:
> + # remove one layer of "quoting" so that it's possible to pass
> + # global opts to a shell command by putting them after '--'.
> + args.remove('--')
> + except ValueError:
> + pass
> +
> + aliasargs = ' '.join(map(util.shellquote, args[1:]))
> +
> + extdir = ui.configpath('shellext', 'extdir', os.path.expanduser('~/.hgext'))
> + if not os.path.isdir(extdir):
> + ui.debug('shellext: %s is not a directory\n' % extdir)
> + return
> +
> + for script in os.listdir(extdir):
> + path = os.path.join(extdir, script)
> + alias = os.path.splitext(script)[0]
> + if not os.access(path, os.X_OK):
> + continue
> + ui.setconfig('alias', alias, '!%s %s' % (path, aliasargs))
> diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
> --- a/mercurial/dispatch.py
> +++ b/mercurial/dispatch.py
> @@ -540,12 +540,6 @@
> rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
> path, lui = _getlocal(ui, rpath)
>
> - # Now that we're operating in the right directory/repository with
> - # the right config settings, check for shell aliases
> - shellaliasfn = _checkshellalias(lui, ui, args)
> - if shellaliasfn:
> - return shellaliasfn()
> -
> # Configure extensions in phases: uisetup, extsetup, cmdtable, and
> # reposetup. Programs like TortoiseHg will call _dispatch several
> # times so we keep track of configured extensions in _loaded.
> @@ -556,6 +550,12 @@
>
> # (uisetup and extsetup are handled in extensions.loadall)
>
> + # Now that we're operating in the right directory/repository with
> + # the right config settings, check for shell aliases
> + shellaliasfn = _checkshellalias(lui, ui, args)
> + if shellaliasfn:
> + return shellaliasfn()
> +
> for name, module in exts:
> cmdtable = getattr(module, 'cmdtable', {})
> overrides = [cmd for cmd in cmdtable if cmd in commands.table]
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercu
--
Mathematics is the supreme nostalgia of our time.
More information about the Mercurial-devel
mailing list