feat(cli): Added CLI command for handling plugins
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details
ci/woodpecker/pr/lint Pipeline was successful Details
ci/woodpecker/pr/test Pipeline was successful Details

* Install / Uninstall plugins
* List plugins
This commit is contained in:
Ferdinand Thiessen 2021-12-23 02:49:19 +01:00
parent 0a7ffc29d1
commit 5038582406
2 changed files with 98 additions and 2 deletions

View File

@ -84,7 +84,7 @@ def cli():
def main(*args, **kwargs): def main(*args, **kwargs):
# from .plugin_cmd import plugin from .plugin_cmd import plugin
from .export_cmd import export from .export_cmd import export
from .docs_cmd import docs from .docs_cmd import docs
from .run_cmd import run from .run_cmd import run
@ -92,8 +92,8 @@ def main(*args, **kwargs):
# Override logging level # Override logging level
environ.setdefault("FG_LOGGING", logging.getLevelName(LOGGING_MAX)) environ.setdefault("FG_LOGGING", logging.getLevelName(LOGGING_MAX))
# cli.add_command(plugin)
cli.add_command(export) cli.add_command(export)
cli.add_command(docs) cli.add_command(docs)
cli.add_command(plugin)
cli.add_command(run) cli.add_command(run)
cli(*args, **kwargs) cli(*args, **kwargs)

View File

@ -0,0 +1,96 @@
import click
from click.decorators import pass_context
from flask import current_app
from flask.cli import with_appcontext
from importlib_metadata import EntryPoint, entry_points
from flaschengeist.config import config
@click.group()
def plugin():
pass
@plugin.command()
@click.argument("plugin", nargs=-1, type=str)
@click.option("--all", help="Install all enabled plugins", is_flag=True)
@with_appcontext
@pass_context
def install(ctx, plugin, all):
"""Install one or more plugins"""
if not all and len(plugin) == 0:
ctx.fail("At least one plugin must be specified, or use `--all` flag.")
if all:
plugins = current_app.config["FG_PLUGINS"].values()
else:
try:
plugins = [current_app.config["FG_PLUGINS"][p] for p in plugin]
except KeyError as e:
ctx.fail(f"Invalid plugin ID, could not find >{e.args[0]}<")
for p in plugins:
name = p.id.split(".")[-1]
click.echo(f"Installing {name}{'.'*(20-len(name))}", nl=False)
p.install()
click.secho(" ok", fg="green")
@plugin.command()
@click.argument("plugin", nargs=-1, type=str)
@with_appcontext
@pass_context
def uninstall(ctx: click.Context, plugin):
"""Uninstall one or more plugins"""
if len(plugin) == 0:
ctx.fail("At least one plugin must be specified")
try:
plugins = [current_app.config["FG_PLUGINS"][p] for p in plugin]
except KeyError as e:
ctx.fail(f"Invalid plugin ID, could not find >{e.args[0]}<")
if (
click.prompt(
"You are going to uninstall:\n\n"
f"\t{', '.join([p.id.split('.')[-1] for p in plugins])}\n\n"
"Are you sure?",
default="n",
show_choices=True,
type=click.Choice(["y", "N"], False),
).lower()
!= "y"
):
ctx.exit()
for p in plugins:
name = p.id.split(".")[-1]
click.echo(f"Uninstalling {name}{'.'*(20-len(name))}", nl=False)
p.uninstall()
click.secho(" ok", fg="green")
@plugin.command()
@click.option("--enabled", "-e", help="List only enabled plugins", is_flag=True)
@click.option("--no-header", "-n", help="Do not show header", is_flag=True)
@with_appcontext
def ls(enabled, no_header):
def plugin_version(p):
if isinstance(p, EntryPoint):
return p.dist.version
return p.version
plugins = entry_points(group="flaschengeist.plugins")
enabled_plugins = [key for key, value in config.items() if "enabled" in value] + [config["FLASCHENGEIST"]["auth"]]
loaded_plugins = current_app.config["FG_PLUGINS"].keys()
if not no_header:
print(f"{' '*13}{'name': <20}|{'version': >10}")
print("-" * 46)
for plugin in plugins:
if enabled and plugin.name not in enabled_plugins:
continue
print(
f"{plugin.name: <33}|{plugin_version(plugin): >12}"
f"{click.style(' (enabled)', fg='green') if plugin.name in enabled_plugins else ' (disabled)'}"
)
for plugin in [value for value in enabled_plugins if value not in loaded_plugins]:
print(f"{plugin: <33}|{' '*12}" f"{click.style(' (not found)', fg='red')}")