From d4129418e97b14944562e0bb5f922cb66faa0fa2 Mon Sep 17 00:00:00 2001 From: novirium Date: Sun, 7 Feb 2021 12:33:28 +0800 Subject: [PATCH] Add "info" command to CLI --- shepherd/agent/cli.py | 85 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/shepherd/agent/cli.py b/shepherd/agent/cli.py index 2323558..5e6b4d4 100644 --- a/shepherd/agent/cli.py +++ b/shepherd/agent/cli.py @@ -66,7 +66,7 @@ def cli(ctx, default_config_path, local_operation, only_default_layer, new_devic log.info(F"Shepherd Agent [{version_text}]") # Drop down to subcommand if it doesn't need default config file processing - if ctx.invoked_subcommand == "template": + if ctx.invoked_subcommand in ["template", "info"]: return # Get a default config path to use @@ -293,3 +293,86 @@ def template(ctx, plugin_name, include_all, config_path, plugin_dir): click.echo(F"Writing [{plugin_name}] template to {config_path}") with open(config_path, 'w+') as f: f.write(template_toml) + + +@cli.command() +@click.argument('plugin_name', required=False) +@click.option('-d', '--plugin-dir', type=click.Path(), + help="Directory to search for plugin modules, in addition to built in Shepherd" + " plugins and the global import path. Defaults to current directory.") +@click.pass_context +def info(ctx, plugin_name, plugin_dir): + """ + Show plugin information. + + If plugin_name is not provided, shows list of all discovered plugins and their sources. Note + that this will detect _all_ valid python modules in the plugin_dir as custom plugins, as these + are not validated as proper Shepherd plugins until they are loaded. + + If plugin_name is provided, attempts to load (but not initialise) the desired plugin and show + all registered plugin features (interface functions, hooks, attachments, and + config specification). + """ + + echo_heading("Shepherd - Info") + + if not plugin_dir: + plugin_dir = Path.cwd() + + if not plugin_name: + log.info("Running plugin discovery...") + base_plugins = plugin.discover_base_plugins() + custom_plugins = plugin.discover_custom_plugins(plugin_dir) + installed_plugins = plugin.discover_installed_plugins() + + echo_section("Discovered base plugins:") + if len(base_plugins) == 0: + click.echo("---none---") + for name in base_plugins: + click.secho(F" {name}", fg='green') + + echo_section("Discovered custom plugins:") + if len(custom_plugins) == 0: + click.echo("---none---") + for name in custom_plugins: + click.secho(F" {name}", fg='green') + + echo_section("Discovered installed plugins:") + if len(installed_plugins) == 0: + click.echo("---none---") + for name in installed_plugins: + click.secho(F" {name}", fg='green') + + return + + # Plugin name supplied, so load it + plugin_interface = None + log.info(F"Attempting to load plugin {plugin_name}...") + + try: + plugin_interface = plugin.load_plugin(plugin_name, plugin_dir) + except plugin.PluginLoadError as e: + log.error(e.args[0]) + sys.exit(1) + + echo_section("Plugin info for", input_text=plugin_name) + + # template_dict = confspec.get_template(include_all) + # template_toml = toml.dumps({plugin_name: template_dict}, encoder=BlankEncoder()) + + echo_section("Interface functions:") + for ifunc_name, ifunc in plugin_interface._functions.items(): + args = "" + if ifunc.remote: + args = F"{ifunc.spec}" + else: + args = F"{inspect.signature(ifunc.func)}" + + click.echo(F"{ifunc_name} {args}") + + echo_section("Hooks:") + for hook in plugin_interface._hooks: + click.echo(hook) + + echo_section("Config:") + click.echo(plugin_interface._confspec)