Initial commit: Shop Database Flask Application
Flask backend with Vue 3 frontend for shop floor machine management. Includes database schema export for MySQL shopdb_flask database. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
203
shopdb/plugins/cli.py
Normal file
203
shopdb/plugins/cli.py
Normal file
@@ -0,0 +1,203 @@
|
||||
"""Flask CLI commands for plugin management."""
|
||||
|
||||
import click
|
||||
from flask import current_app
|
||||
from flask.cli import with_appcontext
|
||||
|
||||
|
||||
@click.group('plugin')
|
||||
def plugin_cli():
|
||||
"""Plugin management commands."""
|
||||
pass
|
||||
|
||||
|
||||
@plugin_cli.command('list')
|
||||
@with_appcontext
|
||||
def list_plugins():
|
||||
"""List all available plugins."""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
if not pm:
|
||||
click.echo(click.style("Plugin manager not initialized", fg='red'))
|
||||
return
|
||||
|
||||
plugins = pm.discover_available()
|
||||
|
||||
if not plugins:
|
||||
click.echo("No plugins found in plugins directory.")
|
||||
return
|
||||
|
||||
# Format output
|
||||
click.echo("")
|
||||
click.echo(click.style("Available Plugins:", fg='cyan', bold=True))
|
||||
click.echo("-" * 60)
|
||||
|
||||
for p in plugins:
|
||||
if p['enabled']:
|
||||
status = click.style("[Enabled]", fg='green')
|
||||
elif p['installed']:
|
||||
status = click.style("[Disabled]", fg='yellow')
|
||||
else:
|
||||
status = click.style("[Available]", fg='white')
|
||||
|
||||
click.echo(f" {p['name']:20} v{p['version']:10} {status}")
|
||||
if p['description']:
|
||||
click.echo(f" {p['description'][:55]}...")
|
||||
if p['dependencies']:
|
||||
deps = ', '.join(p['dependencies'])
|
||||
click.echo(f" Dependencies: {deps}")
|
||||
|
||||
click.echo("")
|
||||
|
||||
|
||||
@plugin_cli.command('install')
|
||||
@click.argument('name')
|
||||
@click.option('--skip-migrations', is_flag=True, help='Skip database migrations')
|
||||
@with_appcontext
|
||||
def install_plugin(name: str, skip_migrations: bool):
|
||||
"""
|
||||
Install a plugin.
|
||||
|
||||
Usage: flask plugin install printers
|
||||
"""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
if not pm:
|
||||
click.echo(click.style("Plugin manager not initialized", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
click.echo(f"Installing plugin: {name}")
|
||||
|
||||
if pm.install_plugin(name, run_migrations=not skip_migrations):
|
||||
click.echo(click.style(f"Successfully installed {name}", fg='green'))
|
||||
else:
|
||||
click.echo(click.style(f"Failed to install {name}", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
@plugin_cli.command('uninstall')
|
||||
@click.argument('name')
|
||||
@click.option('--remove-data', is_flag=True, help='Remove plugin database tables')
|
||||
@click.confirmation_option(prompt='Are you sure you want to uninstall this plugin?')
|
||||
@with_appcontext
|
||||
def uninstall_plugin(name: str, remove_data: bool):
|
||||
"""
|
||||
Uninstall a plugin.
|
||||
|
||||
Usage: flask plugin uninstall printers
|
||||
"""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
if not pm:
|
||||
click.echo(click.style("Plugin manager not initialized", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
click.echo(f"Uninstalling plugin: {name}")
|
||||
|
||||
if pm.uninstall_plugin(name, remove_data=remove_data):
|
||||
click.echo(click.style(f"Successfully uninstalled {name}", fg='green'))
|
||||
else:
|
||||
click.echo(click.style(f"Failed to uninstall {name}", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
@plugin_cli.command('enable')
|
||||
@click.argument('name')
|
||||
@with_appcontext
|
||||
def enable_plugin(name: str):
|
||||
"""Enable a disabled plugin."""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
if not pm:
|
||||
click.echo(click.style("Plugin manager not initialized", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
if pm.enable_plugin(name):
|
||||
click.echo(click.style(f"Enabled {name}", fg='green'))
|
||||
else:
|
||||
click.echo(click.style(f"Failed to enable {name}", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
@plugin_cli.command('disable')
|
||||
@click.argument('name')
|
||||
@with_appcontext
|
||||
def disable_plugin(name: str):
|
||||
"""Disable an enabled plugin."""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
if not pm:
|
||||
click.echo(click.style("Plugin manager not initialized", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
if pm.disable_plugin(name):
|
||||
click.echo(click.style(f"Disabled {name}", fg='green'))
|
||||
else:
|
||||
click.echo(click.style(f"Failed to disable {name}", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
@plugin_cli.command('info')
|
||||
@click.argument('name')
|
||||
@with_appcontext
|
||||
def plugin_info(name: str):
|
||||
"""Show detailed information about a plugin."""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
if not pm:
|
||||
click.echo(click.style("Plugin manager not initialized", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
plugin_class = pm.loader.load_plugin_class(name)
|
||||
if not plugin_class:
|
||||
click.echo(click.style(f"Plugin {name} not found", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
try:
|
||||
temp = plugin_class()
|
||||
meta = temp.meta
|
||||
except Exception as e:
|
||||
click.echo(click.style(f"Error loading plugin: {e}", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
state = pm.registry.get(name)
|
||||
|
||||
click.echo("")
|
||||
click.echo("=" * 50)
|
||||
click.echo(click.style(f"Plugin: {meta.name}", fg='cyan', bold=True))
|
||||
click.echo("=" * 50)
|
||||
click.echo(f"Version: {meta.version}")
|
||||
click.echo(f"Description: {meta.description}")
|
||||
click.echo(f"Author: {meta.author or 'Unknown'}")
|
||||
click.echo(f"API Prefix: {meta.api_prefix}")
|
||||
click.echo(f"Dependencies: {', '.join(meta.dependencies) or 'None'}")
|
||||
click.echo(f"Core Version: {meta.core_version}")
|
||||
click.echo("")
|
||||
|
||||
if state:
|
||||
status = click.style('Enabled', fg='green') if state.enabled else click.style('Disabled', fg='yellow')
|
||||
click.echo(f"Status: {status}")
|
||||
click.echo(f"Installed: {state.installed_at}")
|
||||
click.echo(f"Migrations: {len(state.migrations_applied)} applied")
|
||||
else:
|
||||
click.echo(f"Status: {click.style('Not installed', fg='white')}")
|
||||
|
||||
click.echo("")
|
||||
|
||||
|
||||
@plugin_cli.command('migrate')
|
||||
@click.argument('name')
|
||||
@click.option('--revision', default='head', help='Target revision')
|
||||
@with_appcontext
|
||||
def migrate_plugin(name: str, revision: str):
|
||||
"""Run migrations for a specific plugin."""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
if not pm:
|
||||
click.echo(click.style("Plugin manager not initialized", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
if not pm.registry.is_installed(name):
|
||||
click.echo(click.style(f"Plugin {name} is not installed", fg='red'))
|
||||
raise SystemExit(1)
|
||||
|
||||
click.echo(f"Running migrations for {name}...")
|
||||
|
||||
if pm.migration_manager.run_plugin_migrations(name, revision):
|
||||
click.echo(click.style("Migrations completed", fg='green'))
|
||||
else:
|
||||
click.echo(click.style("Migration failed", fg='red'))
|
||||
raise SystemExit(1)
|
||||
Reference in New Issue
Block a user