Started work on devel CLI commands

For now only devel:newplugin is available (if cookiecutter is installed)
This commit is contained in:
Gina Häußge 2015-10-27 18:10:51 +01:00
parent 2dd04574ce
commit a6f11b9744
3 changed files with 119 additions and 1 deletions

View file

@ -49,6 +49,7 @@ def hidden_option(*param_decls, **attrs):
from .server import server_commands
from .plugins import plugin_commands
from .devel import devel_commands
def set_ctx_obj_option(ctx, param, value):
"""Helper for setting eager options on the context."""
@ -60,7 +61,7 @@ def set_ctx_obj_option(ctx, param, value):
@click.group(name="octoprint", invoke_without_command=True, cls=click.CommandCollection,
sources=[server_commands, plugin_commands])
sources=[server_commands, plugin_commands, devel_commands])
@click.option("--basedir", "-b", type=click.Path(), callback=set_ctx_obj_option, is_eager=True,
help="Specify the basedir to use for uploads, timelapses etc.")
@click.option("--config", "-c", "configfile", type=click.Path(), callback=set_ctx_obj_option, is_eager=True,

View file

@ -0,0 +1,75 @@
# coding=utf-8
from __future__ import absolute_import
__author__ = "Gina Häußge <osd@foosel.net>"
__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 logging
class OctoPrintDevelCommands(click.MultiCommand):
sep = ":"
def list_commands(self, ctx):
result = [name for name in self._get_commands()]
result.sort()
return result
def get_command(self, ctx, cmd_name):
commands = self._get_commands()
return commands.get(cmd_name, None)
def _get_commands(self):
commands = dict()
for name in [x for x in dir(self) if x.startswith("command_")]:
method = getattr(self, name)
try:
result = method()
if result is not None:
commands["devel" + self.sep + result.name] = result
except:
logging.getLogger(__name__).exception("There was an error registering one of the devel commands ({})".format(name))
return commands
def command_newplugin(self):
try:
import cookiecutter.main
except ImportError:
return None
import contextlib
@contextlib.contextmanager
def custom_cookiecutter_config(config):
from octoprint.util import fallback_dict
original_get_user_config = cookiecutter.main.get_user_config
original_config = original_get_user_config()
try:
cookiecutter.main.get_user_config = lambda: fallback_dict(config, original_config)
yield
finally:
cookiecutter.main.get_user_config = original_get_user_config
@click.command("newplugin")
def command():
"""Creates a new plugin based on the OctoPrint Plugin cookiecutter template."""
from octoprint.util import tempdir
with tempdir() as path:
custom = dict(cookiecutters_dir=path)
with custom_cookiecutter_config(custom):
cookiecutter.main.cookiecutter("gh:OctoPrint/cookiecutter-octoprint-plugin")
return command
@click.group(cls=OctoPrintDevelCommands)
def devel_commands():
pass

View file

@ -547,6 +547,36 @@ def dict_contains_keys(keys, dictionary):
return True
class fallback_dict(dict):
def __init__(self, custom, *fallbacks):
self.custom = custom
self.fallbacks = fallbacks
def __getitem__(self, item):
for dictionary in self._all():
if item in dictionary:
return dictionary[item]
raise KeyError()
def __setitem__(self, key, value):
self.custom[key] = value
def __delitem__(self, key):
for dictionary in self._all():
if key in dictionary:
del dictionary[key]
def keys(self):
result = set()
for dictionary in self._all():
result += dictionary.keys()
return result
def _all(self):
return [self.custom] + list(self.fallbacks)
class Object(object):
pass
@ -594,6 +624,18 @@ def atomic_write(filename, mode="w+b", prefix="tmp", suffix=""):
shutil.move(temp_config.name, filename)
@contextlib.contextmanager
def tempdir(**kwargs):
import tempfile
import shutil
dirpath = tempfile.mkdtemp(**kwargs)
try:
yield dirpath
finally:
shutil.rmtree(dirpath)
def bom_aware_open(filename, encoding="ascii", mode="r", **kwargs):
import codecs