118 lines
3.8 KiB
PHP
Executable File
118 lines
3.8 KiB
PHP
Executable File
#!/usr/bin/env php
|
|
<?php
|
|
|
|
/**
|
|
* Console Entry Point
|
|
*
|
|
* Bootstraps the application container and registers console commands
|
|
* from core and modules using lazy loading via Symfony Console.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
use KTXC\Application;
|
|
use KTXC\Kernel;
|
|
use KTXC\Module\ModuleManager;
|
|
use KTXF\Module\ModuleConsoleInterface;
|
|
use Symfony\Component\Console\Application as ConsoleApplication;
|
|
use Symfony\Component\Console\Command\LazyCommand;
|
|
|
|
// Check dependencies
|
|
if (!is_dir(dirname(__DIR__).'/vendor')) {
|
|
fwrite(STDERR, "Dependencies are missing. Run 'composer install' first.\n");
|
|
exit(1);
|
|
}
|
|
|
|
require_once dirname(__DIR__).'/vendor/autoload.php';
|
|
|
|
try {
|
|
// Bootstrap the application
|
|
$projectRoot = dirname(__DIR__);
|
|
$app = new Application($projectRoot);
|
|
|
|
// Boot kernel to initialize container and modules
|
|
$app->kernel()->boot();
|
|
|
|
// Get the container
|
|
$container = $app->container();
|
|
|
|
// Create Symfony Console Application
|
|
$console = new ConsoleApplication('Ktrix Console', Kernel::VERSION);
|
|
|
|
// Collect all command classes
|
|
$commandClasses = [];
|
|
|
|
// Collect commands from modules
|
|
/** @var ModuleManager $moduleManager */
|
|
$moduleManager = $container->get(ModuleManager::class);
|
|
|
|
foreach ($moduleManager->list() as $module) {
|
|
$moduleInstance = $module->instance();
|
|
|
|
// Skip if module instance is not available
|
|
if ($moduleInstance === null) {
|
|
continue;
|
|
}
|
|
|
|
// Check if module implements console command provider
|
|
if ($moduleInstance instanceof ModuleConsoleInterface) {
|
|
try {
|
|
$commands = $moduleInstance->registerCI();
|
|
|
|
foreach ($commands as $commandClass) {
|
|
if (!class_exists($commandClass)) {
|
|
fwrite(STDERR, "Warning: Command class not found: {$commandClass}\n");
|
|
continue;
|
|
}
|
|
$commandClasses[] = $commandClass;
|
|
}
|
|
} catch (\Throwable $e) {
|
|
fwrite(STDERR, "Warning: Failed to load commands from module {$module->handle()}: {$e->getMessage()}\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Register commands using lazy loading
|
|
foreach ($commandClasses as $commandClass) {
|
|
try {
|
|
// Use reflection to read #[AsCommand] attribute without instantiation
|
|
$reflection = new \ReflectionClass($commandClass);
|
|
$attributes = $reflection->getAttributes(\Symfony\Component\Console\Attribute\AsCommand::class);
|
|
|
|
if (empty($attributes)) {
|
|
fwrite(STDERR, "Warning: Command {$commandClass} missing #[AsCommand] attribute\n");
|
|
continue;
|
|
}
|
|
|
|
// Get attribute instance
|
|
/** @var \Symfony\Component\Console\Attribute\AsCommand $commandAttr */
|
|
$commandAttr = $attributes[0]->newInstance();
|
|
|
|
// Create lazy command wrapper that defers instantiation
|
|
$lazyCommand = new LazyCommand(
|
|
$commandAttr->name,
|
|
[],
|
|
$commandAttr->description ?? '',
|
|
$commandAttr->hidden ?? false,
|
|
fn() => $container->get($commandClass) // Only instantiate when executed
|
|
);
|
|
|
|
$console->add($lazyCommand);
|
|
|
|
} catch (\Throwable $e) {
|
|
fwrite(STDERR, "Warning: Failed to register command {$commandClass}: {$e->getMessage()}\n");
|
|
}
|
|
}
|
|
|
|
// Run the console application
|
|
$exitCode = $console->run();
|
|
exit($exitCode);
|
|
|
|
} catch (\Throwable $e) {
|
|
fwrite(STDERR, "Fatal error: " . $e->getMessage() . "\n");
|
|
if (isset($app) && $app->debug()) {
|
|
fwrite(STDERR, $e->getTraceAsString() . "\n");
|
|
}
|
|
exit(1);
|
|
}
|