Initial Version
This commit is contained in:
117
bin/console
Executable file
117
bin/console
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/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);
|
||||
}
|
||||
Reference in New Issue
Block a user