Files
connpy/connpy/cli/plugin_handler.py
T
2026-07-02 16:44:34 -03:00

157 lines
7.9 KiB
Python

import sys
import yaml
from .. import printer
from ..services.exceptions import ConnpyError
class PluginHandler:
def __init__(self, app):
self.app = app
def dispatch(self, args):
try:
# We determine the target PluginService/PluginStub based on standard 'mode'
# But wait, local plugins should go to app.services._init_local version
# Or we can just use the provided app.services.plugins and pass the appropriate grpc calls if needed.
is_remote = getattr(args, "remote", False)
if is_remote and self.app.services.mode != "remote":
printer.error("Cannot use --remote flag when not running in remote mode.")
return
if args.add:
self.app.services.plugins.add_plugin(args.add[0], args.add[1])
printer.success(f"Plugin {args.add[0]} added successfully{' remotely' if is_remote else ''}.")
elif args.update:
self.app.services.plugins.add_plugin(args.update[0], args.update[1], update=True)
printer.success(f"Plugin {args.update[0]} updated successfully{' remotely' if is_remote else ''}.")
elif args.delete:
self.app.services.plugins.delete_plugin(args.delete[0])
printer.success(f"Plugin {args.delete[0]} deleted successfully{' remotely' if is_remote else ''}.")
elif args.enable:
name = args.enable[0]
if is_remote:
self.app.plugins.preferences[name] = "remote"
else:
if name in self.app.plugins.preferences:
del self.app.plugins.preferences[name]
self.app.plugins._save_preferences(self.app.services.config_svc.get_default_dir())
# Always try to enable it locally (remove .bkp) if it exists
# regardless of mode, to keep files consistent with "enabled" state
try:
# We use a local service instance to ensure we touch local files
from ..services.plugin_service import PluginService
local_svc = PluginService(self.app.services.config)
local_svc.enable_plugin(name)
except Exception:
pass # Ignore if not found locally or already enabled
if is_remote and self.app.services.mode == "remote":
self.app.services.plugins.enable_plugin(name)
printer.success(f"Plugin {name} enabled successfully{' remotely' if is_remote else ' locally'}.")
elif args.disable:
name = args.disable[0]
success = False
if is_remote:
if self.app.services.mode == "remote":
self.app.services.plugins.disable_plugin(name)
success = True
else:
# Disable locally
from ..services.plugin_service import PluginService
local_svc = PluginService(self.app.services.config)
try:
if local_svc.disable_plugin(name):
success = True
except Exception as e:
printer.warning(f"Could not disable local plugin: {e}")
if success:
printer.success(f"Plugin {name} disabled successfully{' remotely' if is_remote else ' locally'}.")
# If any remote operation was performed, trigger a sync to update local cache immediately
if is_remote and self.app.services.mode == "remote":
try:
import os
cache_dir = os.path.join(self.app.services.config_svc.get_default_dir(), "remote_plugins")
# We use a dummy subparser choice check bypass by passing force_sync=True
# or just letting the hasher handle it.
self.app.plugins._import_remote_plugins_to_argparse(
self.app.services.plugins,
self.app.subparsers, # We'll need to make sure this is available
cache_dir,
force_sync=True
)
except Exception:
pass
elif getattr(args, "sync", False):
# The actual sync logic is performed in connapp.py during init
# if the --sync flag is detected in sys.argv
printer.success("Remote plugins synchronized successfully.")
elif args.list:
# We need to fetch both local and remote if in remote mode
local_plugins = {}
remote_plugins = {}
# Fetch depending on mode
if self.app.services.mode == "remote":
# For local we need to instantiate a local plugin service bypassing stub
from ..services.plugin_service import PluginService
local_svc = PluginService(self.app.services.config)
local_plugins = local_svc.list_plugins()
remote_plugins = self.app.services.plugins.list_plugins()
else:
local_plugins = self.app.services.plugins.list_plugins()
from rich.table import Table
table = Table(title="Available Plugins", show_header=True, header_style="bold cyan")
table.add_column("Plugin", style="cyan")
table.add_column("State", style="bold")
table.add_column("Origin", style="magenta")
# Populate local plugins
for name, details in local_plugins.items():
if details.get("origin") == "core":
continue
state = "Disabled" if not details.get("enabled", True) else "Active"
color = "red" if state == "Disabled" else "green"
if self.app.services.mode == "remote" and state == "Active":
if self.app.plugins.preferences.get(name) == "remote":
state = "Shadowed (Override by Remote)"
color = "yellow"
origin = details.get("origin", "Local").capitalize()
table.add_row(name, f"[{color}]{state}[/{color}]", origin)
# Populate remote plugins
if self.app.services.mode == "remote":
for name, details in remote_plugins.items():
if details.get("origin") == "core":
continue
state = "Disabled" if not details.get("enabled", True) else "Active"
color = "red" if state == "Disabled" else "green"
if state == "Active":
pref = self.app.plugins.preferences.get(name, "local")
# If preference isn't remote and the plugin exists locally, local takes priority
if pref != "remote" and name in local_plugins:
state = "Shadowed (Override by Local)"
color = "yellow"
origin = details.get("origin", "Remote").capitalize()
table.add_row(name, f"[{color}]{state}[/{color}]", origin)
if not local_plugins and not remote_plugins:
printer.console.print(" No plugins found.")
else:
printer.console.print(table)
except ConnpyError as e:
printer.error(str(e))
sys.exit(1)