mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
221 lines
8 KiB
Python
221 lines
8 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# Copyright (c) 2025 Allaun
|
|
# pylint: disable=broad-exception-caught,unused-argument
|
|
|
|
"""NoDupeLabs Entry Point - CLI using Enhanced Core Loader.
|
|
|
|
This module provides the CLI entry point, delegating core bootstrapping
|
|
and tool loading to the enhanced `nodupe.core.loader`.
|
|
|
|
Key Features:
|
|
- CLI argument parsing
|
|
- Delegation to enhanced Core Loader
|
|
- Tool command dispatch
|
|
- Graceful error handling
|
|
"""
|
|
|
|
import sys
|
|
import argparse
|
|
import logging
|
|
from typing import Optional, List, Any
|
|
|
|
# Import the enhanced core loader bootstrap
|
|
from nodupe.core.loader import bootstrap
|
|
|
|
|
|
class CLIHandler:
|
|
"""Handles CLI argument parsing and command dispatch."""
|
|
|
|
def __init__(self, loader: Any) -> None:
|
|
"""Initialize CLI handler with bootstrapped loader.
|
|
|
|
Args:
|
|
loader: Initialized CoreLoader instance
|
|
"""
|
|
self.loader = loader
|
|
self.parser = self._create_parser()
|
|
self._register_commands()
|
|
|
|
def _create_parser(self) -> argparse.ArgumentParser:
|
|
"""Create the main argument parser."""
|
|
parser = argparse.ArgumentParser(
|
|
description="NoDupeLabs: A tool to find and safely store your files while removing duplicates.",
|
|
add_help=True
|
|
)
|
|
|
|
# Global flags
|
|
parser.add_argument(
|
|
'--verbose',
|
|
action='store_true',
|
|
help='Show detailed technical details for each step'
|
|
)
|
|
parser.add_argument(
|
|
'--debug',
|
|
action='store_true',
|
|
help='Enable debug logging and detailed error output'
|
|
)
|
|
|
|
# Performance tuning
|
|
parser.add_argument('--speed', choices=['normal', 'fast', 'safe'], default='normal', help='Choose how hard the computer works')
|
|
parser.add_argument('--cores', type=int, help='Override number of CPU cores to use')
|
|
parser.add_argument('--max-workers', type=int, help='Override maximum worker threads/processes')
|
|
parser.add_argument('--batch-size', type=int, help='Override processing batch size')
|
|
|
|
return parser
|
|
|
|
def _register_commands(self) -> None:
|
|
"""Register commands from tools."""
|
|
subparsers = self.parser.add_subparsers(
|
|
dest='command',
|
|
help='Available commands'
|
|
)
|
|
|
|
# Built-in commands
|
|
version_parser = subparsers.add_parser('version', help='Show the software version and system info')
|
|
version_parser.set_defaults(func=self._cmd_version)
|
|
|
|
tool_parser = subparsers.add_parser('tools', help='Manage the extra components/tools installed')
|
|
tool_parser.add_argument('--list', action='store_true', help='List all available tools')
|
|
tool_parser.set_defaults(func=self._cmd_tool)
|
|
|
|
# Tool commands
|
|
# The loader has already loaded tools into the registry
|
|
if self.loader.tool_registry:
|
|
tools = self.loader.tool_registry.get_tools()
|
|
for tool in tools:
|
|
if hasattr(tool, 'register_commands'):
|
|
try:
|
|
tool.register_commands(subparsers)
|
|
logging.debug(f"Registered commands for tool: {tool.name}")
|
|
except Exception as e:
|
|
logging.warning(f"Failed to register commands for {tool.name}: {e}")
|
|
|
|
def run(self, args: Optional[List[str]] = None) -> int:
|
|
"""Run the CLI.
|
|
|
|
Args:
|
|
args: Command line arguments
|
|
|
|
Returns:
|
|
Exit code
|
|
"""
|
|
from .api.codes import ActionCode
|
|
parsed_args = self.parser.parse_args(args)
|
|
|
|
# Handle debug flag
|
|
if parsed_args.debug:
|
|
self._setup_debug_logging()
|
|
|
|
# Handle performance overrides
|
|
self._apply_overrides(parsed_args)
|
|
|
|
if hasattr(parsed_args, 'func'):
|
|
try:
|
|
# Inject services into args namespace if needed by commands
|
|
parsed_args.container = self.loader.container
|
|
result = parsed_args.func(parsed_args)
|
|
|
|
# Log accessibility compliance
|
|
print(f"[{ActionCode.ACC_ISO_CMP}] CLI command executed with accessibility compliance")
|
|
return result
|
|
except Exception as e:
|
|
print(f"[{ActionCode.FPT_STM_ERR}] Command failed: {e}", file=sys.stderr)
|
|
if parsed_args.debug:
|
|
import traceback
|
|
traceback.print_exc()
|
|
return 1
|
|
|
|
self.parser.print_help()
|
|
return 0
|
|
|
|
def _cmd_version(self, args: argparse.Namespace) -> int:
|
|
"""Handle version command."""
|
|
from .api.codes import ActionCode
|
|
print(f"[{ActionCode.FIA_UAU_INIT}] NoDupeLabs CLI v1.0.0")
|
|
print("Powered by Enhanced Core Loader")
|
|
|
|
# Show system info from loader config if available
|
|
if self.loader.config and hasattr(self.loader.config, 'config'):
|
|
cfg = self.loader.config.config
|
|
print(f"Platform: {cfg.get('drive_type', 'unknown')} | "
|
|
f"Cores: {cfg.get('cpu_cores', '?')} | "
|
|
f"RAM: {cfg.get('ram_gb', '?')}GB")
|
|
|
|
# Report accessibility compliance
|
|
print(f"[{ActionCode.ACC_ISO_CMP}] ISO Accessibility Compliant")
|
|
return 0
|
|
|
|
def _cmd_tool(self, args: argparse.Namespace) -> int:
|
|
"""Handle tool command."""
|
|
from .api.codes import ActionCode
|
|
if not self.loader.tool_registry:
|
|
print(f"[{ActionCode.FPT_FLS_FAIL}] Tool system is not active.")
|
|
return 1
|
|
|
|
if args.list:
|
|
tools = self.loader.tool_registry.get_tools()
|
|
print(f"[{ActionCode.FIA_UAU_LOAD}] Number of tools available: {len(tools)}")
|
|
for tool in tools:
|
|
# Check accessibility compliance for each tool
|
|
from .tool_system.base import AccessibleTool
|
|
if isinstance(tool, AccessibleTool):
|
|
print(f" - {tool.name} (v{getattr(tool, 'version', '?.?')}) [{ActionCode.ACC_ISO_CMP}]")
|
|
else:
|
|
print(f" - {tool.name} (v{getattr(tool, 'version', '?.?')}) [{ActionCode.ACC_FEATURE_DISABLED}]")
|
|
return 0
|
|
return 0
|
|
|
|
def _setup_debug_logging(self) -> None:
|
|
"""Setup debug logging."""
|
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
logging.debug("Debug logging enabled")
|
|
|
|
def _apply_overrides(self, args: argparse.Namespace) -> None:
|
|
"""Apply performance overrides to the running configuration."""
|
|
if not self.loader.config or not hasattr(self.loader.config, 'config'):
|
|
return
|
|
|
|
cfg = self.loader.config.config
|
|
if args.cores:
|
|
cfg['cpu_cores'] = args.cores
|
|
logging.info(f"Overridden CPU cores: {args.cores}")
|
|
if args.max_workers:
|
|
cfg['max_workers'] = args.max_workers
|
|
logging.info(f"Overridden max workers: {args.max_workers}")
|
|
if args.batch_size:
|
|
cfg['batch_size'] = args.batch_size
|
|
logging.info(f"Overridden batch size: {args.batch_size}")
|
|
|
|
|
|
def main(args: Optional[List[str]] = None) -> int:
|
|
"""Main entry point."""
|
|
from .api.codes import ActionCode
|
|
|
|
loader = None
|
|
try:
|
|
# 1. Bootstrap the system using enhanced loader
|
|
print(f"[{ActionCode.FIA_UAU_INIT}] Starting NoDupeLabs core engine")
|
|
loader = bootstrap()
|
|
|
|
# 2. Run CLI
|
|
cli = CLIHandler(loader)
|
|
return cli.run(args)
|
|
|
|
except KeyboardInterrupt:
|
|
print(f"\n[{ActionCode.FIA_UAU_SHUTDOWN}] Interrupted by user", file=sys.stderr)
|
|
return 130
|
|
except Exception as e:
|
|
print(f"[{ActionCode.FPT_STM_ERR}] Fatal startup error: {e}", file=sys.stderr)
|
|
return 1
|
|
finally:
|
|
if loader:
|
|
try:
|
|
print(f"[{ActionCode.FIA_UAU_SHUTDOWN}] Shutting down NoDupeLabs core engine")
|
|
loader.shutdown()
|
|
except Exception as e:
|
|
print(f"[{ActionCode.FPT_STM_ERR}] Error during shutdown: {e}", file=sys.stderr)
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|