diff --git a/packages/console/src/ConsoleApplication.php b/packages/console/src/ConsoleApplication.php index f8089159ee..7036f9c6b4 100644 --- a/packages/console/src/ConsoleApplication.php +++ b/packages/console/src/ConsoleApplication.php @@ -22,27 +22,30 @@ public function __construct( /** * Boots the console application. * - * @param string $name The name of the console application. * @param string|null $root The root directory of the application. By default, the current working directory. * @param \Tempest\Discovery\DiscoveryLocation[] $discoveryLocations The locations to use for class discovery. * @param string|null $internalStorage The *absolute* internal storage directory for Tempest. + * @param string $name The name of the console application. + * @param bool $loadBuiltInCommands Whether to load built-in Tempest console commands. */ public static function boot( - string $name = 'Tempest', ?string $root = null, array $discoveryLocations = [], ?string $internalStorage = null, + ?string $name = null, + ?bool $loadBuiltInCommands = true, ): self { - $internalStorage ??= '.' . Str\to_kebab_case($name); - $container = Tempest::boot($root, $discoveryLocations, $internalStorage); + if (! $internalStorage && $name) { + $internalStorage = sprintf('.%s', Str\to_kebab_case($name)); + } - $application = $container->get(ConsoleApplication::class); + $container = Tempest::boot($root, $discoveryLocations, $internalStorage); - // Application-specific config $consoleConfig = $container->get(ConsoleConfig::class); - $consoleConfig->name = $name; + $consoleConfig->name ??= $name; + $consoleConfig->loadBuiltInCommands = $loadBuiltInCommands ?? $consoleConfig->loadBuiltInCommands; - return $application; + return $container->get(ConsoleApplication::class); } public function run(): never diff --git a/packages/console/src/ConsoleConfig.php b/packages/console/src/ConsoleConfig.php index ad94cfd3e9..82e58a2755 100644 --- a/packages/console/src/ConsoleConfig.php +++ b/packages/console/src/ConsoleConfig.php @@ -9,15 +9,36 @@ final class ConsoleConfig { - public function __construct( - public string $name = 'Tempest', - - /** @var ConsoleCommand[] $commands */ - public array $commands = [], - public ?string $logPath = null, + /** + * List of registered console commands. + * + * @var ConsoleCommand[] $commands + */ + public array $commands = []; + + /** + * The path to the log file where console output will be recorded. + */ + public ?string $logPath = null; + + /** + * Middleware stack for console commands. + * + * @see https://tempestphp.com/current/essentials/console-commands#middleware + * + * @var Middleware<\Tempest\Console\ConsoleMiddleware> + */ + public Middleware $middleware { + get => $this->middleware ??= new Middleware(); + } - /** @var Middleware<\Tempest\Console\ConsoleMiddleware> */ - public Middleware $middleware = new Middleware(), + /** + * @param ?string $name The name of the application. Will appear in console command menus. + * @param bool $loadBuiltInCommands Whether to load built-in Tempest commands. + */ + public function __construct( + public ?string $name = null, + public bool $loadBuiltInCommands = true, ) {} public function addCommand(MethodReflector $handler, ConsoleCommand $consoleCommand): self diff --git a/packages/console/src/Discovery/ConsoleCommandDiscovery.php b/packages/console/src/Discovery/ConsoleCommandDiscovery.php index 924bcd2dd9..43f6bcb9d6 100644 --- a/packages/console/src/Discovery/ConsoleCommandDiscovery.php +++ b/packages/console/src/Discovery/ConsoleCommandDiscovery.php @@ -28,6 +28,10 @@ public function discover(DiscoveryLocation $location, ClassReflector $class): vo continue; } + if (! $this->consoleConfig->loadBuiltInCommands && $location->isTempest()) { + continue; + } + $this->discoveryItems->add($location, [$method, $consoleCommand]); } } diff --git a/packages/console/src/Initializers/LogOutputBufferInitializer.php b/packages/console/src/Initializers/LogOutputBufferInitializer.php index 840ed0408c..126e365cb6 100644 --- a/packages/console/src/Initializers/LogOutputBufferInitializer.php +++ b/packages/console/src/Initializers/LogOutputBufferInitializer.php @@ -10,8 +10,7 @@ use Tempest\Container\Initializer; use Tempest\Container\Singleton; use Tempest\Core\Kernel; - -use function Tempest\Support\path; +use Tempest\Support\Path; final readonly class LogOutputBufferInitializer implements Initializer { @@ -21,7 +20,7 @@ public function initialize(Container $container): LogOutputBuffer $consoleConfig = $container->get(ConsoleConfig::class); $kernel = $container->get(Kernel::class); - $path = $consoleConfig->logPath ?? path($kernel->root, 'console.log')->toString(); + $path = $consoleConfig->logPath ?? Path\normalize($kernel->root, 'console.log'); return new LogOutputBuffer($path); } diff --git a/packages/console/src/Middleware/OverviewMiddleware.php b/packages/console/src/Middleware/OverviewMiddleware.php index 0611b7800f..f68ce82273 100644 --- a/packages/console/src/Middleware/OverviewMiddleware.php +++ b/packages/console/src/Middleware/OverviewMiddleware.php @@ -12,6 +12,7 @@ use Tempest\Console\ConsoleMiddlewareCallable; use Tempest\Console\ExitCode; use Tempest\Console\Initializers\Invocation; +use Tempest\Core\AppConfig; use Tempest\Core\DiscoveryCache; use Tempest\Core\Priority; @@ -23,6 +24,7 @@ { public function __construct( private Console $console, + private AppConfig $appConfig, private ConsoleConfig $consoleConfig, private DiscoveryCache $discoveryCache, ) {} @@ -41,7 +43,7 @@ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next private function renderOverview(bool $showHidden = false): void { $this->console->header( - header: $this->consoleConfig->name, + header: $this->consoleConfig->name ?? $this->appConfig->name ?? 'Tempest', subheader: 'This is an overview of available commands.' . PHP_EOL . 'Type --help to get more help about a specific command.', ); diff --git a/packages/console/src/Testing/ConsoleTester.php b/packages/console/src/Testing/ConsoleTester.php index eb50db0408..073436ed24 100644 --- a/packages/console/src/Testing/ConsoleTester.php +++ b/packages/console/src/Testing/ConsoleTester.php @@ -20,6 +20,7 @@ use Tempest\Console\OutputBuffer; use Tempest\Container\Container; use Tempest\Highlight\Highlighter; +use Tempest\Validation\Validator; final class ConsoleTester { @@ -174,7 +175,7 @@ public function getBuffer(?callable $callback = null): array public function useInteractiveTerminal(): self { - $this->componentRenderer = new InteractiveComponentRenderer(); + $this->componentRenderer = new InteractiveComponentRenderer($this->container->get(Validator::class)); return $this; } diff --git a/packages/core/src/Tempest.php b/packages/core/src/Tempest.php index 1b30622079..370eacb6ef 100644 --- a/packages/core/src/Tempest.php +++ b/packages/core/src/Tempest.php @@ -8,19 +8,15 @@ final readonly class Tempest { - public static function boot( - ?string $root = null, - /** @var \Tempest\Discovery\DiscoveryLocation[] $discoveryLocations */ - array $discoveryLocations = [], - ?string $internalStorage = null, - ): Container { - $root ??= getcwd(); - - // Kernel - return FrameworkKernel::boot( - root: $root, + /** @param \Tempest\Discovery\DiscoveryLocation[] $discoveryLocations */ + public static function boot(?string $root = null, array $discoveryLocations = [], ?string $internalStorage = null): Container + { + $kernel = FrameworkKernel::boot( + root: $root ?? getcwd(), discoveryLocations: $discoveryLocations, internalStorage: $internalStorage, - )->container; + ); + + return $kernel->container; } } diff --git a/packages/discovery/src/DiscoveryLocation.php b/packages/discovery/src/DiscoveryLocation.php index 93bdb84e88..2faa50042d 100644 --- a/packages/discovery/src/DiscoveryLocation.php +++ b/packages/discovery/src/DiscoveryLocation.php @@ -29,9 +29,14 @@ public static function fromNamespace(Psr4Namespace $namespace): self return new self($namespace->namespace, $namespace->path); } + public function isTempest(): bool + { + return str_starts_with($this->namespace, 'Tempest'); + } + public function isVendor(): bool { - return str_contains($this->path, '/vendor/') || str_contains($this->path, '\\vendor\\') || str_starts_with($this->namespace, 'Tempest'); + return str_contains($this->path, '/vendor/') || str_contains($this->path, '\\vendor\\') || $this->isTempest(); } public function toClassName(string $path): string