From b65e338d4cf06afb8237512e49a51e354277196d Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 10 Aug 2026 23:47:33 +0900 Subject: feat(console): import scripts Command classes as application commands `Application::do_run` registers a `composer.json` script whose value names a `Symfony\Component\Console\Command\Command` subclass as a live command. The class checks and `new $dummy($script)` need a real PHP runtime, so they run in the worker: the command object lives there and this side keeps a metadata mirror for `list`/`help`, forwarding a run to the worker-side console application it is added to. The name and description fixups are applied to the worker-side object, so both sides carry the same values. Loading the Composer PHP runtime into the worker is gated on the Rust-side `ClassLoader`s resolving the class to a file, keeping that load out of every run whose scripts are plain shell commands. The worker-side console application handoff now accepts commands registered after it was published, since the scripts scan runs after plugin commands are collected. Whether it was published is tracked per application: the handoff is process-wide, so a second application must replace it rather than extend it. `shirabe_php_shim::is_subclass_of` has no callers left. --- .../fixtures/e2e-script-command/composer.json | 23 +++++++++++++++ .../e2e-script-command/src/GreetCommand.php | 34 ++++++++++++++++++++++ .../src/MismatchedNameCommand.php | 23 +++++++++++++++ .../e2e-script-command/src/SingleAppCommand.php | 9 ++++++ 4 files changed, 89 insertions(+) create mode 100644 crates/shirabe/tests/plugin/fixtures/e2e-script-command/composer.json create mode 100644 crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/GreetCommand.php create mode 100644 crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/MismatchedNameCommand.php create mode 100644 crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/SingleAppCommand.php (limited to 'crates/shirabe/tests/plugin/fixtures/e2e-script-command') diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-script-command/composer.json b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/composer.json new file mode 100644 index 00000000..2eeff25b --- /dev/null +++ b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/composer.json @@ -0,0 +1,23 @@ +{ + "name": "shirabe/e2e-script-command", + "description": "E2E fixture project: composer.json scripts naming Command classes, run against upstream Composer and Shirabe.", + "autoload": { + "psr-4": { + "ShirabeTest\\ScriptCommand\\": "src/" + } + }, + "scripts": { + "greet": "ShirabeTest\\ScriptCommand\\GreetCommand", + "renamed": "ShirabeTest\\ScriptCommand\\MismatchedNameCommand", + "single": "ShirabeTest\\ScriptCommand\\SingleAppCommand", + "plain": "echo plain-script" + }, + "scripts-descriptions": { + "renamed": "Description taken from composer.json" + }, + "repositories": [ + { + "packagist.org": false + } + ] +} diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/GreetCommand.php b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/GreetCommand.php new file mode 100644 index 00000000..e797486b --- /dev/null +++ b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/GreetCommand.php @@ -0,0 +1,34 @@ +setDescription('Greets someone from a script-provided command.') + ->setHelp('The greet command exercises a Command class named by a composer.json script.') + ->addArgument('who', InputArgument::REQUIRED, 'Who to greet') + ->addOption('shout', 's', InputOption::VALUE_NONE, 'Uppercase the greeting'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $message = 'Hello ' . $input->getArgument('who'); + if ($input->getOption('shout')) { + $message = strtoupper($message); + } + $output->writeln('greet: ' . $message); + $output->writeln('greet: name=' . $this->getName()); + $output->writeln('greet: app=' . get_class($this->getApplication())); + + return 0; + } +} diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/MismatchedNameCommand.php b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/MismatchedNameCommand.php new file mode 100644 index 00000000..f3f6b05f --- /dev/null +++ b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/MismatchedNameCommand.php @@ -0,0 +1,23 @@ +setName('not-the-script-name'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $output->writeln('renamed: name=' . $this->getName()); + $output->writeln('renamed: description=' . $this->getDescription()); + + return 0; + } +} diff --git a/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/SingleAppCommand.php b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/SingleAppCommand.php new file mode 100644 index 00000000..89e17fe9 --- /dev/null +++ b/crates/shirabe/tests/plugin/fixtures/e2e-script-command/src/SingleAppCommand.php @@ -0,0 +1,9 @@ +