CLI command devel:newplugin now allows specifying most of the parameters of the template

This commit is contained in:
Gina Häußge 2015-10-29 18:41:51 +01:00
parent 3c2d2b579d
commit 628b9edbab
2 changed files with 86 additions and 5 deletions

View file

@ -52,6 +52,10 @@ class OctoPrintDevelCommands(click.MultiCommand):
@contextlib.contextmanager
def custom_cookiecutter_config(config):
"""
Allows overriding cookiecutter's user config with a custom dict
with fallback to the original data.
"""
from octoprint.util import fallback_dict
original_get_user_config = cookiecutter.main.get_user_config
@ -62,15 +66,92 @@ class OctoPrintDevelCommands(click.MultiCommand):
finally:
cookiecutter.main.get_user_config = original_get_user_config
@contextlib.contextmanager
def custom_cookiecutter_prompt(options):
"""
Custom cookiecutter prompter for the template config.
If a setting is available in the provided options (read from the CLI)
that will be used, otherwise the user will be prompted for a value
via click.
"""
original_prompt_for_config = cookiecutter.main.prompt_for_config
def custom_prompt_for_config(context, no_input=False):
import cookiecutter.prompt
cookiecutter_dict = {}
env = cookiecutter.prompt.Environment()
for key, raw in cookiecutter.prompt.iteritems(context['cookiecutter']):
if key in options:
val = options[key]
else:
raw = raw if cookiecutter.prompt.is_string(raw) else str(raw)
val = env.from_string(raw).render(cookiecutter=cookiecutter_dict)
if not no_input:
new_val = click.prompt(key, default=val)
if new_val != "":
val = new_val
cookiecutter_dict[key] = val
return cookiecutter_dict
try:
cookiecutter.main.prompt_for_config = custom_prompt_for_config
yield
finally:
cookiecutter.main.prompt_for_config = original_prompt_for_config
@click.command("newplugin")
def command():
@click.option("--name", "-n", help="The name of the plugin")
@click.option("--package", "-p", help="The plugin package")
@click.option("--author", "-a", help="The plugin author's name")
@click.option("--email", "-e", help="The plugin author's mail address")
@click.option("--license", "-l", help="The plugin's license")
@click.option("--description", "-d", help="The plugin's description")
@click.option("--homepage", help="The plugin's homepage URL")
@click.option("--source", "-s", help="The URL to the plugin's source")
@click.option("--installurl", "-i", help="The plugin's install URL")
@click.argument("identifier", required=False)
def command(name, package, author, email, description, license, homepage, source, installurl, identifier):
"""Creates a new plugin based on the OctoPrint Plugin cookiecutter template."""
from octoprint.util import tempdir
with tempdir() as path:
# deleting a git checkout folder might run into access errors due
# to write-protected sub folders, so we use a custom onerror handler
# that tries to fix such permissions
def onerror(func, path, exc_info):
"""Originally from http://stackoverflow.com/a/2656405/2028598"""
import stat
import os
if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IWUSR)
func(path)
else:
raise
with tempdir(onerror=onerror) as path:
custom = dict(cookiecutters_dir=path)
with custom_cookiecutter_config(custom):
cookiecutter.main.cookiecutter("gh:OctoPrint/cookiecutter-octoprint-plugin")
raw_options = dict(
plugin_identifier=identifier,
plugin_package=package,
plugin_name=name,
full_name=author,
email=email,
plugin_description=description,
plugin_license=license,
plugin_homepage=homepage,
plugin_source=source,
plugin_installurl=installurl
)
options = dict((k, v) for k, v in raw_options.items() if v is not None)
with custom_cookiecutter_prompt(options):
cookiecutter.main.cookiecutter("gh:OctoPrint/cookiecutter-octoprint-plugin")
return command

View file

@ -625,7 +625,7 @@ def atomic_write(filename, mode="w+b", prefix="tmp", suffix=""):
@contextlib.contextmanager
def tempdir(**kwargs):
def tempdir(ignore_errors=False, onerror=None, **kwargs):
import tempfile
import shutil
@ -633,7 +633,7 @@ def tempdir(**kwargs):
try:
yield dirpath
finally:
shutil.rmtree(dirpath)
shutil.rmtree(dirpath, ignore_errors=ignore_errors, onerror=onerror)
def bom_aware_open(filename, encoding="ascii", mode="r", **kwargs):