151 lines
5.1 KiB
Python
151 lines
5.1 KiB
Python
# coding=utf-8
|
|
from __future__ import absolute_import
|
|
|
|
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
|
__copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
|
|
|
|
|
import click
|
|
import octoprint
|
|
|
|
#~~ click context
|
|
|
|
class OctoPrintContext(object):
|
|
"""Custom context wrapping the standard options."""
|
|
|
|
def __init__(self, configfile=None, basedir=None, verbosity=0):
|
|
self.configfile = configfile
|
|
self.basedir = basedir
|
|
self.verbosity = verbosity
|
|
|
|
pass_octoprint_ctx = click.make_pass_decorator(OctoPrintContext, ensure=True)
|
|
"""Decorator to pass in the :class:`OctoPrintContext` instance."""
|
|
|
|
#~~ Custom click option to hide from help
|
|
|
|
class HiddenOption(click.Option):
|
|
"""Custom option sub class with empty help."""
|
|
def get_help_record(self, ctx):
|
|
pass
|
|
|
|
def hidden_option(*param_decls, **attrs):
|
|
"""Attaches a hidden option to the command. All positional arguments are
|
|
passed as parameter declarations to :class:`Option`; all keyword
|
|
arguments are forwarded unchanged. This is equivalent to creating an
|
|
:class:`Option` instance manually and attaching it to the
|
|
:attr:`Command.params` list.
|
|
"""
|
|
|
|
import inspect
|
|
from click.decorators import _param_memo
|
|
|
|
def decorator(f):
|
|
if 'help' in attrs:
|
|
attrs['help'] = inspect.cleandoc(attrs['help'])
|
|
_param_memo(f, HiddenOption(param_decls, **attrs))
|
|
return f
|
|
return decorator
|
|
|
|
#~~ helper for settings context options
|
|
|
|
def set_ctx_obj_option(ctx, param, value):
|
|
"""Helper for setting eager options on the context."""
|
|
if ctx.obj is None:
|
|
ctx.obj = OctoPrintContext()
|
|
|
|
if hasattr(ctx.obj, param.name):
|
|
setattr(ctx.obj, param.name, value)
|
|
|
|
#~~ helper for setting a lot of bulk options
|
|
|
|
def bulk_options(options):
|
|
"""
|
|
Utility decorator to decorate a function with a list of click decorators.
|
|
|
|
The provided list of ``options`` will be reversed to ensure correct
|
|
processing order (inverse from what would be intuitive).
|
|
"""
|
|
|
|
def decorator(f):
|
|
options.reverse()
|
|
for option in options:
|
|
option(f)
|
|
return f
|
|
return decorator
|
|
|
|
#~~ helper for setting --basedir, --config and --verbose options
|
|
|
|
def standard_options(hidden=False):
|
|
"""
|
|
Decorator to add the standard options shared among all "octoprint" commands.
|
|
|
|
Adds the options ``--basedir``, ``--config`` and ``--verbose``. If ``hidden``
|
|
is set to ``True``, the options will be available on the command but not
|
|
listed in its help page.
|
|
"""
|
|
|
|
factory = click.option
|
|
if hidden:
|
|
factory = hidden_option
|
|
|
|
options = [
|
|
factory("--basedir", "-b", type=click.Path(), callback=set_ctx_obj_option, is_eager=True, expose_value=False,
|
|
help="Specify the basedir to use for uploads, timelapses etc."),
|
|
factory("--config", "-c", "configfile", type=click.Path(), callback=set_ctx_obj_option, is_eager=True, expose_value=False,
|
|
help="Specify the config file to use."),
|
|
factory("--verbose", "-v", "verbosity", count=True, callback=set_ctx_obj_option, is_eager=True, expose_value=False,
|
|
help="Increase logging verbosity"),
|
|
]
|
|
|
|
return bulk_options(options)
|
|
|
|
#~~ helper for settings legacy options we still have to support on "octoprint"
|
|
|
|
legacy_options = bulk_options([
|
|
hidden_option("--host", type=click.STRING),
|
|
hidden_option("--port", type=click.INT),
|
|
hidden_option("--logging", type=click.Path()),
|
|
hidden_option("--debug", "-d", is_flag=True),
|
|
hidden_option("--daemon", type=click.Choice(["start", "stop", "restart"])),
|
|
hidden_option("--pid", type=click.Path(), default="/tmp/octoprint.pid"),
|
|
hidden_option("--iknowwhatimdoing", "allow_root", is_flag=True),
|
|
])
|
|
"""Legacy options available directly on the "octoprint" command in earlier versions.
|
|
Kept available for reasons of backwards compatibility, but hidden from the
|
|
generated help pages."""
|
|
|
|
#~~ "octoprint" command, merges server_commands and plugin_commands groups
|
|
|
|
from .server import server_commands
|
|
from .plugins import plugin_commands
|
|
from .dev import dev_commands
|
|
from .client import client_commands
|
|
|
|
@click.group(name="octoprint", invoke_without_command=True, cls=click.CommandCollection,
|
|
sources=[server_commands, plugin_commands, dev_commands, client_commands])
|
|
@standard_options()
|
|
@legacy_options
|
|
@click.version_option(version=octoprint.__version__)
|
|
@click.pass_context
|
|
def octo(ctx, debug, host, port, logging, daemon, pid, allow_root):
|
|
|
|
if ctx.invoked_subcommand is None:
|
|
# We have to support calling the octoprint command without any
|
|
# sub commands to remain backwards compatible.
|
|
#
|
|
# But better print a message to inform people that they should
|
|
# use the sub commands instead.
|
|
|
|
if daemon:
|
|
click.echo("Daemon operation via \"octoprint --daemon "
|
|
"start|stop|restart\" is deprecated, please use "
|
|
"\"octoprint daemon start|stop|restart\" from now on")
|
|
|
|
from octoprint.cli.server import daemon_command
|
|
ctx.invoke(daemon_command, debug=debug, pid=pid, daemon=daemon, allow_root=allow_root)
|
|
else:
|
|
click.echo("Starting the server via \"octoprint\" is deprecated, "
|
|
"please use \"octoprint serve\" from now on.")
|
|
|
|
from octoprint.cli.server import serve_command
|
|
ctx.invoke(serve_command, debug=debug, host=host, port=port, logging=logging, allow_root=allow_root)
|