MrDraw/src/octoprint/cli/__init__.py
Gina Häußge c84e199e87 Add & use "octoprint analysis gcode" subcommand
That should solve any weird import issues we have when
running gcodeInterpreter.py directly (and hence putting
octoprint.util as first entry into the python path,
causing potential issues with imported modules such as
yaml to catch the octoprint.util.platform module instead
of the actual python platform module).

See reported problem with that by @CapnBry in #2095
2017-09-28 10:33:28 +02:00

174 lines
6.2 KiB
Python

# coding=utf-8
from __future__ import absolute_import, division, print_function
__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
import sys
#~~ click context
class OctoPrintContext(object):
"""Custom context wrapping the standard options."""
def __init__(self, configfile=None, basedir=None, verbosity=0, safe_mode=False):
self.configfile = configfile
self.basedir = basedir
self.verbosity = verbosity
self.safe_mode = safe_mode
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 setting 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 value != param.default:
setattr(ctx.obj, param.name, value)
elif param.default is not None:
setattr(ctx.obj, param.name, param.default)
#~~ helper for retrieving context options
def get_ctx_obj_option(ctx, key, default, include_parents=True):
if include_parents and hasattr(ctx, "parent") and ctx.parent:
fallback = get_ctx_obj_option(ctx.parent, key, default)
else:
fallback = default
return getattr(ctx.obj, key, fallback)
#~~ 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"),
factory("--safe", "safe_mode", is_flag=True, callback=set_ctx_obj_option, is_eager=True, expose_value=False,
help="Enable safe mode; disables all third party plugins")
]
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, callback=set_ctx_obj_option),
hidden_option("--port", type=click.INT, callback=set_ctx_obj_option),
hidden_option("--logging", type=click.Path(), callback=set_ctx_obj_option),
hidden_option("--debug", "-d", is_flag=True, callback=set_ctx_obj_option),
hidden_option("--daemon", type=click.Choice(["start", "stop", "restart"]), callback=set_ctx_obj_option),
hidden_option("--pid", type=click.Path(), default="/tmp/octoprint.pid", callback=set_ctx_obj_option),
hidden_option("--iknowwhatimdoing", "allow_root", is_flag=True, callback=set_ctx_obj_option),
])
"""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
from .config import config_commands
from .analysis import analysis_commands
@click.group(name="octoprint", invoke_without_command=True, cls=click.CommandCollection,
sources=[server_commands, plugin_commands, dev_commands, client_commands, config_commands, analysis_commands])
@standard_options()
@legacy_options
@click.version_option(version=octoprint.__version__, allow_from_autoenv=False)
@click.pass_context
def octo(ctx, **kwargs):
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.
def get_value(key):
return get_ctx_obj_option(ctx, key, kwargs.get(key))
daemon = get_value("daemon")
if daemon:
click.echo("Daemon operation via \"octoprint --daemon "
"start|stop|restart\" is deprecated, please use "
"\"octoprint daemon start|stop|restart\" from now on")
if sys.platform == "win32" or sys.platform == "darwin":
click.echo("Sorry, daemon mode is not supported under your operating system right now")
else:
from octoprint.cli.server import daemon_command
ctx.invoke(daemon_command, command=daemon, **kwargs)
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, **kwargs)