#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
usage: :command:`earwigbot [-h] [-v] [-d | -q] [-t NAME] [PATH] ...`
This is EarwigBot's command-line utility, enabling you to easily start the bot
or run specific tasks.
.. glossary::
``PATH``
path to the bot's working directory, which will be created if it doesn't
exist; current directory assumed if not specified
``-h``, ``--help``
show this help message and exit
``-v``, ``--version``
show program's version number and exit
``-d``, ``--debug``
print all logs, including ``DEBUG``-level messages
``-q``, ``--quiet``
don't print any logs except warnings and errors
``-t NAME``, ``--task NAME``
given the name of a task, the bot will run it instead of the main bot and
then exit
``TASK_ARGS``
with --task, will pass any remaining arguments to the task's
:py:meth:`.Task.run` method
"""
from argparse import Action, ArgumentParser, REMAINDER
import logging
from os import path
from time import sleep
from earwigbot import __version__
from earwigbot.bot import Bot
__all__ = ["main"]
class _StoreTaskArg(Action):
"""A custom argparse action to read remaining command-line arguments."""
def __call__(self, parser, namespace, values, option_string=None):
kwargs = {}
name = None
for value in values:
if value.startswith("-") and "=" in value:
key, value = value.split("=", 1)
self.insert(kwargs, key.lstrip("-"), value)
elif name:
if value.startswith("-"):
if name not in kwargs:
kwargs[name] = True
name = value.lstrip("-")
else:
self.insert(kwargs, name, value)
name = None
else:
if value.startswith("-"):
name = value.lstrip("-")
if name and name not in kwargs:
kwargs[name] = True
namespace.task_args = kwargs
def insert(self, kwargs, key, value):
"""Add a key/value pair to kwargs; support multiple values per key."""
if key in kwargs:
try:
kwargs[key].append(value)
except AttributeError:
kwargs[key] = [kwargs[key], value]
else:
kwargs[key] = value
[docs]def main():
"""Main entry point for the command-line utility."""
version = "EarwigBot v{0}".format(__version__)
desc = """This is EarwigBot's command-line utility, enabling you to easily
start the bot or run specific tasks."""
parser = ArgumentParser(description=desc)
parser.add_argument("path", nargs="?", metavar="PATH", default=path.curdir,
help="""path to the bot's working directory, which will
be created if it doesn't exist; current
directory assumed if not specified""")
parser.add_argument("-v", "--version", action="version", version=version)
logger = parser.add_mutually_exclusive_group()
logger.add_argument("-d", "--debug", action="store_true",
help="print all logs, including DEBUG-level messages")
logger.add_argument("-q", "--quiet", action="store_true",
help="don't print any logs except warnings and errors")
parser.add_argument("-t", "--task", metavar="NAME",
help="""given the name of a task, the bot will run it
instead of the main bot and then exit""")
parser.add_argument("task_args", nargs=REMAINDER, action=_StoreTaskArg,
metavar="TASK_ARGS",
help="""with --task, will pass these arguments to the
task's run() method""")
args = parser.parse_args()
if not args.task and args.task_args:
unrecognized = " ".join(args.task_args)
parser.error("unrecognized arguments: {0}".format(unrecognized))
level = logging.INFO
if args.debug:
level = logging.DEBUG
elif args.quiet:
level = logging.WARNING
print version
print
bot = Bot(path.abspath(args.path), level=level)
if args.task:
thread = bot.tasks.start(args.task, **args.task_args)
if not thread:
return
try:
while thread.is_alive(): # Keep it alive; it's a daemon
sleep(1)
except KeyboardInterrupt:
pass
finally:
if thread.is_alive():
bot.tasks.logger.warn("The task will be killed")
else:
try:
bot.run()
except KeyboardInterrupt:
pass
finally:
if bot.is_running:
bot.stop()
if __name__ == "__main__":
main()