Log message for revision 116268: Merge r116267 from 2.12 branch. Changed: U Zope/trunk/doc/CHANGES.rst U Zope/trunk/doc/operation.rst U Zope/trunk/src/Zope2/Startup/zopectl.py
-=- Modified: Zope/trunk/doc/CHANGES.rst =================================================================== --- Zope/trunk/doc/CHANGES.rst 2010-09-09 12:54:45 UTC (rev 116267) +++ Zope/trunk/doc/CHANGES.rst 2010-09-09 12:58:54 UTC (rev 116268) @@ -11,7 +11,11 @@ Bugs Fixed ++++++++++ +Features Added +++++++++++++++ +- Add ability to define extra zopectl commands via setuptools entrypoints. + 2.13.0a4 (2010-09-09) --------------------- Modified: Zope/trunk/doc/operation.rst =================================================================== --- Zope/trunk/doc/operation.rst 2010-09-09 12:54:45 UTC (rev 116267) +++ Zope/trunk/doc/operation.rst 2010-09-09 12:58:54 UTC (rev 116268) @@ -154,3 +154,40 @@ should already be available. - See the :doc:`CHANGES` for important notes on this version of Zope. + + + +Adding extra commands to Zope +----------------------------- + +It is possible to add extra commands to ``zopectl`` by defining *entry points* +in ``setup.py``. Commands have to be put in the ``zopectl.command`` group: + +.. code-block:: python + + setup(name="MyPackage", + .... + entry_points=""" + [zopectl.command] + init_app = mypackage.commands:init_application + """) + +.. note:: + + Due to an implementation detail of ``zopectl`` you can not use a minus + character (``-``) in the command name. + +This adds a ``init_app`` command that can be used directly from the commandline:: + + bin\zopectl init_app + +The command must be implemented as a python callable. It will be called with +two parameters: the Zope2 application and a tuple with all commandline +arguments. Here is a basic example: + +.. code-block:: python + + def init_application(app, args): + print 'Initialisating the application' + + Modified: Zope/trunk/src/Zope2/Startup/zopectl.py =================================================================== --- Zope/trunk/src/Zope2/Startup/zopectl.py 2010-09-09 12:54:45 UTC (rev 116267) +++ Zope/trunk/src/Zope2/Startup/zopectl.py 2010-09-09 12:58:54 UTC (rev 116268) @@ -36,10 +36,13 @@ action "help" to find out about available actions. """ +import csv import os import sys import signal +import pkg_resources + import zdaemon import Zope2.Startup @@ -328,6 +331,63 @@ print "debug -- run the Zope debugger to inspect your database" print " manually using a Python interactive shell" + def __getattr__(self, name): + """Getter to check if an unknown command is implement by an entry point.""" + if not name.startswith("do_"): + raise AttributeError(name) + data=list(pkg_resources.iter_entry_points("zopectl.command", name=name[3:])) + if not data: + raise AttributeError(name) + if len(data)>1: + print >>sys.stderr, "Warning: multiple entry points found for command" + return + func=data[0].load() + if not callable(func): + print >>sys.stderr, "Error: %s is not a callable method" % name + return + + return self.run_entrypoint(data[0]) + + + def run_entrypoint(self, entry_point): + def go(arg): + # If the command line was something like + # """bin/instance run "one two" three""" + # cmd.parseline will have converted it so + # that arg == 'one two three'. This is going to + # foul up any quoted command with embedded spaces. + # So we have to return to self.options.args, + # which is a tuple of command line args, + # throwing away the "run" command at the beginning. + # + # Further complications: if self.options.args has come + # via subprocess, it may look like + # ['run "arg 1" "arg2"'] rather than ['run','arg 1','arg2']. + # If that's the case, we'll use csv to do the parsing + # so that we can split on spaces while respecting quotes. + if len(self.options.args) == 1: + tup = csv.reader(self.options.args, delimiter=' ').next() + + # Remove -c and add command name as sys.argv[0] + cmd = [ 'import sys', + 'sys.argv.pop()', + 'sys.argv.append(r\'%s\')' % entry_point.name + ] + if len(tup) > 1: + argv = tup[1:] + cmd.append('[sys.argv.append(x) for x in %s]; ' % argv) + cmd.extend([ + 'import pkg_resources', + 'import Zope2', + 'func=pkg_resources.EntryPoint.parse(\'%s\').load(False)' % entry_point, + 'app=Zope2.app()', + 'func(app)', + ]) + cmdline = self.get_startup_cmd(self.options.python, ' ; '.join(cmd)) + self._exitstatus = os.system(cmdline) + return go + + def do_run(self, args): if not args: print "usage: run <script> [args]" _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins