123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- # -*- coding: utf-8 -*-
- """The :program:`celery` umbrella command.
- .. program:: celery
- .. _preload-options:
- Preload Options
- ---------------
- These options are supported by all commands,
- and usually parsed before command-specific arguments.
- .. cmdoption:: -A, --app
- app instance to use (e.g., ``module.attr_name``)
- .. cmdoption:: -b, --broker
- URL to broker. default is ``amqp://guest@localhost//``
- .. cmdoption:: --loader
- name of custom loader class to use.
- .. cmdoption:: --config
- Name of the configuration module
- .. cmdoption:: -C, --no-color
- Disable colors in output.
- .. cmdoption:: -q, --quiet
- Give less verbose output (behavior depends on the sub command).
- .. cmdoption:: --help
- Show help and exit.
- .. _daemon-options:
- Daemon Options
- --------------
- These options are supported by commands that can detach
- into the background (daemon). They will be present
- in any command that also has a `--detach` option.
- .. cmdoption:: -f, --logfile
- Path to log file. If no logfile is specified, `stderr` is used.
- .. cmdoption:: --pidfile
- Optional file used to store the process pid.
- The program won't start if this file already exists
- and the pid is still alive.
- .. cmdoption:: --uid
- User id, or user name of the user to run as after detaching.
- .. cmdoption:: --gid
- Group id, or group name of the main group to change to after
- detaching.
- .. cmdoption:: --umask
- Effective umask (in octal) of the process after detaching. Inherits
- the umask of the parent process by default.
- .. cmdoption:: --workdir
- Optional directory to change to after detaching.
- .. cmdoption:: --executable
- Executable to use for the detached process.
- ``celery inspect``
- ------------------
- .. program:: celery inspect
- .. cmdoption:: -t, --timeout
- Timeout in seconds (float) waiting for reply
- .. cmdoption:: -d, --destination
- Comma separated list of destination node names.
- .. cmdoption:: -j, --json
- Use json as output format.
- ``celery control``
- ------------------
- .. program:: celery control
- .. cmdoption:: -t, --timeout
- Timeout in seconds (float) waiting for reply
- .. cmdoption:: -d, --destination
- Comma separated list of destination node names.
- .. cmdoption:: -j, --json
- Use json as output format.
- ``celery migrate``
- ------------------
- .. program:: celery migrate
- .. cmdoption:: -n, --limit
- Number of tasks to consume (int).
- .. cmdoption:: -t, -timeout
- Timeout in seconds (float) waiting for tasks.
- .. cmdoption:: -a, --ack-messages
- Ack messages from source broker.
- .. cmdoption:: -T, --tasks
- List of task names to filter on.
- .. cmdoption:: -Q, --queues
- List of queues to migrate.
- .. cmdoption:: -F, --forever
- Continually migrate tasks until killed.
- ``celery upgrade``
- ------------------
- .. program:: celery upgrade
- .. cmdoption:: --django
- Upgrade a Django project.
- .. cmdoption:: --compat
- Maintain backwards compatibility.
- .. cmdoption:: --no-backup
- Don't backup original files.
- ``celery shell``
- ----------------
- .. program:: celery shell
- .. cmdoption:: -I, --ipython
- Force :pypi:`iPython` implementation.
- .. cmdoption:: -B, --bpython
- Force :pypi:`bpython` implementation.
- .. cmdoption:: -P, --python
- Force default Python shell.
- .. cmdoption:: -T, --without-tasks
- Don't add tasks to locals.
- .. cmdoption:: --eventlet
- Use :pypi:`eventlet` monkey patches.
- .. cmdoption:: --gevent
- Use :pypi:`gevent` monkey patches.
- ``celery result``
- -----------------
- .. program:: celery result
- .. cmdoption:: -t, --task
- Name of task (if custom backend).
- .. cmdoption:: --traceback
- Show traceback if any.
- ``celery purge``
- ----------------
- .. program:: celery purge
- .. cmdoption:: -f, --force
- Don't prompt for verification before deleting messages (DANGEROUS)
- ``celery call``
- ---------------
- .. program:: celery call
- .. cmdoption:: -a, --args
- Positional arguments (json format).
- .. cmdoption:: -k, --kwargs
- Keyword arguments (json format).
- .. cmdoption:: --eta
- Scheduled time in ISO-8601 format.
- .. cmdoption:: --countdown
- ETA in seconds from now (float/int).
- .. cmdoption:: --expires
- Expiry time in float/int seconds, or a ISO-8601 date.
- .. cmdoption:: --serializer
- Specify serializer to use (default is json).
- .. cmdoption:: --queue
- Destination queue.
- .. cmdoption:: --exchange
- Destination exchange (defaults to the queue exchange).
- .. cmdoption:: --routing-key
- Destination routing key (defaults to the queue routing key).
- """
- from __future__ import absolute_import, print_function, unicode_literals
- import numbers
- import sys
- from functools import partial
- # Import commands from other modules
- from celery.bin.amqp import amqp
- # Cannot use relative imports here due to a Windows issue (#1111).
- from celery.bin.base import Command, Extensions
- from celery.bin.beat import beat
- from celery.bin.call import call
- from celery.bin.control import _RemoteControl # noqa
- from celery.bin.control import control, inspect, status
- from celery.bin.events import events
- from celery.bin.graph import graph
- from celery.bin.list import list_
- from celery.bin.logtool import logtool
- from celery.bin.migrate import migrate
- from celery.bin.purge import purge
- from celery.bin.result import result
- from celery.bin.shell import shell
- from celery.bin.upgrade import upgrade
- from celery.bin.worker import worker
- from celery.platforms import EX_FAILURE, EX_OK, EX_USAGE
- from celery.utils import term, text
- __all__ = ('CeleryCommand', 'main')
- HELP = """
- ---- -- - - ---- Commands- -------------- --- ------------
- {commands}
- ---- -- - - --------- -- - -------------- --- ------------
- Type '{prog_name} <command> --help' for help using a specific command.
- """
- command_classes = [
- ('Main', ['worker', 'events', 'beat', 'shell', 'multi', 'amqp'], 'green'),
- ('Remote Control', ['status', 'inspect', 'control'], 'blue'),
- ('Utils',
- ['purge', 'list', 'call', 'result', 'migrate', 'graph', 'upgrade'],
- None),
- ('Debugging', ['report', 'logtool'], 'red'),
- ]
- def determine_exit_status(ret):
- if isinstance(ret, numbers.Integral):
- return ret
- return EX_OK if ret else EX_FAILURE
- def main(argv=None):
- """Start celery umbrella command."""
- # Fix for setuptools generated scripts, so that it will
- # work with multiprocessing fork emulation.
- # (see multiprocessing.forking.get_preparation_data())
- try:
- if __name__ != '__main__': # pragma: no cover
- sys.modules['__main__'] = sys.modules[__name__]
- cmd = CeleryCommand()
- cmd.maybe_patch_concurrency()
- from billiard import freeze_support
- freeze_support()
- cmd.execute_from_commandline(argv)
- except KeyboardInterrupt:
- pass
- class multi(Command):
- """Start multiple worker instances."""
- respects_app_option = False
- def run_from_argv(self, prog_name, argv, command=None):
- from celery.bin.multi import MultiTool
- cmd = MultiTool(quiet=self.quiet, no_color=self.no_color)
- return cmd.execute_from_commandline([command] + argv)
- class help(Command):
- """Show help screen and exit."""
- def usage(self, command):
- return '%(prog)s <command> [options] {0.args}'.format(self)
- def run(self, *args, **kwargs):
- self.parser.print_help()
- self.out(HELP.format(
- prog_name=self.prog_name,
- commands=CeleryCommand.list_commands(
- colored=self.colored, app=self.app),
- ))
- return EX_USAGE
- class report(Command):
- """Shows information useful to include in bug-reports."""
- def __init__(self, *args, **kwargs):
- """Custom initialization for report command.
- We need this custom initialization to make sure that
- everything is loaded when running a report.
- There has been some issues when printing Django's
- settings because Django is not properly setup when
- running the report.
- """
- super(report, self).__init__(*args, **kwargs)
- self.app.loader.import_default_modules()
- def run(self, *args, **kwargs):
- self.out(self.app.bugreport())
- return EX_OK
- class CeleryCommand(Command):
- """Base class for commands."""
- commands = {
- 'amqp': amqp,
- 'beat': beat,
- 'call': call,
- 'control': control,
- 'events': events,
- 'graph': graph,
- 'help': help,
- 'inspect': inspect,
- 'list': list_,
- 'logtool': logtool,
- 'migrate': migrate,
- 'multi': multi,
- 'purge': purge,
- 'report': report,
- 'result': result,
- 'shell': shell,
- 'status': status,
- 'upgrade': upgrade,
- 'worker': worker,
- }
- ext_fmt = '{self.namespace}.commands'
- enable_config_from_cmdline = True
- prog_name = 'celery'
- namespace = 'celery'
- @classmethod
- def register_command(cls, fun, name=None):
- cls.commands[name or fun.__name__] = fun
- return fun
- def execute(self, command, argv=None):
- try:
- cls = self.commands[command]
- except KeyError:
- cls, argv = self.commands['help'], ['help']
- cls = self.commands.get(command) or self.commands['help']
- try:
- return cls(
- app=self.app, on_error=self.on_error,
- no_color=self.no_color, quiet=self.quiet,
- on_usage_error=partial(self.on_usage_error, command=command),
- ).run_from_argv(self.prog_name, argv[1:], command=argv[0])
- except self.UsageError as exc:
- self.on_usage_error(exc)
- return exc.status
- except self.Error as exc:
- self.on_error(exc)
- return exc.status
- def on_usage_error(self, exc, command=None):
- if command:
- helps = '{self.prog_name} {command} --help'
- else:
- helps = '{self.prog_name} --help'
- self.error(self.colored.magenta('Error: {0}'.format(exc)))
- self.error("""Please try '{0}'""".format(helps.format(
- self=self, command=command,
- )))
- def _relocate_args_from_start(self, argv, index=0):
- if argv:
- rest = []
- while index < len(argv):
- value = argv[index]
- if value.startswith('--'):
- rest.append(value)
- elif value.startswith('-'):
- # we eat the next argument even though we don't know
- # if this option takes an argument or not.
- # instead we'll assume what's the command name in the
- # return statements below.
- try:
- nxt = argv[index + 1]
- if nxt.startswith('-'):
- # is another option
- rest.append(value)
- else:
- # is (maybe) a value for this option
- rest.extend([value, nxt])
- index += 1
- except IndexError: # pragma: no cover
- rest.append(value)
- break
- else:
- break
- index += 1
- if argv[index:]: # pragma: no cover
- # if there are more arguments left then divide and swap
- # we assume the first argument in argv[i:] is the command
- # name.
- return argv[index:] + rest
- # if there are no more arguments then the last arg in rest'
- # must be the command.
- [rest.pop()] + rest
- return []
- def prepare_prog_name(self, name):
- if name == '__main__.py':
- return sys.modules['__main__'].__file__
- return name
- def handle_argv(self, prog_name, argv, **kwargs):
- self.prog_name = self.prepare_prog_name(prog_name)
- argv = self._relocate_args_from_start(argv)
- _, argv = self.prepare_args(None, argv)
- try:
- command = argv[0]
- except IndexError:
- command, argv = 'help', ['help']
- return self.execute(command, argv)
- def execute_from_commandline(self, argv=None):
- argv = sys.argv if argv is None else argv
- if 'multi' in argv[1:3]: # Issue 1008
- self.respects_app_option = False
- try:
- sys.exit(determine_exit_status(
- super(CeleryCommand, self).execute_from_commandline(argv)))
- except KeyboardInterrupt:
- sys.exit(EX_FAILURE)
- @classmethod
- def get_command_info(cls, command, indent=0,
- color=None, colored=None, app=None):
- colored = term.colored() if colored is None else colored
- colored = colored.names[color] if color else lambda x: x
- obj = cls.commands[command]
- cmd = 'celery {0}'.format(colored(command))
- if obj.leaf:
- return '|' + text.indent(cmd, indent)
- return text.join([
- ' ',
- '|' + text.indent('{0} --help'.format(cmd), indent),
- obj.list_commands(indent, 'celery {0}'.format(command), colored,
- app=app),
- ])
- @classmethod
- def list_commands(cls, indent=0, colored=None, app=None):
- colored = term.colored() if colored is None else colored
- white = colored.white
- ret = []
- for command_cls, commands, color in command_classes:
- ret.extend([
- text.indent('+ {0}: '.format(white(command_cls)), indent),
- '\n'.join(
- cls.get_command_info(
- command, indent + 4, color, colored, app=app)
- for command in commands),
- ''
- ])
- return '\n'.join(ret).strip()
- def with_pool_option(self, argv):
- if len(argv) > 1 and 'worker' in argv[0:3]:
- # this command supports custom pools
- # that may have to be loaded as early as possible.
- return (['-P'], ['--pool'])
- def on_concurrency_setup(self):
- self.load_extension_commands()
- def load_extension_commands(self):
- names = Extensions(self.ext_fmt.format(self=self),
- self.register_command).load()
- if names:
- command_classes.append(('Extensions', names, 'magenta'))
- if __name__ == '__main__': # pragma: no cover
- main()
|